1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Google VertexAI] Google ADKのAgentをAgent Engineにデプロイする

Last updated at Posted at 2025-08-02

内容

Develop and deploy agents on Vertex AI Agent Engine のデプロイを試す

サンプルコード

Develop and deploy agents on Vertex AI Agent Engineのコードを argparseで簡単に操作できるようにしたもの

  • GOOGLE_CLOUD_PROJECT_ADK: GCP プロジェクト
  • GOOGLE_CLOUD_REGION: デプロイリジョン
  • GOOGLE_CLOUD_ADK_BUCKET: deployするエージェントのZipを格納するGCS bucket
import argparse
import os
import sys

import vertexai
from google.adk.agents import Agent
from vertexai import agent_engines
from vertexai.preview.reasoning_engines import AdkApp


vertexai.init(
    project=os.environ["GOOGLE_CLOUD_PROJECT_ADK"],  # Your project ID.
    location=os.environ["GOOGLE_CLOUD_REGION"],  # Your cloud region.
    staging_bucket=os.environ["GOOGLE_CLOUD_ADK_BUCKET"],  # Your staging bucket.
)


def get_exchange_rate(
    currency_from: str = "USD",
    currency_to: str = "EUR",
    currency_date: str = "latest",
):
    """Retrieves the exchange rate between two currencies on a specified date."""
    import requests

    response = requests.get(
        f"https://api.frankfurter.app/{currency_date}",
        params={"from": currency_from, "to": currency_to},
    )
    return response.json()


def create_agent():
    """Create and return the agent."""
    return Agent(
        model="gemini-2.5-flash",  # https://ai.google.dev/gemini-api/docs/models
        name="currency_exchange_agent",
        tools=[get_exchange_rate],
    )


def run_locally(message: str, user_id: str):
    """Run the agent locally."""
    print("Running agent locally...")
    print(f"User ID: {user_id}")
    agent = create_agent()
    app = AdkApp(agent=agent)

    for event in app.stream_query(
        user_id=user_id,
        message=message,
    ):
        print(event)


def deploy_to_remote():
    """Deploy the agent to Vertex AI."""
    print("Deploying agent to Vertex AI...")
    agent = create_agent()
    app = AdkApp(agent=agent, enable_tracing=False)

    remote_agent = agent_engines.create(
        agent_engine=app,
        requirements=["google-cloud-aiplatform[adk,agent_engines]>=1.106.0"],
    )

    print(f"Agent deployed successfully!")
    print(f"Resource name: {remote_agent.resource_name}")
    return remote_agent.resource_name


def run_with_remote(resource_name: str, message: str, user_id: str):
    """Run with an existing remote agent."""
    print(f"Running with remote agent: {resource_name}")
    print(f"User ID: {user_id}")

    remote_agent = agent_engines.get(resource_name)

    for event in remote_agent.stream_query(
        user_id=user_id,
        message=message,
    ):
        print(event)


def check_resources():
    """Check and list all agent resources."""
    print("Checking agent resources...")

    agents = list(agent_engines.list())

    if not agents:
        print("No agent resources found.")
        return

    print(f"Found {len(agents)} agent(s):")
    for agent in agents:
        print(f"  - {agent.resource_name}")
        # Display available attributes
        try:
            if hasattr(agent, "display_name"):
                print(f"    Display name: {agent.display_name}")
            if hasattr(agent, "create_time"):
                print(f"    Created: {agent.create_time}")
            if hasattr(agent, "update_time"):
                print(f"    Updated: {agent.update_time}")
        except Exception as e:
            print(f"    (Unable to retrieve details: {e})")


