ag2-subagent-delegation について
AG2 で複数のエージェントを連携させる開発者向けスキルです。自動サブタスクツールや名前付き子エージェントのツール化に加え、並列実行とストリーム管理を説明します。
主な機能
- 01run_subtask と run_subtasks を有効化
- 02独立したサブタスクを並列実行
- 03子エージェントを名前付きツール化
- 04サブタスクが使うツールを絞り込み
- 05サブタスクのストリームを再利用・カスタマイズ
活用シーン
- 01複雑な作業を専門エージェントに分割
- 02独立した調査課題を並行処理
- 03名前付きの調査・執筆エージェントに作業を委任
- 04複数回の呼び出しで委任先の履歴を保持
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ag2ai/ ag2-skills --skill ag2-subagent-delegationインストール後、Claude Code で/ag2-subagent-delegationを入力して読み込まれたか確認します。
同梱ファイルassets/research_squad.py
詳細
サブエージェントへの委譲
使用する場面
- 「コーディネーター+専門家」— 親エージェントがタスクの一部を調査エージェント、数学エージェントなどに割り当てる場合。
- 「並列実行してから集約」— 各部分が独立している複数の質問で、並列実行によって所要時間を短縮できる場合。
- 「自己委譲」— 1つのエージェントが、複雑な作業を自分向けの重点的なサブタスクに分割する場合。
2つのパターン
| パターン | 使用する場面 | API |
|---|---|---|
自動注入 run_subtask / run_subtasks | 軽量な自己委譲、動的な並列実行、並列で処理するサブ質問 | 親エージェントの tasks=TaskConfig(...) |
Agent.as_tool() | LLM が推論して呼び出す、明確な名前を持つ委譲先(「調査担当を呼ぶ」「執筆担当を呼ぶ」) | 子エージェントを親エージェントのツールとしてラップ |
2つは組み合わせて使用できます。コーディネーターは両方を持てます。
パターン 1 — 自動注入される run_subtasks
サブタスク用ツールはデフォルトで無効です(tasks=False)。tasks=TaskConfig(...) を指定すると、エージェントで以下を使用できるようになります。
run_subtask(task: str)— 分離された1つのサブタスクエージェント。run_subtasks(tasks: list[str], parallel: bool = True)— 1回のツール呼び出しで複数のタスクを並列実行します(デフォルトでは同時実行)。
from ag2 import Agent, TaskConfig
from ag2.config import GeminiConfig
config = GeminiConfig(model="gemini-3-flash-preview")
coordinator = Agent(
"coordinator",
prompt=(
"You answer multi-part questions by dispatching run_subtasks "
"with parallel=True. Use one tool call with every sub-question "
"packed into the 'tasks' list."
),
config=config,
tasks=TaskConfig(), # opt in
)
reply = await coordinator.ask(
"In one run_subtasks call, answer: "
"(a) tallest waterfall, (b) Eiffel Tower year, (c) boiling point of nitrogen."
)
TaskConfig はサブタスクエージェントの構築方法を制御します。
@dataclass
class TaskConfig:
config: ModelConfig | None = None # falls back to parent's config
prompt: str = "You are a task agent..."
include_tools: Iterable[str] | None = None # None = inherit all parent tools
exclude_tools: Iterable[str] = ()
extra_tools: Iterable[Callable | Tool] = ()
一般的な構成 — サブタスクには低コストのモデルを使い、使用できるツールを絞ります。
TaskConfig(
config=worker_config, # smaller model
prompt="You are a focused worker; one step only.",
include_tools=["search", "fetch_url"], # don't expose `summarize` to children
)
サブタスクエージェントは tasks=False で構築されるため、サブタスクエージェント自身が run_subtask ツールを持つことはありません。再帰的な委譲は構造上不可能なので、深さの上限を設ける必要はありません。
パターン 2 — Agent.as_tool()
エージェント全体を、LLM が名前を指定して呼び出せるツールとして公開します。
from ag2 import Agent
from ag2.config import AnthropicConfig
config = AnthropicConfig(model="claude-sonnet-4-6")
researcher = Agent("researcher", prompt="Provide concise factual findings.", config=config, tools=[search_tool])
writer = Agent("writer", prompt="Turn research into clear prose.", config=config)
coordinator = Agent(
"coordinator",
prompt="First delegate research, then pass findings to the writer.",
config=config,
tools=[
researcher.as_tool(description="Research a topic and return findings."),
writer.as_tool(description="Write an article. Pass research notes in the context parameter."),
],
)
コーディネーターの LLM には task_researcher と task_writer が表示されます。各呼び出しには2つのパラメーターがあります。
objective(必須)— サブタスクで実行する内容です。context(任意)— 親エージェントが共有する関連情報です。
as_tool() で指定できるパラメーターは次のとおりです。
| パラメーター | 説明 |
|---|---|
description | LLM に表示するツールの説明(必須) |
name | デフォルトの task_{agent.name} を上書きします |
stream | カスタムのサブタスクストリーム用の StreamFactory(下記参照) |
middleware | ToolMiddleware 呼び出し可能オブジェクト(例:approval_required) |
より細かく制御するには、subagent_tool() を直接使用します。
from ag2.tools.subagents import subagent_tool
coordinator = Agent("coordinator", config=config, tools=[
subagent_tool(researcher, description="Research a topic."),
])
as_tool() による自己委譲
汎用的な run_subtask ではなく、名前付きの自己委譲(sub_task)を使いたい場合は、エージェント自身のツールとして追加します。
analyst = Agent(
"analyst",
prompt=(
"You have search and sub_task tools. "
"Only use sub_task when the task has clearly independent parts."
),
config=config,
tools=[search_tool],
)
analyst.add_tool(
analyst.as_tool(
description="Break work into a focused sub-task for independent analysis.",
name="sub_task",
)
)
再帰の安全対策
as_tool() による自己委譲では再帰が発生する可能性があります。子エージェントが同じ sub_task ツールを持つため、ガードがないと LLM が呼び出しを無限に連鎖させることがあります。
最も簡単な安全な方法は、自己委譲には自動注入される run_subtask / run_subtasks を優先することです。この方法で起動したサブタスクは tasks=False で構築されるため、run_subtask ツールを持たず、再帰は構造上不可能です。
再帰的な as_tool() による自己委譲がどうしても必要な場合は、context.dependencies の深さカウンターを増加させ、しきい値を超えたら処理を短絡するツールミドルウェアを作成してください。subagents モジュールは ag2.tools.subagents から subagent_tool、background_agent_tool、persistent_stream、StreamFactory をエクスポートしています。組み込みの深さ制限ヘルパーに依存する前に、現在の公開インターフェースを確認してください。
サブタスクのストリーム
デフォルトでは、各サブタスクに新しい MemoryStream が割り当てられます。履歴は分離され、空の状態から始まります。コンテキストの受け渡しは次のとおりです。
| 対象 | 動作 | 理由 |
|---|---|---|
| 依存関係 | コピー(トップレベルのみの浅いコピー) | 分離されています。サブタスク内では依存関係を読み取り専用として扱ってください |
| 変数 | コピーされ、親エージェントには同期されません | 並行実行に対応できます。asyncio.gather で兄弟タスクを実行した場合、後から書き込まれた値が先の値を黙って上書きする可能性があるため、子の変更は設計上、子のスコープ内に留まります |
| 履歴 | 新しいストリーム | コンテキストを整理した状態に保ち、関連情報は context ツールパラメーターを通じて渡します |
| ツール | 親エージェントから継承(TaskConfig でフィルタリング) | サブタスクが作業を行うには、実際に使用できる機能が必要です |
persistent_stream()
サブエージェントが過去の呼び出しを参照できると便利な場合(検索の繰り返しを避ける場合など)は、親コンテキスト内の呼び出し間で維持されるストリームを渡します。
from ag2.tools.subagents import persistent_stream
researcher.as_tool(
description="Research a topic",
stream=persistent_stream(),
)
ストリーム ID は context.dependencies に f"ag:{agent.name}:stream" をキーとして保存され、親ストリームのストレージバックエンドが再利用されます。
カスタムファクトリー
from ag2 import Agent, Context
from ag2.streams.redis import RedisStream
def make_redis_stream(agent: Agent, ctx: Context) -> RedisStream:
return RedisStream(MY_REDIS_URL, prefix=f"ag2:sub:{agent.name}")
researcher.as_tool(description="Research a topic", stream=make_redis_stream)
さらに詳しく
- 動作するスターター:
assets/research_squad.py(code_examples/05に対応)。run_subtasks(parallel=True)とAgent.as_tool()の両方を扱い、TaskStarted/TaskCompletedのライフサイクルイベントも含みます。 - 完全なリファレンス:
website/docs/user-guide/subagents.mdx。 tasks=コンストラクターパラメーター(KnowledgeConfigなど):website/docs/user-guide/agent_harness.mdx。
よくある落とし穴
- 有効化を忘れる —
tasks=Falseがデフォルトです。TaskConfigを指定しないと、run_subtaskツールは使えません。 - サブタスクが
run_subtaskで再帰すると期待する — サブタスクは再帰できません。サブタスク自体はtasks=Falseです。より深い階層が必要な場合は、手動の深度カウンターミドルウェアを使ってAgent.as_tool()で自身に委譲してください(上記の「再帰の安全性」を参照)。 - 変更が統合されることを期待して、ミュータブルな変数を共有する — 各サブタスクは親の変数をコピーしますが、変更が親に同期されることはありません(成功した場合も同様です)。兄弟サブタスク間で変更が伝播することもありません。必要な結果は、共有変数ではなくサブタスクの戻り値で渡してください。
dependenciesがサブタスクごとに分離されていると考える — コピーされるのは最上位の dict だけです。その中のミュータブルな値は引き続き参照によって共有されます。サブタスク内では dependencies を読み取り専用として扱ってください。as_tool()にdescription=がない — LLM はいつ呼び出すべきか分かりません。必須パラメーターです。- 並行処理する作業で
run_subtasks(parallel=False)を使う — デフォルトがTrueなのには理由があります。後続のタスクが先行タスクの結果に依存する場合にのみ、Falseを設定してください。 task_{agent.name}の衝突を見落とす — 短い名前や、同じエージェントの異なる委譲先が必要な場合は、name=を渡して上書きしてください。