Agent Mentor Learn
マルチエージェントコラボレーション · 第 2 回 / 全 6 回

レッスン2: オーケストレーターとサブエージェント: ファンアウトと集約

学習目標:

  • オーケストレーター・サブエージェントアーキテクチャにおいて、オーケストレーターとサブエージェントがそれぞれ何を担当するかを述べる
  • 「コンテキストの分離」が実際に何を分離するのか、そしてそれがなぜ前回のレッスンのコンテキストの汚染と注意の希釈を緩和するのかを説明する
  • サブエージェントが蓄積された思考の流れ全体をオーケストレーターに押し戻すのではなく、結論だけを返すべき理由を説明する

前提: レッスン1を完了し、「マルチエージェントシステム」の定義とそれがどこに適合するかを理解している | 前: レッスン1 << | 次: レッスン3 >>

オーケストレーター: タスクを分割し、配分し、結果を待つ

前回のレッスンで、「3つのクラウドプロバイダーの価格を調査する」ようなタスクは複数のエージェントに分割するのに適していると判断しましたが、その分割が実際にどのように機能するかは詳しく説明しませんでした。それに対する一般的な構造の1つがオーケストレーター・サブエージェントアーキテクチャです。公式の定義は"a central LLM dynamically breaks down tasks, delegates them to worker LLMs, and synthesizes their results."(中央のLLMが動的にタスクを分解し、ワーカーLLMに委任し、その結果を統合する)1です。

この定義は3つのアクションを挙げており、それらはオーケストレーターが行う3つのことに対応しています: 分解する——1つの大きなタスクを見て、どのチャンクに分割されるかを判断する。委任する——各チャンクを、必要な背景とともに、実行するサブエージェントに渡す。統合する——サブエージェントが結果を返したら、それらの結果を最終的な答えにまとめる。オーケストレーター自身は、プロバイダーの価格ページを読みに行きません。その仕事は、作業をどう分割するか、誰が何を得るか、複数の結果を一貫性のある1つの答えにどうつなぎ合わせるかを決めることです。

サブエージェント: 1つのタスクを受け取り、独自のコンテキスト内で完了する

サブエージェント側では、事態はまったく異なる動きをします。ドキュメントは明示的です: "Each subagent starts with a fresh, isolated context window. It doesn't see your conversation history, the skills you've already invoked, or the files Claude has already read. Claude composes a delegation message that summarizes the task, and the subagent works from there."(各サブエージェントは新鮮な、分離されたコンテキストウィンドウから始まる。それはあなたの会話履歴、あなたが既に呼び出したスキル、Claudeが既に読んだファイルを見ない。Claudeはタスクを要約した委任メッセージを作成し、サブエージェントはそこから作業する)2。言い換えると、サブエージェントはあなたが最初にオーケストレーターに何を言ったか、またはオーケストレーターが「これを分割すべきか」「何個に分けるか」を内部でどう検討したかを知りません。見えるのは、オーケストレーターが渡した1つのタスクブリーフだけです。

これは制限のように見えますが、実際には前回のレッスンからの2つの問題の治療法です。サブエージェントのコンテキストはオーケストレーターの完全な会話履歴を持たないため、オーケストレーターが他の場所でぶつかった行き詰まりや、見た無関係な材料も持ちません。これがコンテキストの分離です: 各エージェントの作業範囲を独自のコンテキストウィンドウに限定し、1つのエージェント内のコンテキストの汚染が他のエージェントに広がらないようにします。サブエージェントは自分のタスクの一部分のための材料だけを保持し、3社すべてのコンテンツを一度に扱う必要がないため、注意の希釈の圧力も低下します。会話履歴を一度も見ずにサブエージェントが良い仕事をできるほど明確なタスクブリーフの書き方については、次のレッスンで扱います。

ファンアウト: タスクを分割し、複数のサブエージェントに一度に渡す

3プロバイダーの価格調査例に戻りましょう。オーケストレーターが作業を「最初をチェック」「2番目をチェック」「3番目をチェック」に分解したら、それらを一度に1つずつキューに入れません。3つすべてを一度に渡します——これはまさにプロダクションシステムが行うことです: リードエージェントは3から5のサブエージェントを直列ではなく並列に立ち上げます3。この「すべてを同時に配る」動きがファンアウトです: オーケストレーターは、分割されたサブタスクを、対応する数のサブエージェントに並列に配布し、それぞれが独立して同時に作業を開始できるようにします。最初のサブエージェントが終了するのを待ってから2番目を送り出すのではありません。