def check_sessions(resource_name: str, user_id: str = "naka"):
    """Check sessions for a specific agent resource."""
    print(f"Checking sessions for: {resource_name}")
    print(f"User ID: {user_id}")

    try:
        agent = agent_engines.get(resource_name)
        # List sessions - requires user_id parameter
        sessions_response = agent.list_sessions(user_id=user_id)
        
        # Extract sessions from response
        if isinstance(sessions_response, dict) and 'sessions' in sessions_response:
            sessions = sessions_response['sessions']
        elif hasattr(sessions_response, 'sessions'):
            sessions = sessions_response.sessions
        elif isinstance(sessions_response, list):
            sessions = sessions_response
        else:
            sessions = list(sessions_response)

        if not sessions:
            print("No sessions found.")
            return

        print(f"\nFound {len(sessions)} session(s):")
        
        # Handle session data based on type
        for i, session in enumerate(sessions):
            if isinstance(session, dict):
                # Extract session information from dict
                print(f"\n  Session {i+1}:")
                print(f"    Session ID: {session.get('id', 'N/A')}")
                print(f"    User ID: {session.get('userId', 'N/A')}")
                print(f"    App Name: {session.get('appName', 'N/A')}")
                
                # Format timestamp
                last_update = session.get('lastUpdateTime')
                if last_update:
                    from datetime import datetime
                    try:
                        dt = datetime.fromtimestamp(last_update)
                        print(f"    Last Updated: {dt.strftime('%Y-%m-%d %H:%M:%S')}")
                    except:
                        print(f"    Last Updated: {last_update}")
                
                # Show state if not empty
                state = session.get('state', {})
                if state:
                    print(f"    State: {state}")
                    
                # Show events count
                events = session.get('events', [])
                print(f"    Events: {len(events)} event(s)")
                
            elif isinstance(session, str):
                print(f"  - Session ID: {session}")
                # Try to get session details if it's just an ID
                try:
                    session_detail = agent.get_session(user_id=user_id, session_id=session)
                    print(f"    Details: {session_detail}")
                except Exception as e:
                    print(f"    (Unable to retrieve session details)")
            else:
                print(f"  Session {i+1}: {session}")
                
    except Exception as e:
        print(f"Error retrieving sessions: {e}")


def cleanup_resource(resource_name: str, force: bool = False):
    """Clean up a specific agent resource."""
    print(f"Cleaning up resource: {resource_name}")

    try:
        remote_agent = agent_engines.get(resource_name)
        remote_agent.delete(force=force)
        print(f"Resource {resource_name} deleted successfully.")
    except Exception as e:
        print(f"Error deleting resource: {e}")


def main():
    parser = argparse.ArgumentParser(description="Google ADK Agent Management Tool")
    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # Run locally
    local_parser = subparsers.add_parser("run-local", help="Run the agent locally")
    local_parser.add_argument(
        "-m",
        "--message",
        type=str,
        default="What is the exchange rate from US dollars to SEK today?",
        help="Message to send to the agent",
    )
    local_parser.add_argument(
        "-u",
        "--user-id",
        type=str,
        default="naka",
        help="User ID for the session",
    )

    # Deploy to remote
    deploy_parser = subparsers.add_parser("deploy", help="Deploy the agent to Vertex AI")

    # Run with remote
    remote_parser = subparsers.add_parser("run-remote", help="Run with an existing remote agent")
    remote_parser.add_argument("resource_name", type=str, help="Resource name of the remote agent")
    remote_parser.add_argument(
        "-m",
        "--message",
        type=str,
        default="What is the exchange rate from US dollars to SEK today?",
        help="Message to send to the agent",
    )
    remote_parser.add_argument(
        "-u",
        "--user-id",
        type=str,
        default="naka",
        help="User ID for the session",
    )

    # Check resources
    check_parser = subparsers.add_parser("check", help="Check and list all agent resources")

    # Check sessions
    sessions_parser = subparsers.add_parser("sessions", help="Check sessions for a specific agent resource")
    sessions_parser.add_argument("resource_name", type=str, help="Resource name of the agent")
    sessions_parser.add_argument("-u", "--user-id", type=str, default="naka", help="User ID for session lookup")

    # Cleanup
    cleanup_parser = subparsers.add_parser("cleanup", help="Clean up a specific agent resource")
    cleanup_parser.add_argument("resource_name", type=str, help="Resource name to delete")
    cleanup_parser.add_argument("-f", "--force", action="store_true", help="Force deletion")

    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        sys.exit(1)

    # Execute command
    if args.command == "run-local":
        run_locally(args.message, args.user_id)
    elif args.command == "deploy":
        deploy_to_remote()
    elif args.command == "run-remote":
        run_with_remote(args.resource_name, args.message, args.user_id)
    elif args.command == "check":
        check_resources()
    elif args.command == "sessions":
        check_sessions(args.resource_name, args.user_id)
    elif args.command == "cleanup":
        cleanup_resource(args.resource_name, args.force)


