agent-orchestrator について
マルチエージェントシステムを構築する開発者向けの、本番設計ガイドです。ツール呼び出し、サブエージェント、段階的なワークフロー、モデルルーティング、メモリ、予算管理を扱います。
主な機能
- 01共有コンテキストとサブエージェントのプロトコル
- 02ツールループ、リトライ、結果検証
- 03依存関係とチェックポイントを持つ段階的ワークフロー
- 04LLM プロバイダーのルーティングとフォールバック
- 05階層型メモリとフィードバック学習
- 06コンテキスト予算、可観測性、ガードレール
活用シーン
- 01ツールを呼び出すエージェントループの設計
- 02依存関係のある複数段階タスクの調整
- 03モデルプロバイダーのルーティングとフォールバック設定
- 04エージェントのコンテキストと呼び出し予算の管理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ssheleg/ agent-stack --skill agent-orchestratorインストール後、Claude Code で/agent-orchestratorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/context-engineering.mdgovernance.mdgraph-engineering.mdkv-cache.mdllm-proxy-billing.mdmemory-architecture.mdmemory-landscape.mdmemory-lifecycle.mdpatterns.mdpipeline.mdprovider-lifecycle.mdruntime.md詳細
エージェントオーケストレーター — 本番環境でのベストプラクティス
本番環境のマルチエージェントシステムから得られたパターンです。本文は意思決定を示し、仕組みはすぐ参照できる別ファイルにあります。また、4750 トークンの予算内に収めています。本文が長くなると、分割すべきレイヤーを取り込んでしまいます。実際、この本文は 2026-08-16 までそうなっていました。
トリガー
「ツール呼び出し」、「LLM ルーター」、「フォールバックチェーン」、「メモリレイヤー」、「トークンウォレット」、「роутер моделей」、「слой памяти」、「граф задач」。
スコープに基づいてこちらに振り分けられる内容もあります。説明文に 0.30.0 まで記載されていたのは、ツール呼び出しループ、人間によるチェックポイントを設けたパイプライン、プロバイダールーティング、フォールバック/再試行、メモリアーキテクチャ、検索と減衰、コンテキスト予算、サブエージェントの連携、エラー階層です。作業をグラフとして捉えること(並列レイヤー、偽のエッジ、収束前のチェッカー)、再販向けの構成(階層型ウォレット、単一のマークアップ境界、データベースとプロバイダー API をまたぐサーガ、支出差分のポーリング、予算とループのガード、テナントごとのキー)も含まれます。
0.31.3 で説明文からこちらに移動しました:「оркестратор」、「суб-агент」、「human in the loop」、「человек в цикле」、「биллинг LLM」。
アーキテクチャの概要
User Question
↓
OrchestratorAgent.run(AgentContext)
├─ Shape check → one loop, or a planned path (§5, references/pipeline.md)
├─ Context loading (a parallel layer: staleness, sources, KB — §13)
├─ History trimming, then context budget allocation
├─ System prompt built from the live capabilities (§10)
└─ Execute:
├─ SIMPLE: LLM → tools → sub-agents → results → LLM → … → answer (§2)
└─ PLANNED: plan → dependency layers → checker → checkpoints → done (§5)
1. オーケストレーターパターン
共有コンテキストオブジェクト
単一の、ほぼ不変なコンテキストオブジェクトを各サブエージェントに渡します。このオブジェクトには、リクエスト(project_id、user_question、chat_history)、仕組み(llm_router、tracker、workflow_id)、解決済みのプロバイダーとモデル、パイプラインのフラグを格納する extra 辞書が含まれます。データクラス全体は references/patterns.md → オーケストレーターの共有コンテキストとサブエージェントプロトコル にあります。
主な原則:
- サブエージェントはコンテキストを変更せず、型付きの結果を返します
- プロバイダー/モデルの設定は、ユーザー → プロジェクトのデフォルト → アプリのデフォルトの順に引き継がれます
extra辞書にはパイプラインの状態や、_skip_complexityなどのフラグ、セッション ID が格納されます
サブエージェントプロトコル
各サブエージェントは、単一の抽象メソッド run(context) -> Result を持つ基底クラスを継承します。そのため、オーケストレーターは各サブエージェントの内部処理を知る必要がありません。クラスは同じリファレンスのセクションにあります。
エージェントごとに型付きの結果サブクラスを用意します(例:query、results、attempts を持つ SQLAgentResult)。
2. ツール呼び出しループ(シンプルな経路)
このループは 6 つのステップで構成され、どれも欠かせません。
- まずコンテキストの逼迫に対処します — 呼び出しを消費する前に、トリミングし、ウィンドウがほぼいっぱいならまとめの指示を挿入します。
- ツールを付けて、再試行付きでモデルを呼び出します。
- ツール呼び出しがなければ、それが回答です — これがループの唯一の正常終了条件です。
- ツール呼び出しを含むアシスタントのターンを、編集せずに追加します。
- ディスパッチします — 独立したツールには
asyncio.gatherを使い、状態を持つツールは順次実行します。 - すべての結果を
tool_call_idにひも付けて追加し、反復します。
for の else がガードになります。反復回数を使い切った場合は何も返さずに終わるのではなく、収集済みの情報からベストエフォートの回答を作成します。全体のコードは references/patterns.md → ツール呼び出しループの全体像 にあります。
重要な詳細:
- 並列ツールディスパッチ:独立したツールには
asyncio.gatherを使い、状態を持つツール(先行するクエリ結果に依存するデータ処理など)は順次実行します - まとめの指示の挿入:コンテキスト容量が約 70% に達したら、ツール呼び出しを止めて最終回答を出すよう LLM に伝えるシステムメッセージを挿入します
- ループ内のトリミング:容量が約 80% に達したら、古いアシスタントとツールのやり取りを一行の要約にまとめます
- トークン上限からの復旧:
LLMTokenLimitErrorが発生したら、60% に圧縮して一度再試行します。それでも失敗した場合は部分的な回答を返します - 最大反復回数のガード:必ず厳格な上限を設けます。上限に達したら、収集済みのデータからベストエフォートの回答を作成します
- 反復回数の返却:復旧可能なプロバイダーエラーはこのガードの回数に加算しません。ただし費用は発生するため、成功時の経路だけで計上すると、最悪の実行における費用を過少評価します
- 予算の把握:残りの予算をモデルに伝えます。そうしないと、300 ステップでも 30 ステップと同じように動作してしまいます
3. メタツール(オーケストレーター層)
オーケストレーターのツールは、実行するのではなく、サブエージェントに委譲します。
query_database は自然言語の質問を受け取り、その背後にいる SQL エージェントが生成、検証、実行を担当します。パラメーターは 1 つで、責務も 1 つです。呼び出し側がサブエージェントの存在を知ることはありません。
def get_tools(*, has_db=False, has_kb=False, has_mcp=False) -> list[Tool]:
"""Assembled per request from the same capability flags that build the prompt (§10)."""
tools = []
if has_db: tools.extend([QUERY_DB, PROCESS_DATA, MANAGE_RULES, ASK_USER])
if has_kb: tools.append(SEARCH_CODEBASE)
if has_mcp: tools.append(QUERY_MCP)
return tools
この層に属し、プロンプトには属さないルールが 2 つあります。リクエストにない機能はツールを追加しないこと、そしてツールが受け付けるすべての列挙型をスキーマで閉じることです(ask_user の question_type は yes_no | multiple_choice | free_text であり、自由形式の文章は受け付けません)。モデルが適切なツールを選ぶようにツールを説明する方法、つまり使用する場面を示す文と、混同されやすい隣接ツールについては、agent-harness/references/tools.md を参照してください。
4. サブエージェントの再試行と検証
すべてのサブエージェント呼び出しを再試行と検証で包み、両者を分けてください。例外を投げた呼び出しと、使用できない内容を返した呼び出しには、それぞれ異なる対処が必要です。前者は再試行し、後者は再プロンプトするか失敗として処理します。
以降の方針を決めるのは、次の点です。
- エラーは呼び出し箇所ではなく、型の段階で再試行可能と致命的なものに分けます。 不正な認証情報とプロバイダーの過負荷はどちらも例外ですが、再試行する価値があるのは一方だけです。
- 結果がユーザーに届く前に、呼び出し側が期待する形式に照らして検証します。 行が含まれているか、列に名前が付いているか、引用が添付されているかを確認してください。例外の有無だけを見るチェックでは、自信に満ちた誤答も通過してしまいます。
- 試行回数を制限し、最善の部分的な結果を返します。 部分的な回答に代わるものは、より良い回答ではなく、予算を使い切ったうえで回答が得られないことだからです。
- 制限による停止は、待機ではありません。 独立した作業を続け、停止したワーカーを限定的かつ許可された形で再開できるよう手配してください。沈黙のすべてが停滞を意味するわけではありません。プロバイダーのタイミング、試行回数と期限の予算、不確かな効果からの復旧を維持してください。使用量と請求額の制限は、引き続き人が判断します。仕組みと実行許可については、
references/runtime.md→ 制限による停止は待機ではありません を参照してください。
階層、ループ、ドメインごとのバリデーターについては、
references/patterns.md を参照してください。
5. 多段階パイプライン(複雑な経路)
1 つのループでは対応できない場合、たとえば相互に依存する複数のデータ処理段階がある場合、途中で人の承認が必要な場合、2 つのメッセージの間の中断を越えて実行を継続する必要がある場合、オーケストレーターはまず計画を立て、ツールではなくステージを実行します。
ここで決めることは 3 つです。仕組みについては
references/pipeline.md を参照してください。
- 複雑さは 2 段階で検出し、まずは低コストの方法を使います。 キーワードのヒューリスティックを使い、その判定が不確かな場合に限って小規模なモデル呼び出しを行います。すべての質問の分類にモデルを使うのは、一般的なケースにかかるコストです。
- 実行はリストの順番ではなく、依存関係の層ごとに行います(§13)。
depends_onを宣言した計画をリストの上から順に処理するのでは、直列化してしまいます。ステージが 2 つ以上ある層では、どれかを消費する前にチェックを行います。 - チェックポイントは、ワーカーを解放する一時停止です。 人を待つためにプロセスを維持する必要があると、時間のかかる承認がいつの間にか設計から外されてしまいます。こうして、ヒューマン・イン・ザ・ループのシステムから人の関与が失われます。
6. LLM プロバイダーのルーティング
プロバイダーの前段にルーターを置き、アプリの前段にはプロバイダークライアントを置きません。 順番に試し、失敗したら次へ進み、呼び出し元からどのベンダーが応答したのか分からないよう、単一のエラー階層を上位に返します。
フォールバックチェーンと、指数バックオフによるプロバイダーごとの再試行については
references/llm-proxy-billing.md → モデルのルーティングとフォールバックを、
予算、ループ検出、自動一時停止については同ファイルの
ガードレールセクションを参照してください。
実際にコストを招く3つの落とし穴:
- 再試行ループとフォールバックチェーンは呼び出し回数を掛け合わせます。 プロバイダーが3つあり、それぞれ3回再試行すると、1つのプロンプトに対して9回呼び出すことになります。プロバイダーごとの回数ではなく、試行の総数に上限を設けてください。
- 失敗時にしか実行されないヘルスチェックでは復旧できません。 異常と判定されたプロバイダーには定期的なプローブが必要です。そうしないと、チェーンからそのプロバイダーが永久に1つ欠けたままになり、リクエスト自体は成功するため、誰も気づきません。
- モデル選択には、リクエスト、テナント、システムのデフォルトという3つの階層があります。 リクエストパラメーターによってテナントの上書き設定がひそかに無効になると、低価格モデルを使うはずが、プレミアムモデルの料金で請求されることになります。
- この3つの前提はリクエストが移行可能であることですが、軌跡はそうではありません。 推論にはベンダーの認証情報が含まれることがあり、ツール呼び出しに含まれる場合もあるため、ターンの途中でフェイルオーバーすると400エラーになることがあります。その原因となるのが、推論をすべて取り除くことです。フェイルオーバーはターン間で行ってください。
- 能力が均等に消費されるわけではありません。 ボトルネックはプランナーなので、最も高性能なモデルはマネージャーに割り当ててください。最も多く作業するエージェントに割り当てるのではありません。
7. 多層メモリシステム
4つのレイヤーがあり、それぞれ存続期間と存在理由が異なります。
| レイヤー | スコープ | 存続期間 | 格納内容 |
|---|---|---|---|
| 1 チャット履歴 | セッションごと | 数分 | トークン予算に合わせて調整された会話のターン |
| 2 作業メモリ | リソースごと | 数日 | これまでにタスクで明らかになったこと |
| 3 長期的な学び | リソースごと | 数か月 | うまくいったことと、その信頼度スコア |
| 4 インサイト | プロジェクトごと | 永続 | リソースの存続期間を超えて残った結論 |
レイヤー3と4に何を格納するかは、references/patterns.md の信頼度管理、
学習抽出のヒューリスティクス、ファジー重複排除、競合解決で決まります。
これら4つは存続期間の分類であり、分類体系そのものではありません。 レイヤー3と4は 経験に基づくものであり、ここには事実を格納する場所がありません。古くなったユーザーに関する事実は エージェントを無礼にし、環境に関する事実はエージェントを誤らせます。ここでは取得処理も説明されていませんが、 取得には4つの判断が必要です。その最初の判断、つまりそもそも取得するかどうかでさえ、エラーログに残らないまま、 何も根拠がないのに確信に満ちた回答を生成する失敗につながります。
この表ではなく、
references/memory-architecture.mdを基にメモリレイヤーを
設計してください。同ファイルでは、コンテキスト予算の落とし穴、レイヤー0の引き継ぎ、ワークスペースの規模も扱っています。
書き込み経路と、独自に構築するか既存のものを採用するかという問題については、以下のインデックスにそれぞれ項目があります。
8. 自己学習フィードバックループ
メモリレイヤーには3つのサイクルが情報を提供します。それぞれ、シグナルの元が異なります。修正された失敗、 ユーザーの評価、そして時間です。
このセクション全体の根幹となるルール: 学習内容は、対比から書き出します。失敗した試行と成功した試行を並べ、 単一の成功した実行から書き出すことはありません。成功だけから学習するシステムは、自らの習慣を学習します。
抽出器、信頼度の計算、昇格クエリについては、
references/patterns.mdを参照してください。
9. 可観測性
単一のバスに各ステップのイベントを流し、回答も同じバスでチャンクとしてストリーミングします。
これがフィードなのか単なる飾りなのかを決める特性は2つあります。すべてのイベントが単調増加するIDを持つため、
再接続したクライアントは実行を見逃さずに再開できること。そしてフィードが永続化されたトレースのビューであり、
記録そのものではないことです。保存されなかったストリームは、agent-evalsで評価できる実行ではありません。
トラッカーの形式については、
references/runtime.mdを参照してください。
10. 動的システムプロンプト
実際に利用可能な機能からプロンプトを組み立てます。ツール(§3)を組み立てるのと同じ処理で、利用可能な各機能を示すセクション、存在する場合はリソースマップ、現在の学び、ガイドラインの順にまとめます。エージェントに与えられていないツールについてプロンプトに記述すると、モデルは存在しないものを呼び出すためにターンを費やすことになります。
どの内容をどの粒度で記述するか、そしてエージェントがステータス値を勝手に作り出さなくなるよう語彙をどう列挙するかについては、agent-harness スキルの agent-harness/references/system-prompt.md を参照してください。ここにあるべき情報はそこに集約されており、このドキュメントでは扱いません。このスキルが扱うのは、その配線です。プロンプトは、ツール一覧の構築元と同じ機能フラグからリクエストごとに再構築されるため、両者が食い違うことはありません。再構築が無料なのは、バイト単位で同一である場合だけです。セッション中に機能が変わった場合は、プレフィックスを書き換えずに変更を追記します。境界より前を編集すると何が起きるかについては、references/kv-cache.md を参照してください。
11. 確認のリクエスト(ask_user)
質問するために停止することは、呼び出し元が異なるだけで、チェックポイントと同じ中断・再開の仕組みです。契約は一つであり、二つではありません(references/pipeline.md)。
12. コンテキストエンジニアリング
コンパクションは一度の呼び出しではなく、段階的に行います。 古いツール結果を消去し、大きすぎるブロックを折りたたみ、メッセージを簡潔にし、それから要約のコストをかけます。各段階の間で再計測してください。ほとんどの場合、最初の呼び出しを行う前にコンテキストの逼迫は解消します。
tool_use を孤立させないでください。 切り詰める位置は必ず assistant と tool のペアの間にします。そうしないと、次のリクエストがタスクの途中で 400 エラーになります。
境界を越えて状態を引き継ぐときは、文章ではなく型付きブロックを使います。目標、成果物、検証済みの作業、制限モードを含めます。要約器は議論を残して状態を落とし、「何も書き込まない」よう指示していたフラグまで失うことがあります。
大きなツール結果はファイルに退避し、パスを保持します。 履歴を削っても、すでに一つのツール出力で埋まったウィンドウを空けることはできません。
サブエージェントの価値は、独自のウィンドウにあります。返すのは文字起こしではなく、型付きの要約です。
13. 作業をグラフとして捉える
ループ、パイプライン、サブエージェントの前に、形を決めましょう。 ノードは作業の単位であり、エッジは依存関係で、エッジはデータを運びます。完全なモデル、その出典、このホストが実際に実行する内容については、
references/graph-engineering.md を参照してください。
コードを変えるのは、次の4つのルールです。
- 各エッジをデータ、制御、認可、リソースのいずれかに分類します。 引き継いだあらゆるチェーンで疑似エッジテストを実施し、4つのいずれも運ばない場合に限って矢印を削除します。ペイロードも、因果関係の制約も、権限も、共有リソースもない場合です。backup→migration、approval→charge、lease→edit はバイトを運びませんが、実際のエッジです。単に誰かが入力した順序だけを表す矢印は、通常、このテストでワークフローごとに2つか3つ見つかります。ファンアウトの前に読み書きセットを比較します。読み取り専用の分岐は並列化でき、同じものに対する2つの書き込みはリソースエッジでした。
depends_onは主張なので、レイヤー単位で実行します。 §5 のエグゼキューターは、依存関係を宣言するモデルがあるにもかかわらず、plan.stagesをリスト順に処理していました。せっかく実行不要と宣言したプランを、順次実行してしまいます。グラフに対して Kahn のアルゴリズムを適用します。サイクルがあれば、実行がデッドロックするのではなく、プランを失敗させます。- 並列レイヤーでは、収束の前にチェッカーが必要です。 3つの分岐が実行され、そのうち1つが幻覚を返しても、合成ノードにはそれを見抜けません。3つすべてを組み合わせ、自信満々に回答します。チェッカーが判定するのは 利用可能/利用不可 だけで、それ以外は判定しません。収束ノードが依存するのはチェッカーであり、分岐に直接依存してはいけません。
- 動的にする理由を明示できない限り、静的にします――監査可能性ではなく、予測可能性のためです。実行記録(実行したノード/エッジ/イベント、ポリシーのバージョン、決定論的な予算/深さ/ノード数の上限、来歴)を保存すれば、実行は監査可能です。その記録を保持する動的グラフも監査可能です。設計図だけでは証拠になりません。描かれた形が、実行された形とは限らないのです。
チェックリスト — 新しいオーケストレーターの構築
上の各セクションが全体像です。見出しからは読み取れない項目、つまり、間違いから学んだ項目を以下にまとめます。
- ウィンドウの約80%でループ内のトリミングを行い、約70%で終了処理を注入し、最大反復回数のガードでは何も返さずに終わるのではなく、部分的な回答をまとめる
- 回復可能なプロバイダーエラーでは反復回数を返還します。設定ミスによって、暴走を止めるための予算を消費してはいけません
- 再試行とフォールバックには合計の上限を設けます。プロバイダー3つ × 再試行3回は、1つのプロンプトに対して9回の呼び出しになります
- 不健全と判定されたプロバイダーは、スケジュールに従ってプローブします。障害時にしか実行されないヘルスチェックでは復旧せず、誰にも気づかれないままチェーンが短くなります
- チャット履歴には下限を設けます。過去の学びを残すために履歴を切り詰めるセッションは、ユーザーが1分前に言ったことより一般論を優先しています
- 宣言されたすべての依存関係で、運ばれるデータを明示します。プランはレイヤー単位で実行し、複数のノードを含むレイヤーでは、何かが利用する前にチェッカーを通します(§13)
- 意図的に仕込んだ不正な入力をチェッカーが拒否するのを確認し、その判定をスコアとして保存します。一度も拒否したことのないチェッカーは、それ自体が発見事項です
- サブエージェントはトランスクリプトではなく、要約した概要を返します。入力に比例する戻り値は、仮装した関数呼び出しです
- モデル、ウィンドウ、価格は、設定またはプロバイダーから1つの境界で解決します。ソース内のベンダー ID のテーブルから解決してはいけません
- 実装前に観測可能性を確保し、プロンプト調整前に評価を行います。そうしなければ、調整は言い伝えになります。本番環境まで待つのはコーパスだけです
- 人々に回答するエージェントは、
agent-evals/references/support-quality.mdに従って測定します。記録、メトリクス、ルーブリック、評価者、日次イベントを用意します
リファレンス
各ファイルの冒頭には、それぞれ 次の場合に読み込む という行があります。正式なトリガーはその行に記載されています。この表は索引にすぎません。
| ファイル | 読むタイミング |
|---|---|
references/graph-engineering.md | 作業の形を決めるとき — 偽のエッジ、ダイヤモンド、チェッカーノード、静的か動的か |
references/pipeline.md | 1つのループでは形が合わないとき — 計画された経路、そのチェックポイント、再開、人に確認を求める割り込み |
references/patterns.md | 本体を支えるデータモデルとアルゴリズムが必要なとき |
references/memory-architecture.md | エージェントにメモリを与えるとき、またはメモリが正常に機能しないとき |
references/memory-lifecycle.md | メモリの書き込み経路 — 何が入り、何が出るか |
references/memory-landscape.md | メモリレイヤーを構築するか採用するか、また確立された実践を知りたいとき |
references/context-engineering.md | ループのコンテキストウィンドウが不足しそうなとき |
references/kv-cache.md | リクエスト内の配置を決めるとき — 軌跡に対する静的プレフィックス、キャッシュミスのコスト、境界の前に置かれた実行時条件が生み出す2^N通りのキャッシュ構成、名前の挙がっている無効化要因、そしてキャッシュを無駄に消費するよくある4つの最適化 |
references/runtime.md | エージェントにクラッシュ、一時停止、2通目のメッセージ、スケジュール、または使用制限による停止を乗り越えさせる必要があるとき |
references/governance.md | 問題がコストではなく権限に関するもの — 何が許可され、どう証明するか。インシデントのチェックリスト(DNSの外向き通信、シークレットの分離、要約へのインジェクション、外部への影響、発見された認証情報、公開されたDocker API) |
references/llm-proxy-billing.md | 製品がLLMアクセスを再販するとき |
references/provider-lifecycle.md | 問題がループではなくワークフォースに関するもの — プロバイダーのライフサイクル、カナリアの信頼性、フリートの予算 |