google-adk について
Google Agent Development Kit を使って、本番向けの Python エージェントを構築・運用するためのスキルです。開発者向けに、エージェントの構成、状態やメモリの管理、評価、デプロイを扱います。
主な機能
- 01エージェントとツールの設計
- 02マルチエージェントのオーケストレーション
- 03セッション、状態、メモリの管理
- 04アーティファクトの処理
- 05評価とデプロイ
活用シーン
- 01役割を絞ったエージェントの設計
- 02順次・並列タスクのエージェント連携
- 03ツール呼び出し経路と応答品質のテスト
- 04本番デプロイの準備
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mindrally/ skills --skill google-adkインストール後、Claude Code で/google-adkを入力して読み込まれたか確認します。
詳細
Google Agent Development Kit(ADK)
このスキルでは、エージェントの構成、ツールの設計、セッション/状態/メモリの管理、アーティファクト、評価、デプロイなど、Google Agent Development Kit(ADK)を使って Python で本番環境向けの高品質な AI エージェントを構築する方法を説明します。
ADK エージェントを構築するワークフロー
- エージェントを定義する — 明確な
name、model、instruction、descriptionを設定してLlmAgent(またはAgent)を作成します。指示は一つの役割に絞ります。 - ツールを作成する — 型ヒントと docstring を付けた通常の Python 関数を作成するか、
FunctionToolで既存の API をラップします。副作用を伴う処理の前に、すべての入力を検証します。 - マルチエージェントシステムを構成する — 複雑なワークフローでは、サブエージェントに責務を分割し、決定論的なオーケストレーションには
SequentialAgent、ParallelAgent、LoopAgentを使用します。または、LLM 主導のルーティングにはsub_agentsで委譲します。 - セッションと状態を接続する —
SessionServiceを選択し(開発時はインメモリ、本番環境ではDatabaseSessionServiceまたは Vertex AI 管理のサービス)、会話単位のデータにはsession.stateを使用します。 - メモリを追加する(任意) — 複数の会話をまたいで事実を記憶する必要がある場合は、
MemoryServiceを設定してセッションをまたいだ想起を可能にします。 - アーティファクトを処理する(任意) — エージェントがファイル、画像、その他のバイナリ出力を生成または受信する場合は、
ArtifactServiceを設定します。 - ローカルで実行する —
adk web、adk run、またはRunnerAPI を使用して、エージェントをSessionに対して実行します。 - 評価する —
.evalset.jsonのテストケースを作成し、adk evalを実行して、ツール呼び出しの軌跡と応答品質のリグレッションを確認します。 - デプロイする — Vertex AI Agent Engine、Cloud Run、または GKE 向けにエージェントをパッケージ化し、開発/ステージング/本番環境の設定を分離します。
エージェントの設計
- 各エージェントの目標、ペルソナ、ツールセットは、明確で一つに絞ります。あらゆることをこなそうとする単一のエージェントは避けてください。
- 柔軟な推論主導の動作には
LlmAgentを使用し、次のステップの判断に LLM が不要な決定論的オーケストレーションにはワークフローエージェント(SequentialAgent、ParallelAgent、LoopAgent)を使用します。 - タスクの境界、ツール使用のルール(「注文に関する質問に答える前に、必ず
lookup_orderを呼び出す」)、エスカレーションの動作(「問題を解決できない場合は、human_handoff_agentに引き継ぐ」)を定めた指示を作成します。 - マルチエージェントシステムは、実装上の都合ではなく、責務ごとに分割します(例:「トリアージ」エージェント、「請求」エージェント、「テクニカルサポート」エージェント)。
- モデル名は設定可能にしておき(環境変数または設定ファイル)、コードを変更せずに
gemini-2.0-flash、gemini-2.5-pro、その他のサポート対象モデルに切り替えられるようにします。 - エージェントの最終応答を、他のコードで利用する構造化データにする必要がある場合は、
output_schema(Pydantic モデル)を使用します。
ツール
- ツールの入出力は、範囲を絞って型を指定します。一つの関数は一つの処理を行うようにし、LLM が呼び出すタイミングを判断するための docstring を付けます。
- 副作用を伴う処理(書き込み、外部呼び出し、決済)の前に、ツールの引数を検証します。
- シークレット、認証情報、特権 API キーをエージェントの指示やプロンプトに含めず、ツールの実装層で注入します。
- ツールのエラーは明示的に処理し、エージェントのループを中断する未処理の例外を送出するのではなく、実行可能なエラーメッセージ(例:
{"status": "error", "message": "order_id not found"})を返します。 - ADK のツールには制限があることに注意してください。一部の組み込みツール(例:
google_search、code_execution)は同じエージェント上で他のツールと併用できません。その場合は専用のサブエージェントに委譲します。 - カスタムの Python ロジックには
FunctionTool、別のエージェントをツールとして呼び出す場合はAgentToolを優先します。組み込みツール(google_search、BuiltInCodeExecutor)は、制約がユースケースに適合する場合にのみ使用します。
例:ツールを使うエージェントの定義
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from google.adk.runners import InMemoryRunner
from google.genai import types
def get_order_status(order_id: str) -> dict:
"""Look up the current status of a customer order.
Args:
order_id: The unique identifier of the order, e.g. "ord-12345".
Returns:
A dict with 'status' ('found' or 'error') and either 'state'
and 'updated_at', or an error 'message'.
"""
if not order_id or not order_id.startswith("ord-"):
return {"status": "error", "message": "invalid order_id format"}
# In production this would call a real order service.
orders = {"ord-12345": {"state": "shipped", "updated_at": "2026-08-30T10:00:00Z"}}
order = orders.get(order_id)
if order is None:
return {"status": "error", "message": f"no order found for {order_id}"}
return {"status": "found", **order}
root_agent = Agent(
name="order_support_agent",
model="gemini-2.0-flash",
description="Answers customer questions about order status.",
instruction=(
"You help customers check their order status. "
"Always call get_order_status before answering an order question. "
"If the tool returns an error, apologize and ask the customer to "
"double-check their order ID. Never invent an order status."
),
tools=[FunctionTool(func=get_order_status)],
)
async def main() -> None:
runner = InMemoryRunner(agent=root_agent, app_name="order_support")
session = await runner.session_service.create_session(
app_name="order_support", user_id="user-1"
)
message = types.Content(
role="user", parts=[types.Part(text="What's the status of ord-12345?")]
)
async for event in runner.run_async(
user_id="user-1", session_id=session.id, new_message=message
):
if event.content and event.content.parts:
for part in event.content.parts:
if part.text:
print(part.text)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
セッション、状態、メモリ
- 現在の会話に関するデータ(会話中に判明したユーザー設定、カウンター、中間結果など)には、
session.stateを使用します。 - セッションをまたいだ想起や検索(セッション終了後も保持し、今後のセッションで検索できるようにする事実)には、
MemoryServiceを使用します。 - 状態値は小さく、シリアライズ可能なもの(文字列、数値、小さな辞書やリスト)にします。大きなファイルやバイナリペイロードをセッション状態に直接保存しないでください。
- 状態キーは安定させ、文書化します。
user:、app:、temp:などのプレフィックスを使って、アプリ全体で状態の有効期間を一貫して管理します。 - 本番環境では、プロセス再起動時にすべての状態が失われる
InMemorySessionServiceではなく、DatabaseSessionServiceまたはマネージド Vertex AI セッションサービスを使用します。
アーティファクト
- 生成ファイル、アップロードファイル、レポート、画像、音声など、その他のバイナリデータにはアーティファクトを使用します。セッション状態には保存しないでください。
save_artifactやload_artifactなどのアーティファクト操作を利用する前に、RunnerでArtifactService(開発用のInMemoryArtifactService、本番用のGcsArtifactServiceなど)を設定します。- アーティファクトのファイル名には意図的にバージョンを付けます(ADK はファイル名ごとにバージョンを自動で増分します)。意味の異なる出力を同じ名前で上書きしないでください。
- 全文をアーティファクトに保存する場合、セッション状態には参照情報または短い要約のみを保存します。たとえば、
report_v2.pdfはアーティファクトとして保存し、"generated report v2"は状態メモとして保存します。
評価とデプロイ
- ツール呼び出しの軌跡(呼び出されたツール、その順序、引数)と最終応答の品質を対象とするテストケースを
.evalset.jsonに追加します。 - CI で
adk eval <agent_module> <eval_set_file>を実行し、指示の変更をマージする前にプロンプトのリグレッションを検出します。 - エージェントの判断をデバッグするには、ADK のトレースとイベントログ(
adk webのトレースビュー、またはRunnerのイベント)を使用します。どのツールが呼び出され、どの引数が渡され、モデルに何が表示されたかを確認します。 - ローカル開発、ステージング、本番環境の設定を分けます(異なる
SessionService/ArtifactServiceバックエンド、異なる API キー、異なるモデル階層を使用します)。 - レイテンシ、ツールの失敗、トークン使用量、ハンドオフの失敗を監視できるようにします。ツール関数を計測・ログ記録用デコレーターでラップし、既存の監視スタックにメトリクスをエクスポートします。
- マネージドで自動スケーリングされるランタイムには Vertex AI Agent Engine にデプロイします。より細かく環境を制御する必要がある場合は、
adk deploy cloud_runまたはカスタム Dockerfile を使って、Cloud Run または GKE 向けにコンテナ化します。
よくある間違い
- 役割を絞ったサブエージェントに分割せず、すべてのワークフローを一つのエージェントに任せる。
- 任意のシェル、SQL、HTTP 入力を検証せずにツールで受け入れ、ツール呼び出しをインジェクションの侵入口にしてしまう。
- アクセス制御をプロンプトの文面に頼る。「他のユーザーのデータを決して明かさない」といった指示はガイダンスであり、強制ではありません。ツールコードで権限を確認してください。
- 支払い、削除、外部への通知など重要な副作用を、
processやhandleのような汎用的なツール名の背後に隠す。ツールには実際の処理内容が分かる名前を付けてください。 - 後続コードが構造化された最終応答に依存しているのに
output_keyやoutput_schemaの設定を忘れ、脆弱な文字列解析が必要になる。 - 指示の変更時に評価を省略する。プロンプトの言い換えによって、モデルが呼び出すツールが気付かないうちに変わることがあります。
コメント
Markdown 対応