if __name__ == "__main__":
    main()

サンプルコード実行

uv run python tools/google_adk.py -h
usage: google_adk.py [-h] {run-local,deploy,run-remote,check,sessions,cleanup} ...

Google ADK Agent Management Tool

positional arguments:
  {run-local,deploy,run-remote,check,sessions,cleanup}
                        Available commands
    run-local           Run the agent locally
    deploy              Deploy the agent to Vertex AI
    run-remote          Run with an existing remote agent
    check               Check and list all agent resources
    sessions            Check sessions for a specific agent resource
    cleanup             Clean up a specific agent resource

options:
  -h, --help            show this help message and exit

1. Local実行

uv run python tools/google_adk.py run-local
Running agent locally...
Warning: there are non-text parts in the response: ['function_call'], returning concatenated text result from text parts. Check the full candidates.content.parts accessor to get the full model response.
{'content': {'parts': [{'function_call': {'id': 'adk-422b59a0-eeaa-46f6-9954-4a1b9c20bf28', 'args': {'currency_from': 'USD', 'currency_to': 'SEK'}, 'name': 'get_exchange_rate'}}], 'role': 'model'}, 'usage_metadata': {'candidates_token_count': 13, 'candidates_tokens_details': [{'modality': 'TEXT', 'token_count': 13}], 'prompt_token_count': 63, 'prompt_tokens_details': [{'modality': 'TEXT', 'token_count': 63}], 'thoughts_token_count': 120, 'total_token_count': 196, 'traffic_type': 'ON_DEMAND'}, 'invocation_id': 'e-b0b0aab8-aa68-46b0-834f-fa5bdf49ba88', 'author': 'currency_exchange_agent', 'actions': {'state_delta': {}, 'artifact_delta': {}, 'requested_auth_configs': {}}, 'long_running_tool_ids': [], 'id': '97c3f434-63b4-4cf3-ba74-22d659832dc7', 'timestamp': 1754116103.578109}
{'content': {'parts': [{'function_response': {'id': 'adk-422b59a0-eeaa-46f6-9954-4a1b9c20bf28', 'name': 'get_exchange_rate', 'response': {'amount': 1.0, 'base': 'USD', 'date': '2025-08-01', 'rates': {'SEK': 9.818}}}}], 'role': 'user'}, 'invocation_id': 'e-b0b0aab8-aa68-46b0-834f-fa5bdf49ba88', 'author': 'currency_exchange_agent', 'actions': {'state_delta': {}, 'artifact_delta': {}, 'requested_auth_configs': {}}, 'id': 'aa55bbe6-ce05-402d-8eb3-ae422b2c6e94', 'timestamp': 1754116108.905558}
{'content': {'parts': [{'text': 'Today, the exchange rate from US Dollars to SEK is 1 USD = 9.818 SEK.'}], 'role': 'model'}, 'usage_metadata': {'candidates_token_count': 23, 'candidates_tokens_details': [{'modality': 'TEXT', 'token_count': 23}], 'prompt_token_count': 99, 'prompt_tokens_details': [{'modality': 'TEXT', 'token_count': 99}], 'total_token_count': 122, 'traffic_type': 'ON_DEMAND'}, 'invocation_id': 'e-b0b0aab8-aa68-46b0-834f-fa5bdf49ba88', 'author': 'currency_exchange_agent', 'actions': {'state_delta': {}, 'artifact_delta': {}, 'requested_auth_configs': {}}, 'id': '07bfe254-6e6b-4d36-ada3-281be5ddda69', 'timestamp': 1754116108.908657}

質問 "What is the exchange rate from US dollars to SEK today?" に対して、回答'Today, the exchange rate from US Dollars to SEK is 1 USD = 9.818 SEK.'が返ってることがわかります。

2. Agent Engine へDeploy