ファンアウトからの利益は直接的です: 3つのサブエージェントが並列で作業するということは、合計時間が1つの調査を行うのに近く、3つの合計ではないということです。プロダクションシステムがこの種の並列化を導入した後、複雑なクエリの調査時間は最大90%削減されました3。しかしファンアウトは、タスクを部分にハックして終わりではありません——どう切るかが重要です。3つの会社は自然に独立しているので、3つに切るのはきれいな適合です。「20ページの契約書をレビューする」に切り替えると、条項が互いに参照し制約し合うかもしれません。悪い切り方をすると、サブエージェントはそれぞれ重要なコンテキストを欠き、互いに矛盾する結論に達します。どのように、どれだけ細かく切るかを決めることは、前回のレッスンのテストに戻ります: 切り出した各チャンクは本当に、他のチャンクの中間結果に依存せずに、独自に処理できるものですか?

集約: 結果をまとめる、ただ貼り付けるだけではなく

3つのサブエージェントがそれぞれ自社の価格チェックを終え、結果を返した後、オーケストレーターが行うのは3つのテキストブロックを端から端まで貼り付けることではありません。サブエージェントが返すのは自分の視点からの調査結論であり、オーケストレーターの仕事は集約することです: 独立して生成された複数の結果を並べ、比較し、現れる重複や矛盾を解決し、最終成果物の形に再編成する——明らかに3つのピースをつなぎ合わせたものではなく、1つの全体として読める文書を書きます。

ドキュメントは、サブエージェントが順番に引き渡すことを説明して、こう述べています: "Each subagent completes its task and returns results to Claude, which then passes relevant context to the next subagent."(各サブエージェントはタスクを完了し、結果をClaudeに返し、Claudeは関連するコンテキストを次のサブエージェントに渡す)2。したがって、集約は必ずしも「すべてのサブエージェントが作業を提出するのを待ち、オーケストレーターが一度にすべてを集めて処理する」ほど単純ではありません。場合によっては、早いサブエージェントの結果自体が次のサブエージェントのタスクブリーフの一部であり、オーケストレーターはすべてのサブタスクが結果を持つまで、ファンアウトと集約の間を行き来します。

結果が通る経路も、常にオーケストレーターを経由する必要はありません。サブエージェントが生成するコンテンツが大きく、そのまま保持する必要がある場合、ドキュメントは1つのアプローチに言及しています: "Subagent output to a filesystem to minimize the 'game of telephone.' Direct subagent outputs can bypass the main coordinator for certain types of results, improving both fidelity and performance."(サブエージェントの出力をファイルシステムに出力して「伝言ゲーム」を最小化する。直接的なサブエージェントの出力は、特定の種類の結果のために主要なコーディネーターをバイパスし、忠実度とパフォーマンスの両方を向上させることができる)3。ファイルシステムに直接書き込むことは、結果が「サブエージェント→オーケストレーター→最終出力」の連鎖で言い換えられ、圧縮され、詳細を失うのを防ぐ方法です。

結論だけを返す、サブエージェントの思考の流れ全体ではなく

タスクを完了するために、サブエージェントは途中で多くの無関係な材料のページを読むかもしれないし、どこにも行かないいくつかの経路を試すかもしれないし、小さな間違いをして自分で修正するかもしれません。そのプロセスは、オーケストレーターのコンテキストにそのまま詰め込む必要はありませんし、そうすべきでもありません。オーケストレーターが必要とするのは、サブエージェントの最終的な、擁護可能な結論とそれを裏付ける主要な証拠であって、回り道を含む推論の軌跡全体ではありません。

理由はレッスン1のポイントに戻ります: オーケストレーターは独自のコンテキストウィンドウを持ち、それもまたコンテキストの汚染と注意の希釈を経験します。ドキュメントはこれについて直接的です: サブエージェントが完了すると、その結果はメインの会話に戻り、多くのサブエージェントがそれぞれ詳細な結果を返すと、大量のコンテキストを消費する可能性があります2。3つのサブエージェントがそれぞれ完全な推論の数千語をそのまま押し戻すと、オーケストレーターは、複数のエージェントが緩和するはずだったまさにその問題に、自分のレイヤーで出会うことになります。返却は結論自体だけを運び、「そこにどう到達したか」の詳細はサブエージェント自身のコンテキストに残すべきです。それは既に使い果たされ、まもなく破棄されます。

これは、すべての委任がゼロから始まるという意味ではありません。ドキュメントは特別なサブエージェントタイプに言及しています——フォーク: "A fork is a subagent that inherits the entire conversation so far instead of starting fresh... The fork's own tool calls still stay out of your conversation and only its final result comes back, so your main context window stays clean."(フォークは、新しく始める代わりにこれまでの会話全体を継承するサブエージェントである...フォーク自身のツール呼び出しはあなたの会話の外に留まり、その最終結果だけが戻ってくるので、メインのコンテキストウィンドウはきれいなままである)2。したがって、サブエージェントが完全な履歴を見る必要がまれにある場合でも(例えば、以前のすべてのディスカッションに基づいた深い要約を作成する必要がある場合)、その中間思考はオーケストレーターのコンテキストにそのまま入りません。「結論だけを返す」原則は安定しています。変わるのは、サブエージェントが履歴を手に持って始まるかどうかだけです。

