最近は Google Agent Developer Kit (通称: ADK) でエージェントを自作して遊んでいます。
サブエージェントにタスクを委譲ってやつをやってみました。そしたら思ってたんと違ったので書き記します。
サブエージェントが思ってたんと違った
ADK ではとても簡単にサブエージェントを定義可能です。最小コードはこんな感じ。
from google.adk.agents.llm_agent import Agent sub_agent = Agent(name="sub", ...) root_agent = Agent( name="root", tools=[], sub_agents=[sub_agent], # ← サブエージェントとして追加 )
これで親エージェントとの会話中、必要に応じてサブエージェントに処理が委譲されます。が、 サブエージェントから処理が戻ってきません 。
sequenceDiagram
participant ユーザー
participant 親エージェント
participant サブエージェント
ユーザー->>親エージェント: このタスク頼む
activate 親エージェント
親エージェント->>親エージェント: (これはサブエージェントが得意そうやな...)
親エージェント->>サブエージェント: このタスク頼む
deactivate 親エージェント
activate サブエージェント
サブエージェント->>サブエージェント: (あれこれ処理する)
サブエージェント->>ユーザー: タスク完了しました!
deactivate サブエージェント
サブエージェントに委譲するのはいいとして、コミュニケーション役は親エージェントに一任したい。
私の理想はこうです、
sequenceDiagram
participant ユーザー
participant 親エージェント
participant サブエージェント
ユーザー->>親エージェント: このタスク頼む
activate 親エージェント
親エージェント->>親エージェント: (これはサブエージェントが得意そうやな...)
親エージェント->>サブエージェント: このタスク頼む
activate サブエージェント
サブエージェント->>サブエージェント: (あれこれ処理する)
サブエージェント->>親エージェント: タスク完了しました!
deactivate サブエージェント
親エージェント->>親エージェント: (なるほどなるほど)
親エージェント->>ユーザー: タスク完了しました!
deactivate 親エージェント
この挙動の差は「サブエージェント」と「エージェントツール」の違いを認識することで理解できるようになります。
「サブエージェント」と「エージェントツール」という別概念
親エージェントから別のエージェントを利用する方法には「サブエージェント」と「エージェントツール」の二つあり、これらは別の概念です。
まずはコードで見比べてみましょう。
# サブエージェント from google.adk.agents.llm_agent import Agent sub_agent = Agent(name="sub", ...) root_agent = Agent( name="root", tools=[], sub_agents=[sub_agent], # ← サブエージェントとして追加 )
# エージェントツール from google.adk.agents.llm_agent import Agent from google.adk.tools.agent_tool import AgentTool sub_agent = Agent(name="sub", ...) root_agent = Agent( name="root", tools=[AgentTool(agent=sub_agent)], # ← エージェントツールとして追加 sub_agents=[], )
親エージェントに sub_agents=[sub_agent] で渡すか tools=[AgentTool(agent=sub_agent)] で渡すかの違いです。
そもそも、なぜサブエージェントが必要か
エージェントを賢くするには様々なツールを追加することになります。が、実はツール説明もコンテキストを圧迫します。
そのためエージェント強化のためにツールを追加しまくるとコンテキストが埋まってしまい、ユーザーの指示をうまく理解できなくなるジレンマが起こります。
そこでサブエージェントです。専門性の高いエージェントを定義し、専門に合ったツールだけ渡すことでコンテキストを節約します。そして専門知識が必要なときだけサブエージェントを呼んでもらうわけです。
指示 (Instruction) についても親エージェントのものとは別に専用のものを渡せるので、挙動を細かくカスタマイズする余地が生まれていいですね。
サブエージェントの特徴
sub_agents=[sub_agent] でサブエージェントを渡した場合、コミュニケーション役が親エージェントからサブエージェントに完全に切り替わる挙動になります。
実生活で例えるなら、窓口での会話中に「詳しい者に担当者代わります」と別の担当者が出てくる感じです。
さらに親エージェントとサブエージェントはコンテキストを共有しています。
- メリット: サブエージェントから元の会話履歴が見えるのでコミュニケーションがスムーズ
- デメリット: サブエージェントに切り替え後もメインのコンテキストを圧迫し続ける
- コンテキストをサブエージェントに閉じて親コンテキストを節約する効果は期待できない
このような挙動は汎用性の高い (やれることの多い) エージェントにおいて、ユーザーの要望に応じて順次エージェントを切り替えて処理するのに使えそうです。
例えば「旅行計画エージェント」を作っているとして。最初は親エージェントが要望を聞き、内容に応じて
- 目的地調査エージェント
- 交通手段調査エージェント
- 予約エージェント
などに切り替えながら処理をするのに使えそうです。
エージェントツールの特徴
対して、エージェントツールは AgentTool(agent=sub_agent) を作成し、tools= 引数に渡すことで実装します。
エージェントツールにおいては、一貫して親エージェントがオーケストレーションとコミュニケーション役を担います。ユーザーがエージェントツールと会話することはありません。
実生活で例えると、窓口担当者は一人で、裏側の処理中に専門家が監修・分業しているイメージです。
さらに親エージェントとエージェントツール (サブエージェント) でコンテキストが切り離されます。
- メリット: サブエージェントのコンテキストが親コンテキストを圧迫しない
- 親コンテキストの圧縮・忘却・ハルシネーションを抑止できる
- デメリット: 親エージェント・サブエージェント間で指示とレスポンスの受け渡しが発生する分、処理時間が増える
- サブエージェントに委譲する前の親エージェントの思考時間
- サブエージェントから結果を受けた後の親エージェントの思考時間
親エージェントのコンテキスト圧迫を防ぎつつ出来ることを増やすにはエージェントツールが適しています。
まとめ
サブエージェントとエージェントツールを表で比較すると。
| サブエージェント | エージェントツール | |
|---|---|---|
| 会話主体 | 切り替わる | 親のまま |
| コンテキスト | 共有 | 分離 |
| 役割 | 担当交代 | 内部処理 |
| 向いている用途 | 対話の文脈ごと切り替え | 処理の委譲 |
「親エージェントから別のエージェントを呼ぶ」は同じでもユーザー体験は大きく違います。特徴を理解して使い分けることが大切です。
私からは以上です。