uv run python tools/google_adk.py deploy
Deploying agent to Vertex AI...
Identified the following requirements: {'cloudpickle': '3.1.1', 'pydantic': '2.11.7', 'google-cloud-aiplatform': '1.106.0'}
The following requirements are missing: {'cloudpickle', 'pydantic'}
The following requirements are appended: {'cloudpickle==3.1.1', 'pydantic==2.11.7'}
The final list of requirements: ['google-cloud-aiplatform[adk,agent_engines]>=1.106.0', 'cloudpickle==3.1.1', 'pydantic==2.11.7']
Using bucket sample-bucket
Wrote to gs://sample-bucket/agent_engine/agent_engine.pkl
Writing to gs://sample-bucket/agent_engine/requirements.txt
Creating in-memory tarfile of extra_packages
Writing to gs://sample-bucket/agent_engine/dependencies.tar.gz
Creating AgentEngine
Create AgentEngine backing LRO: projects/xxxx/locations/asia-northeast1/reasoningEngines/6007819495098286080/operations/2440268751069773824
View progress and logs at https://console.cloud.google.com/logs/query?project=sample-project
AgentEngine created. Resource name: projects/xxxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
To use this AgentEngine in another session:
agent_engine = vertexai.agent_engines.get('projects/xxxx/locations/asia-northeast1/reasoningEngines/6007819495098286080')
Agent deployed successfully!
Resource name: projects/xxxx/locations/asia-northeast1/reasoningEngines/6007819495098286080

Deployには5分近く時間がかかりました。

Screenshot 2025-08-02 at 15.32.45.png

コンソールからも確認できます。が、QuickstartのままDeployすると名前がになってしまってます。

3. Agent Engineの確認

uv run python tools/google_adk.py check
Checking agent resources...
Found 1 agent(s):
  - projects/xxxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
    Display name: 
    Created: 2025-08-02 06:11:00.462211+00:00
    Updated: 2025-08-02 06:19:46.295795+00:00

4. Agent EngineのRemote実行

上で指定された resource_nameを指定して実行します。

uv run python tools/google_adk.py run-remote projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
Running with remote agent: projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
{'content': {'parts': [{'function_call': {'id': 'adk-492d5586-3776-4921-a65f-88b3cb3c7f06', 'args': {'currency_to': 'SEK', 'currency_from': 'USD'}, 'name': 'get_exchange_rate'}}], 'role': 'model'}, 'usage_metadata': {'candidates_token_count': 13, 'candidates_tokens_details': [{'modality': 'TEXT', 'token_count': 13}], 'prompt_token_count': 63, 'prompt_tokens_details': [{'modality': 'TEXT', 'token_count': 63}], 'thoughts_token_count': 107, 'total_token_count': 183, 'traffic_type': 'ON_DEMAND'}, 'invocation_id': 'e-87a127b6-6f68-4410-9773-210713620ca5', 'author': 'currency_exchange_agent', 'actions': {'state_delta': {}, 'artifact_delta': {}, 'requested_auth_configs': {}}, 'long_running_tool_ids': [], 'id': '6439ed1f-601a-47f5-8ddf-ad33b867d028', 'timestamp': 1754116542.804556}
{'content': {'parts': [{'function_response': {'id': 'adk-492d5586-3776-4921-a65f-88b3cb3c7f06', 'name': 'get_exchange_rate', 'response': {'amount': 1.0, 'base': 'USD', 'date': '2025-08-01', 'rates': {'SEK': 9.818}}}}], 'role': 'user'}, 'invocation_id': 'e-87a127b6-6f68-4410-9773-210713620ca5', 'author': 'currency_exchange_agent', 'actions': {'state_delta': {}, 'artifact_delta': {}, 'requested_auth_configs': {}}, 'id': '29b6571d-62a2-4078-adcf-29bcdbb124ae', 'timestamp': 1754116547.653954}
{'content': {'parts': [{'text': 'Today, the exchange rate from USD to SEK is 1 USD = 9.818 SEK.'}], 'role': 'model'}, 'usage_metadata': {'candidates_token_count': 22, 'candidates_tokens_details': [{'modality': 'TEXT', 'token_count': 22}], 'prompt_token_count': 99, 'prompt_tokens_details': [{'modality': 'TEXT', 'token_count': 99}], 'total_token_count': 121, 'traffic_type': 'ON_DEMAND'}, 'invocation_id': 'e-87a127b6-6f68-4410-9773-210713620ca5', 'author': 'currency_exchange_agent', 'actions': {'state_delta': {}, 'artifact_delta': {}, 'requested_auth_configs': {}}, 'id': 'af4e3478-4cb4-4bd6-8fef-d98430c583de', 'timestamp': 1754116547.887588}

