0
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 ADK 1.31でCoordinator+Sub-Agentシステムを5分で構築する

0
Posted at

qiita-adk-multi-agent-thumbnail.png
2026年4月22日、Google Cloud Next 2026の基調講演でGoogleはGemini Enterprise Agent Platformを発表しました。中身としては Vertex AI の進化版で、Agent Studio / Agent Garden / Agent Development Kit (ADK) / Agent Gateway などを1つのスタックにまとめた構成です。そしてPython用の google-adk は4月21日に 1.31.1 がリリースされたばかりです。

この記事では、ADK 1.31系を使って「ユーザー入力を受け取るコーディネーター」が「天気を調べる専門エージェント」と「挨拶担当のエージェント」にタスクを委譲する、グラフ構造のマルチエージェントを動かすところまでを5分でやります。

※ 本記事は公開情報をもとにした個人的なまとめです。

前提

  • Python 3.10 以上(PyPIの google-adk 1.31.1 は Python>=3.10
  • Google AI StudioのAPIキー(もしくはVertex AIのプロジェクト)
  • OS: Linux / macOS / Windowsのいずれか。GPUは不要です(APIコール先はGoogle側)。

ハードウェア目安

ローカルでは推論しないので、開発マシンのスペック要件はほぼありません。実用レベルの目安は次の通りです。

  • CPU: 2コア以上(手元のノートPCで十分)
  • RAM: 4GB以上
  • ディスク: 仮想環境込みで1GB未満
  • ネットワーク: Gemini API と双方向で話せる回線

ローカルLLMに切り替える場合は LiteLLM プロバイダ経由で Ollama を刺せますが、そちらは別記事向けの話題です。

ステップ1: インストール

仮想環境を切ってインストールします。公式の手順そのままです。

python3 -m venv .venv
source .venv/bin/activate        # Windowsは .venv\Scripts\activate
pip install google-adk==1.31.1

バージョン確認も一応しておきます。

pip show google-adk | head -n 2
# Name: google-adk
# Version: 1.31.1

個人的な感想: 4月の週次リリースで v1.31 系に入ってからは、Agent Studio側のUIとPythonパッケージ側の挙動がかみ合うようになって、adk web の体験が目に見えて安定しました。

ステップ2: APIキーを設定

ADKはデフォルトでGemini APIを呼びます。プロジェクトディレクトリの .env に書いておけば勝手に読み込まれます。

# .env
GOOGLE_API_KEY="AIza...(AI Studioで発行したキー)"
GOOGLE_GENAI_USE_VERTEXAI=FALSE

Vertex AI側を使う場合は GOOGLE_GENAI_USE_VERTEXAI=TRUE にして、GOOGLE_CLOUD_PROJECTGOOGLE_CLOUD_LOCATION を足します。

ステップ3: ディレクトリ構成

ADKは「1エージェント = 1ディレクトリ」の規約が強めで、ここを外すとCLIが沈黙します。

trip_team/
├── __init__.py
├── agent.py
└── .env

__init__.py は1行だけ。

# trip_team/__init__.py
from . import agent

この1行が地味に重要で、抜けていると adk run trip_team で「root_agent が見つからない」系のエラーが出ますadk create trip_team で雛形を作れば自動で書かれます。

ステップ4: シングルエージェントを先に動かす

まずは1エージェントだけで動く形を確認します。

# trip_team/agent.py
from google.adk.agents import Agent

def get_weather(city: str) -> dict:
    """Return a fake weather report for a city.

    Args:
        city: The city name, e.g. "Tokyo".

    Returns:
        A dict with temperature in Celsius and a short condition string.
    """
    table = {
        "Tokyo": {"temp_c": 19, "condition": "rainy"},
        "Osaka": {"temp_c": 21, "condition": "cloudy"},
        "Sapporo": {"temp_c": 8, "condition": "snowing"},
    }
    return table.get(city, {"temp_c": 20, "condition": "unknown"})

root_agent = Agent(
    model="gemini-flash-latest",
    name="root_agent",
    description="Answers travel questions using live tools.",
    instruction=(
        "あなたは旅行アシスタントです。都市名を受け取ったら"
        " get_weather ツールで天気を取り、短くまとめて返答してください。"
    ),
    tools=[get_weather],
)

実行はtrip_team/親ディレクトリから打ちます。ここがもう1つのハマりどころで、cd trip_team && adk run . みたいにエージェントディレクトリに入った状態で叩くと認識されません。

adk run trip_team

対話型で 札幌の天気は? と聞けば、ツール呼び出しのログと最終応答が流れてくるはずです。

ステップ5: サブエージェントを束ねるコーディネーターを作る

ここからが本題です。2つの専門エージェントを sub_agents で束ねて、Coordinatorにルーティングを任せます。ADKの LlmAgentsub_agents 引数を渡すと、transferToAgent 関数呼び出しで子エージェントに委譲する AutoFlow が自動的に有効になります。

agent.py を次のように置き換えます。

# trip_team/agent.py
from google.adk.agents import LlmAgent

def get_weather(city: str) -> dict:
    """Return a fake weather report for a city."""
    table = {
        "Tokyo": {"temp_c": 19, "condition": "rainy"},
        "Osaka": {"temp_c": 21, "condition": "cloudy"},
        "Sapporo": {"temp_c": 8, "condition": "snowing"},
    }
    return table.get(city, {"temp_c": 20, "condition": "unknown"})

weather_agent = LlmAgent(
    name="weather_agent",
    model="gemini-flash-latest",
    description="Looks up current weather for a given city.",
    instruction=(
        "あなたは天気専門のサブエージェントです。"
        " 都市名を受け取ったら get_weather を1回だけ呼び、要点を1文で返してください。"
    ),
    tools=[get_weather],
)

greeter_agent = LlmAgent(
    name="greeter_agent",
    model="gemini-flash-latest",
    description="Greets the user and confirms what they want to plan.",
    instruction=(
        "あなたは旅の出だしを整えるサブエージェントです。"
        " 最初のあいさつと、目的地や日付を整理するだけに専念してください。"
    ),
)

root_agent = LlmAgent(
    name="coordinator",
    model="gemini-flash-latest",
    description="Routes the user request to the right specialist.",
    instruction=(
        "あなたは旅行コーディネーターです。"
        " あいさつや予定の整理が必要なときは greeter_agent に、"
        " 天気の照会は weather_agent に委譲してください。"
        " 自分でツールを呼ぼうとしないこと。"
    ),
    sub_agents=[greeter_agent, weather_agent],
)

sub_agents=[...] を渡すと、子エージェントそれぞれの description がLLMに「どの子に投げるべきか」のヒントとして見えるようになります。description をサボると振り分けが崩れるので、タイトル風ではなく「何を受け付け、何を返すか」を1文で書くのがコツです。

ステップ6: Web UIから動きを見る

adk web を立てると、どのサブエージェントに遷移したかがステップごとに表示できるので、デバッグがぐっと楽になります。

adk web --port 8000

起動後、http://localhost:8000 に出てくるエージェント選択から trip_team を選び、こんにちは、札幌に行く予定です。天気を教えて のような投げ方をしてみてください。挨拶→委譲→天気取得→最終応答の流れが画面に出ます。

ステップ7: プログラム側から呼び出す

最終的に Slack Bot や社内ツールに組み込むときは、Runner から直接叩きます。ここは run_async が基本APIです。

# run_trip_team.py
import asyncio
from google.adk.runners import InMemoryRunner
from google.genai import types as genai_types
from trip_team.agent import root_agent

async def main() -> None:
    runner = InMemoryRunner(agent=root_agent)
    session = await runner.session_service.create_session(
        app_name=runner.app_name, user_id="user-1"
    )

    user_message = genai_types.Content(
        role="user",
        parts=[genai_types.Part(text="こんにちは、札幌の天気を教えて")],
    )

    async for event in runner.run_async(
        user_id="user-1",
        session_id=session.id,
        new_message=user_message,
    ):
        if event.content and event.content.parts:
            for part in event.content.parts:
                if part.text:
                    print(f"[{event.author}] {part.text}")

if __name__ == "__main__":
    asyncio.run(main())

InMemoryRunner はセッションを内部で持ってくれるので、サーバー常駐でなければこれで十分です。本番サーバーでは RunnerDatabaseSessionService などを渡して永続化します。

覚えておきたいハマりどころ

30分削れる類の落とし穴をまとめます。

  • __init__.pyfrom . import agent を書く: これを抜かすと adk run が静かに失敗します。adk create コマンドで作ると自動で入ります。
  • CLIはエージェントディレクトリの親で実行する: adk run trip_team はOK、cd trip_team && adk run . はNG。
  • sub_agents を渡したCoordinatorに自前ツールを追加しない: AutoFlowの委譲とツール呼び出しが競合してルーティングが不安定になります。Coordinatorは「仕分け」役に徹するのが鉄則。
  • gemini-flash-latest のエイリアス: 現行の公式サンプルでも使われているので、特定バージョン固定が要らなければこれで十分です。固定したい場合は gemini-2.5-flash のような具体バージョンに差し替えます。
  • adk web は開発用: 本番向けではないとドキュメントに明記されています。adk api_server か、FastAPI から Runner を叩く形に切り替えてください。

まとめ

  • ADK 1.31.1 + sub_agents で、10分かからずにCoordinatorと専門エージェントのグラフが組める。
  • Gemini Enterprise Agent Platformの中核はこのADKなので、個人検証で書いたエージェントがそのまま社内展開に寄せやすい構造になっている。
  • 落とし穴は「ディレクトリ規約」と「__init__.py の1行」と「CoordinatorにツールをつけすぎないAND description を手を抜かない」の3点が8割。
  • モデル名は gemini-flash-latest のエイリアスで始め、本番に寄せるタイミングで具体バージョンへ。
  • Gemini Enterprise Agent PlatformはGA発表直後なので、ドキュメントの細部は数週間単位で動く前提で運用設計するのが安全です。

参考

  • Introducing Gemini Enterprise Agent Platform (Google Cloud Blog)
  • google/adk-python (GitHub)
  • google-adk 1.31.1 (PyPI)
  • Multi-agent systems - ADK docs
0
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
0
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?