Lesson CH08-L01
Delegation
親Agentが子Agentに部分タスクを委譲する。
- 読了目安
- 11 min
- Colab目安
- 16 min
- 合計
- 27 min
- 前提
- Deferred Tools
関連: 公式ドキュメント
一行サマリ
親 Agent の ツール内から子 Agent.run を呼ぶ だけで、親が制御を保ったまま部分タスクを子に委譲できる。usage=ctx.usage を渡せば トークン消費が親に集約 され、コスト計測も一元化される。マルチエージェントの第一歩。
ヒーロー: ツールが「別 Agent」になる
Ch3 のツールは Python 関数でした。Delegation ではそのツールの中身を 別の Agent.run にすり替えるだけで、親 Agent が 「専門サブ Agent を呼び出すオーケストレータ」 に変わります。LLM 側からは「ツールを呼んだ」ようにしか見えませんが、内部では別 Agent が独自モデル + 独自 instructions で考えています。
概念: Hand-off との違い
| 観点 | Delegation (本レッスン) | Hand-off (次レッスン) |
|---|---|---|
| 制御 | 親が保持。子は終わったら親に戻る | 完全に別 Agent に移譲。元 Agent は関与しない |
| 呼び出し場所 | 親のツール内 | アプリケーションコードで順次切り替え |
| 結果 | 子の戻り値が親のツール戻り値になる | 各 Agent の result を独立して扱う |
| usage の集約 | usage=ctx.usage で親に集約 | 各 run の usage を別々に計測 |
「親が編集権を持って細かく指揮するなら Delegation、専門 Agent に丸投げして次工程に渡すなら Hand-off」と覚えると判断しやすい。
コード: 3 つのパターン
パターン 1: 子 Agent をツール内から呼ぶ最小例
from pydantic_ai import Agent, RunContext
from pydantic_ai.models.google import GoogleModel
model = GoogleModel('gemini-3-flash-preview')
# 子 Agent: 1 つの仕事に特化
joke_agent = Agent(
model,
instructions='与えられたお題で、短い日本語のジョークを 1 つだけ作ってください。',
)
# 親 Agent: 子を「ツール」として持つ
parent = Agent(
model,
instructions='ユーザーのお題に対して generate_joke を呼んでジョークを返してください。',
)
@parent.tool
async def generate_joke(ctx: RunContext, topic: str) -> str:
"""指定トピックでジョークを生成する。"""
result = await joke_agent.run(topic, usage=ctx.usage)
return result.output
print(parent.run_sync('猫').output)
print(parent.run_sync('プログラマー').output)ポイント:
@parent.tool内でawait child_agent.run(...)usage=ctx.usageを渡すと子 Agent のトークン消費が親の usage に積算される- 子は stateless で別ファイルに切り出して再利用可能
パターン 2: 専門 Agent 複数を「束ねる」オーケストレータ
from pydantic_ai import Agent, RunContext
from pydantic_ai.models.google import GoogleModel
translator = Agent(
GoogleModel('gemini-3-flash-preview'),
instructions='与えられた文を自然な日本語に翻訳してください。',
)
summarizer = Agent(
GoogleModel('gemini-3-flash-preview'),
instructions='与えられた日本語を 2 文以内で要約してください。',
)
orchestrator = Agent(
GoogleModel('gemini-3-flash-preview'),
instructions=(
'英語のニュース文が来たら、まず translate_to_ja で翻訳し、'
'次に summarize で要約してから返してください。'
),
)
@orchestrator.tool
async def translate_to_ja(ctx: RunContext, en_text: str) -> str:
"""英語を日本語に翻訳する。"""
return (await translator.run(en_text, usage=ctx.usage)).output
@orchestrator.tool
async def summarize(ctx: RunContext, ja_text: str) -> str:
"""日本語を 2 文以内に要約する。"""
return (await summarizer.run(ja_text, usage=ctx.usage)).output
print(orchestrator.run_sync(
'OpenAI announced new model series with improved coding ability.'
).output)専門 Agent 同士はお互いを知らず、親が呼出順序を組む ことで「翻訳 → 要約」のパイプラインが組み上がります。
パターン 3: 構造化出力とのコンビ
子 Agent の output_type を BaseModel にすると、親のツールが構造化データを返す ようになります。
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
from pydantic_ai.models.google import GoogleModel
class Sentiment(BaseModel):
polarity: str = Field(description='positive / neutral / negative のいずれか')
confidence: float = Field(description='0.0 〜 1.0 の確信度')
reason_ja: str = Field(description='判断理由の日本語要約 (60 字以内)')
sentiment_agent = Agent(
GoogleModel('gemini-3-flash-preview'),
output_type=Sentiment,
instructions='文の感情を分析し、極性 / 確信度 / 理由を日本語で返してください。',
)
parent = Agent(
GoogleModel('gemini-3-flash-preview'),
instructions='ユーザーが与える文の感情を analyze_sentiment で分析して報告してください。',
)
@parent.tool
async def analyze_sentiment(ctx: RunContext, text: str) -> Sentiment:
"""文の感情を構造化分析する。"""
return (await sentiment_agent.run(text, usage=ctx.usage)).output
print(parent.run_sync('今日の発表は本当にひどかった。').output)子 Agent の構造化出力 (Sentiment) がそのままツール戻り値になり、親 LLM がそれを読んで自然言語に整形します。
観察: usage を見て本当に集約されているか確認
result = parent.run_sync('プログラマー')
print(result.usage())
# RunUsage(requests=2, input_tokens=350, output_tokens=120, ...)
# ^^^ 親 1 回 + 子 1 回 = 2requests が 親 + 子の合計 になっていれば集約成功。usage=ctx.usage を忘れると親 = 1、子の usage はロストします。
まとめ
- 親 Agent のツール内から
await child_agent.run(prompt, usage=ctx.usage)を呼ぶだけで Delegation usage=ctx.usageを必ず渡してトークン消費を親に集約- 専門 Agent を複数組み合わせて オーケストレータ が呼出順序を決められる
- 子の
output_type=BaseModelで構造化データのまま親に戻せる - ネストは 2 段まで が推奨。深いワークフローは Hand-off / Graph へ
次レッスンでは Hand-off — 制御を完全に別 Agent に渡す Programmatic ハンドオフを扱います。
Colab で実際に動かす
本レッスンの内容を Google Colab 上で実行できるノートブックを用意しています。下のボタンから自分のColab環境に開けます (要 Google アカウント / GOOGLE_API_KEY)。
notebooks/ch08/01-delegation.ipynb