ローカルで実行したのと同じように回答が得られました :white_check_mark:

コードとしては、 agent_engines.get(resource_name) remote_agentをresource_nameで指定して、local agentと同様に呼び出すことができます。

def run_with_remote(resource_name: str, message: str = "What is the exchange rate from US dollars to SEK today?"):
    """Run with an existing remote agent."""
    print(f"Running with remote agent: {resource_name}")

    remote_agent = agent_engines.get(resource_name)

    for event in remote_agent.stream_query(
        user_id="naka",
        message=message,
    ):
        print(event)

5. Agent Engine のセッションの確認

Agent Engine以下にSessionが作られるのでSessionも確認します。

uv run python tools/google_adk.py sessions projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
Checking sessions for: projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
User ID: naka

Found 1 session(s):

  Session 1:
    Session ID: 3234020488812429312
    User ID: naka
    App Name: 6007819495098286080
    Last Updated: 2025-08-02 15:35:49
    Events: 0 event(s)

UIでも確認可能です。

Screenshot 2025-08-02 at 15.52.17.png

run-remoteでsession_idを指定することで過去の会話の履歴に追記していくことができます。

for event in remote_app.stream_query(
    user_id="naka",
    session_id=session_id,
    message="whats the weather in new york",
):
    print(event)

6. Agent Engineの削除

remote_agent = agent_engines.get(resource_name)
remote_agent.delete(force=True)

作成したAgent Engineを削除します。 Sessionが子リソースとしてあるので -f をつけて消します。

uv run python tools/google_adk.py cleanup projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080 -f
Cleaning up resource: projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
Delete Agent Engine backing LRO: projects/xxx/locations/asia-northeast1/operations/911859627530911744
Agent Engine deleted. Resource name: projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080
Resource projects/xxx/locations/asia-northeast1/reasoningEngines/6007819495098286080 deleted successfully.

ハマりどころ

location asia-northeast1 にして localで実行すると404 NOT_FOUND

google.genai.errors.ClientError: 404 NOT_FOUND. {'error': {'code': 404, 'message': 'Publisher Model `projects/<project>/locations/asia-northeast1/publishers/google/models/gemini-2.5-flash-lite` not found.', 'status': 'NOT_FOUND'}}

model="gemini-2.5-flash-lite" を使ってたら遭遇したエラーで、モデルごとにデプロイされてるロケーションを確認する必要がある

Screenshot 2025-08-02 at 12.15.29.png

  • gemini-2.5-flash-liteを使うのであれば、globalus-central1でうまくいく
  • gemini-2.5-flashであればasia-northeast1でも実行可

remote agentデプロイに失敗する google.api_core.exceptions.Aborted: 409

us-central1でもasia-northeast1でも同じ失敗でした

google.api_core.exceptions.Aborted: 409 Please refer to our documentation (https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/troubleshooting/deploy) for checking logs and other troubleshooting tips. 10: Please refer to our documentation (https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/troubleshooting/deploy) for checking logs and other troubleshooting tips.

https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/troubleshooting/deploy ここにも409のエラーはなし

何回か実行したら成功しました。(もしかしたらコードが間違ってたかも)

対応リジョン

Pricing

Agent Engine

Screenshot 2025-08-02 at 12.05.33.png

Model

Screenshot 2025-08-02 at 16.37.48.png

Gemini 2.5 Flash Lite が一番ダントツでやすいので、Quickstartとかで適当なのを試すにはこのモデルを使っています。ですが、Liteはasia-northeast1にはないので、globalやus-central1などを指定する必要があります。

Command

まだgcloud コマンドがない模様:

reasoning engineをリスト

curl -H "Authorization: Bearer $(gcloud auth print-access-token)" "https://$GOOGLE_CLOUD_REGION-aiplatform.googleapis.com/v1/projects/$GOOGLE_CLOUD_PROJECT_ADK/locations/$GOOGLE_CLOUD_REGION/reasoningEngines"

特定のReasoning Engineを見る

curl -H "Authorization: Bearer $(gcloud auth print-access-token)" "https://$GOOGLE_CLOUD_REGION-aiplatform.googleapis.com/v1/projects/$GOOGLE_CLOUD_PROJECT_ADK/locations/$GOOGLE_CLOUD_REGION/reasoningEngines/<engine id>"

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?