内容
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分近く時間がかかりました。
コンソールからも確認できます。が、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}
ローカルで実行したのと同じように回答が得られました ![]()
コードとしては、 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でも確認可能です。
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" を使ってたら遭遇したエラーで、モデルごとにデプロイされてるロケーションを確認する必要がある
-
gemini-2.5-flash-liteを使うのであれば、globalやus-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のエラーはなし
何回か実行したら成功しました。(もしかしたらコードが間違ってたかも)
対応リジョン
- model: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations#asia-pacific_1
- モデルによってはglobalやus-central1などを使う必要あり
- reasoningEngine: https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/overview#supported-regions
-
asia-northeast1も含まれている
-
Pricing
Agent Engine
Model
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>"