別の言い方: 同じ分業は他のフレームワークにも現れる

「オーケストレーター・サブエージェント」は1つのベンダーの私的な言い回しではありません。OpenAIのAgents SDKドキュメントは同じ構造をManagerパターンと呼んでいます: "A central manager/orchestrator invokes specialized sub‑agents as tools and retains control of the conversation."(中央のマネージャー/オーケストレーターは特化したサブエージェントをツールとして呼び出し、会話のコントロールを保持する)4。単語を入れ替えても——マネージャーをオーケストレーター、agents-as-toolsをサブエージェントに——同じことを説明しています: 中央のノードがタスクを分解し、作業を配分し、全体のコントロールを保ち、実際の実行は専門的な部下に行き、彼らは結果を返し、中央のノードは次に何が来るかを操縦し続けます。この分業の形を認識することは、1つのフレームワークの用語を暗記することよりも重要です——ほぼすべてのマルチエージェントフレームワークのドキュメントで、このロジックの何らかのバリアントを見ることになります。

まとめ

  • オーケストレーター・サブエージェントアーキテクチャでは、中央のLLMがタスクを分解し、サブタスクを複数のワーカーLLMに委任し、その結果を統合します1。オーケストレーター自身はサブタスクの詳細な内容を処理しに行きません。
  • 各サブエージェントはデフォルトで新鮮な、分離されたコンテキストウィンドウから始まり、オーケストレーターの会話履歴を見ることができません2——これがコンテキストの分離であり、前回のレッスンからのコンテキストの汚染と注意の希釈を緩和するための鍵となるメカニズムです。
  • ファンアウトは分割されたサブタスクを複数のサブエージェントに並列に配布して一度に作業させます。集約はサブエージェントの返答の単純な貼り付けではなく、比較し、矛盾を解決し、1つのフォーマットに再編成するステップです。そして結果の受け渡しは、オーケストレーターをバイパスしてファイルシステムに直接書き込むこともでき、言い換えで失われる情報を減らすことができます3
  • サブエージェントが終了した後、その結果はオーケストレーターに返ります2。返されるべきものは結論だけであり、ぶつかった回り道や思考の流れ全体ではありません——ドキュメントは、多くのサブエージェントがそれぞれ詳細な結果を返すと大量のコンテキストを消費する可能性があることを明示しており2、オーケストレーターは自分のレイヤーでコンテキストの汚染と注意の希釈に再び出会うことになります。
  • 「オーケストレーター・サブエージェント」は1つのフレームワークの私的な言い回しではありません——OpenAI Agents SDKは同じ構造をManagerパターンと呼び、中央のマネージャーがサブエージェントをツールとして呼び出しながら会話のコントロールを保持します4。この分業の背後にある共有されたロジックを認識することは、どんな1つの用語を暗記することよりも重要です。

>> レッスン3: 委任のためのプロンプトを書く

Footnotes

  1. Building effective agents (Anthropic Engineering) — https://www.anthropic.com/engineering/building-effective-agents 2

  2. Create custom subagents (Claude Code Docs) — https://code.claude.com/docs/en/sub-agents 2 3 4 5 6 7

  3. How we built our multi-agent research system (Anthropic Engineering) — https://www.anthropic.com/engineering/multi-agent-research-system 2 3 4

  4. Agents (OpenAI Agents SDK) — https://openai.github.io/openai-agents-python/agents/ 2

練習

01

タスクは: 「オープンソースプロジェクトの最後の10件のPRをレビューし、コアの権限ロジックに触れたPRを見つけ、そのような各PRにリスクノートを書く」。答えてください:

レベル1: コードレビュータスクのオーケストレーター/サブエージェント分割を描く
  1. オーケストレーターは何をすべきですか?
  2. このタスクはどうファンアウトすべきですか——いくつのチャンクに、そして各チャンクはおおよそ何ですか?
  3. サブエージェントが終了したら、何を返すべきですか?そしてオーケストレーターが返却を得たら、「集約」ステップは正確に何ですか?
完了基準 · ローカルでチェック
02

誰かがこんなオーケストレーター・サブエージェントフローを設計しました: 「最初から、オーケストレーターはユーザーとの完全な会話履歴をパッケージ化します——このタスクとは無関係な数ラウンドの雑談を含む——そしてそれを背景としてすべてのサブエージェントに送ります。論理は「サブエージェントが何か背景を必要とする場合に備えて、最初に与えることは省くことよりも良い」です」。この設計の問題を見つけ、より良いアプローチを示してください。

レベル2: このオーケストレーション設計の問題を見つける
完了基準 · ローカルでチェック