マルチエージェントオーケストレーション
単一のセッション内で複数のエージェントを連携させます。
「multiagent orchestration」(マルチエージェントオーケストレーション)により、1つのエージェントが他のエージェントと連携して複雑な作業を完了できます。エージェントはそれぞれ独立したコンテキストを持って並列に動作できるため、出力品質の向上に役立ち、完了までの時間も短縮できる場合があります。
マルチエージェント構成が自分の課題に適しているかわからない場合は、マルチエージェントシステムを使うべきとき(と使うべきでないとき)を参照してください。
仕組み
すべてのエージェントは同じサンドボックス、ファイルシステム、およびvault認証情報を共有しますが、各エージェントはそれぞれ独自のセッションスレッド(独自の会話履歴を持つ、コンテキストが分離されたイベントストリーム)で実行されます。コーディネーターはプライマリスレッド(セッションレベルのイベントストリームと同じもの)でアクティビティを報告します。追加のスレッドは、コーディネーターが作業を委任する際に実行時に生成されます。
スレッドは永続的です。コーディネーターは以前に呼び出したエージェントにフォローアップを送信でき、そのエージェントは以前のターンの内容をすべて保持しています。
各エージェントは独自の設定(モデル、システムプロンプト、ツール、MCPサーバー、スキル)を使用します。セッションレベルのエージェント設定のオーバーライドは例外で、コーディネーターとそのselfコピーに適用されます。ツール、MCPサーバー、コンテキストは共有されません。
何を委任するか
マルチエージェント連携は、さまざまな領域にまたがる作業を必要とする複雑なタスク、または適切にスコープが定められた複数のタスクが全体の目標に貢献するような複雑なタスクに最適です。
うまく機能するパターン:
- 並列化: 独立したサブタスク(複数のソースの検索、別々のファイルの分析など)を同時に展開し、コーディネーターに結果を統合させます。
- 専門化: あらゆる機能を単一のエージェントに詰め込むのではなく、セキュリティエージェントやドキュメントエージェントなど、ドメインに特化したシステムプロンプトとツールを持つエージェントにルーティングします。
- エスカレーション: 複雑なサブタスクの一部について、より高性能なエージェントやモデルに相談します。
コーディネーターを設定する
エージェントを定義する際に、multiagentを設定して、コーディネーターが委任できるエージェントの名簿(roster)を宣言します。
ant apply engineering-lead.md reviewer.md test-writer.md---
name: Engineering Lead
model: claude-opus-5-5
tools:
- type: agent_toolset_20260401
multiagent:
type: coordinator
agents: # paths: ant apply substitutes {type: agent, id, version}
- ./reviewer.md
- ./test-writer.md
---
You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.---
name: reviewer
model: claude-haiku-4-5
---
You are a code reviewer.---
name: test-writer
model: claude-haiku-4-5
---
You write unit tests.multiagent.agentsには以下のいずれかを指定できます:
{"type": "agent", "id": agent.id}は、以前に作成したagentをIDで参照します。versionが指定されていない場合、参照はコーディネーター作成時点でのそのエージェントの最新バージョンに固定されます。{"type": "agent", "id": agent.id, "version": agent.version}は、特定のエージェントバージョンに固定します。{"type": "self"}は、コーディネーターが自身のコピーを生成できるようにします。セッションがエージェント設定のオーバーライド付きで作成された場合、それらのオーバーライドはこれらのコピーにも適用されます。IDで参照される名簿エントリは影響を受けません。{"type": "advisor", "model": "は、セッションのプライマリスレッドに、ターンの途中で相談できるアドバイザーを与えます。名簿ごとにアドバイザーエントリは最大1つです。セッションにアドバイザーを与えるを参照してください。"}
ant applyのエージェントファイル(CLIタブ)では、ロスターエントリとして./reviewer.mdのような別のエージェントのファイルへのパスを指定することもできます。applyはまずそのエージェントを作成し、パスを固定された{"type": "agent", "id": ..., "version": ...}参照に置き換えます。
コーディネーターの設定(multiagent.agents名簿を含む)は、コーディネーターの作成時または更新時にスナップショットされます。参照されるエージェントはその時点で解決されたバージョンに固定されたままとなり、その後の定義の更新を自動的に取り込むことはありません。参照されるエージェントの新しいバージョンに委任するには、名簿がそのバージョンを参照するようにコーディネーターを更新してください。
コーディネーターが委任できるのは1階層のエージェントのみです。独自のmultiagent.agents名簿を持つエージェントを参照すると、作成または更新リクエストはバリデーションエラーで失敗します。multiagent.agentsには最大20個の一意のエージェントを列挙できますが、コーディネーターは各エージェントの複数のコピーを呼び出すことができます。
エージェントが推論地域(エージェント定義のmodel.inference_geo)を固定している場合、コーディネーターの固定値とすべての名簿メンバーの固定値は、すべて同じ値に設定されているか、すべて未設定である必要があります。不一致のある名簿は、エージェントの保存時にも、セッション作成時のオーバーライドがいずれかの固定値を変更した場合にも、400バリデーションエラーで拒否されます。
セッションにアドバイザーを与える
multiagent.agents内のアドバイザーエントリは、セッションのプライマリスレッドにアドバイザーを与えます。アドバイザーとは、アプローチの計画、行き詰まりの解消、完了前の作業レビューなど、戦略的なガイダンスを得るためにターンの途中で相談できるモデルです。このエントリにはtypeとmodelのちょうど2つのフィールドがあります:
curl -fsS https://api.anthropic.com/v1/agents \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d '{
"name": "Backend engineer",
"model": "claude-sonnet-5",
"system": "You implement backend features end to end. Consult the advisor before major backend design decisions.",
"multiagent": {
"type": "coordinator",
"agents": [
{"type": "advisor", "model": "claude-opus-5-5"}
]
}
}'名簿には、他の名簿形式のエントリと並んで、アドバイザーエントリを最大1つ含めることができます。このエントリは予約済みの名簿名anthropic.advisorを占有します。アドバイザーエントリと、文字どおりanthropic.advisorという名前のメンバーの両方を列挙した名簿は、400バリデーションエラーで拒否されます。レスポンスでは、アドバイザーエントリは送信時の位置に関係なく、名簿の最後にエコーされます。
アドバイザーモデルは最低限の能力基準を満たす必要があり、エージェント自身のモデルはそのアドバイザーより高性能であってはなりません。同等の能力のモデル同士は組み合わせることができます。無効な組み合わせは、エージェントの保存時に400バリデーションエラーで拒否されます。有効な組み合わせは、アドバイザーツールのモデル互換性表に従います。
アドバイザーはMessages APIのサーバーツールとしても利用できます。Managed Agentsでは設定と配信方法が異なります。名簿エントリにはmax_uses、max_tokens、cachingフィールドがなく、アドバイスはadvisor_tool_resultブロックではなくスレッドイベントを通じて届きます。
相談の仕組み
各相談は、プラットフォームが生成するanthropic.advisorという名前のスレッドとして実行され、相談が完了すると自ら終了します。アドバイスはagent.thread_message_receivedイベントとしてプライマリスレッドに配信されます。相談は、予約名anthropic.advisorで識別される標準のスレッドイベントを発行します(スレッドのライフサイクルイベントではagent_nameとして、アドバイスの配信ではfrom_agent_nameとして保持されます)。通常は次の順序です:
session.thread_createdsession.thread_status_runningagent.thread_message_received(アドバイス)session.thread_status_idle(stop_reason: end_turn)session.thread_status_terminated
相談の入力はエージェントが送信するのではなくプラットフォームが構成するため、相談に対してagent.tool_useイベントは発行されず、セッションのイベントストリームにagent.thread_message_sentイベントも現れません。アドバイザースレッド自身のイベントを一覧表示すると、アドバイスはそこにもagent.thread_message_sentイベントとして現れます。アドバイスの配信(イベント3)がアドバイザースレッドのidleおよびterminatedイベントより前に届くことは保証されないため、それらをアドバイスがすでに配信されたことを示すシグナルとして扱わないでください。
クライアントがアドバイスを読めるかどうかはアドバイザーモデルのポリシーによって決まり、Messages APIのアドバイザーツールにおける結果のバリアントの区分を反映しています。そちらでプレーンテキストの結果を返すアドバイザーモデルは、こちらでは読み取り可能なテキストコンテンツとしてアドバイスを配信します。そちらで秘匿化された結果を返すアドバイザーモデルは、すべてのクライアント向けの場面でメッセージコンテンツとして[{"type": "redacted"}]プレースホルダーを配信しますが、エージェント自身はサーバー側で完全なアドバイスを読み取ります。前述の例では、Claude Opus 5は秘匿化結果のアドバイザーであるため、クライアントにはプレースホルダーが表示され、エージェントは完全なアドバイスを読み取ります。イベントストリーム上でアドバイスを読み取り可能にしたい場合は、代わりにClaude Opus 4.8をアドバイザーとして選択してください。アドバイザーの思考は決して表示されません。クライアント自身がredactedブロックを送信することはできず、それを含むイベントは400バリデーションエラーで拒否されます。
相談が失敗または中断されても、エージェントのターンが失敗することはありません。エージェントは、相談が失敗したという一般的な通知の後に続行します。相談中のセッションレベルのuser.interruptは、アドバイスを配信せずにアドバイザースレッドを終了させます。アドバイザースレッドのsession_thread_idを指定したuser.interruptは、その相談のみを破棄します。
アドバイザースレッド
アドバイザーは名簿エージェントではありません。コーディネーターのlist_agentsツールからは見えず、send_to_agentでメッセージを送ることもできず、相談できるのはセッションのプライマリスレッドのみです。名簿エージェントは相談できません。
アドバイザースレッドは同時スレッド数の制限から除外されます。セッションのスレッド一覧には、agentが設定どおりのアドバイザー形式({"type": "advisor", "model": ...})に、parent_thread_idがプライマリスレッドに設定された状態で表示されます。
アドバイザー側のプロンプトキャッシングは自動で行われ、設定するものは何もありません。相談はアドバイザーモデルの料金で課金され、そのトークンはアドバイザースレッドの使用量とセッションの使用量合計に表示されます。
アドバイザーを削除する
アドバイザーを削除するには、アドバイザーエントリを含まない名簿でエージェントを更新します。アドバイザーが名簿の唯一のエントリである場合は、"multiagent": nullを設定して名簿全体をクリアしてください。
セッションを作成する
コーディネーターを参照するセッションを作成します。コーディネーターは必要に応じて名簿内のエージェントに委任します。
session = client.beta.sessions.create(
agent=coordinator.id,
environment_id=environment.id,
)エージェントをMCPサーバーに接続する
MCPサーバーはエージェントスコープ(各エージェント定義が独自のサーバーとツールを宣言する)である一方、vault認証情報はセッションスコープ(セッション作成時に渡されるvault_idsがすべてのスレッドに適用される)です。インテグレーションにとっての2つの意味合い:
- MCPサーバーを認証するには、すべてのエージェントで使用されるすべてのMCPサーバーについてvault認証情報を含めてください。
- エージェントのアクセスを制限するには、そのエージェント定義で必要なサーバーのみを宣言してください。
セッション作成時のエージェント設定のオーバーライドにより、コーディネーターおよびそのselfコピーのMCPサーバーを置き換えることができます。
limited の環境では、コーディネーター、またはコーディネーターが委任できるエージェントが、ホストが allowed_hosts に含まれていないMCPサーバーを宣言している場合、セッション作成は400エラーで失敗します。環境のネットワーク設定で allow_mcp_servers: true を設定すると、このチェックは無効になります。
GitHub MCPサーバーを宣言するリサーチャーと、リサーチャーに委任するコーディネーターを作成します:
ant apply coordinator.md researcher.md---
name: coordinator
model: claude-opus-5-5
tools:
- type: agent_toolset_20260401
multiagent:
type: coordinator
agents: # path: ant apply substitutes {type: agent, id, version}
- ./researcher.md
------
name: researcher
model: claude-haiku-4-5
mcp_servers:
- type: url
name: github
url: https://api.githubcopilot.com/mcp/
tools:
- type: mcp_toolset
mcp_server_name: github
---次に、GitHub認証情報を保持するvaultを使用してセッションを作成します:
session = client.beta.sessions.create(
agent=coordinator.id,
environment_id=environment.id,
vault_ids=[vault.id],
)
print(session.id)この例では、researcherのみがGitHub MCPサーバーを宣言しているため、コーディネーターにはアクセス権がありません。セッションのvault_idsがresearcherのスレッドにGitHub認証情報を提供します。
スレッド
セッションレベルのイベントストリーム(/v1/sessions/{session_id}/events/stream)はプライマリスレッドとみなされ、すべてのスレッドにわたるすべてのアクティビティの要約ビューを含みます。サブエージェントのアクティビティ全体は表示されませんが、その作業の開始と終了、およびツール権限リクエストなどのブロッキングイベントは表示されます。
セッションスレッドは、特定のエージェントのアクティビティを詳しく調べる場所です。
セッションのstatusはすべてのエージェントアクティビティの集約です。少なくとも1つのスレッドがrunningであれば、セッション全体のステータスもrunningになります。
セッション予算は、セッションのすべてのスレッドにわたる単一の共有上限です。上限に達すると、スレッドはそれぞれ独立して一時停止し、各スレッドのコストはそのスレッド自身が提供されたモデルの料金で計算されます。
セッションに関連付けられたすべてのスレッドを次のように一覧表示します:
for thread in client.beta.sessions.threads.list(session.id):
print(f"[{thread.agent.name}] {thread.status}")完全な一覧にはプライマリスレッドが含まれます。プライマリスレッドのparent_thread_idはnullです。
特定のスレッドを停止するには、session_thread_idを指定してuser.interruptを送信します。session_thread_idを省略すると、プライマリを含む、セッション内のアーカイブされていないすべてのスレッドが中断されます。
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
)requires_actionでブロックされている子スレッドに対しては、中断により保留中の各ツール呼び出しがエラーのツール結果("Tool execution was interrupted before completion. Please retry.")で閉じられ、stop_reason: end_turnを持つsession.thread_status_idleが直接再発行されます。モデルはサンプリングされません。すでにidleのスレッドに対しては、中断は何も行いません。
作業を完了したセッションスレッドは、任意でアーカイブできます。これにより、25スレッドの制限に対してスレッドが1つ解放されます。
archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
print(archived.status, archived.archived_at)アーカイブはスレッドがidleの場合にのみ成功します。requires_actionで待機中のスレッドはidleとみなされ、直接アーカイブできます。実行中のスレッドのみ、先に中断する必要があります:
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
)
archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
print(archived.status, archived.archived_at)プライマリスレッドのイベント
これらのイベントは、/v1/sessions/{session_id}/events/streamのプライマリスレッド上でマルチエージェントのアクティビティを表示します。メッセージ方向のイベントは、それが現れるストリームのスレッドを基準に命名されています。agent.thread_message_receivedは別のスレッドからこのスレッドにメッセージが届いたことを意味し、agent.thread_message_sentはこのスレッドがメッセージを送信したことを意味します。たとえば、コーディネーターが委任するタスクは、子スレッド自身のストリームにはagent.thread_message_receivedイベントとして届きます。
| タイプ | 説明 |
|---|---|
session.thread_created | スレッドが作成されました。session_thread_idとagent_nameを含みます。 |
session.thread_status_running | スレッドがアクティビティを開始しました。 |
session.thread_status_idle | スレッドに関連付けられたエージェントが入力を待っています。エージェントが停止した理由を示すstop_reasonを含みます。 |
session.thread_status_terminated | スレッドがアーカイブされたか、終端エラーが発生しました。 |
agent.thread_message_received | プライマリスレッド上で、エージェントがコーディネーターに報告または質問を送信しました。from_session_thread_id、from_agent_name、contentを含みます。 |
agent.thread_message_sent | プライマリスレッド上で、コーディネーターが別のエージェントにタスクまたはフォローアップメッセージを送信しました。to_session_thread_id、to_agent_name、contentを含みます。 |
アドバイザーの相談は、予約名anthropic.advisorの下でこれらと同じスレッドイベントを発行します(スレッドのライフサイクルイベントではagent_nameとして、アドバイスの配信ではfrom_agent_nameとして)。シーケンスについてはセッションにアドバイザーを与えるを参照してください。
セッションスレッドのイベント
重要なイベントはプライマリスレッドにプロキシされます。ただし、特定のエージェントの推論やツール呼び出しを調査したい場合もあるでしょう。そのためには、関連するセッションスレッドからイベントをストリーミングまたは一覧表示します。
各セッションスレッドは/v1/sessions/{session_id}/threads/{thread_id}/streamに独自のイベントストリームを持ち、セッションレベルのストリームと同じevent_deltas[]パラメータを受け付けるため、モデルが生成するサブエージェントのテキストをプレビューできます。接続がプレビューするのは読み取っているスレッドのみです。子スレッドのプレビューがセッションレベルのストリームに現れることはないため、サブエージェントをライブで監視するには、そのスレッド自身のストリームを開いてください。プレビューのオプトイン、蓄積、照合については、セッションスレッドイベントのプレビューを参照してください。
with client.beta.sessions.threads.events.stream(
thread.id,
session_id=session.id,
) as stream:
for event in stream:
match event.type:
case "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="")
case "session.thread_status_idle":
break過去のセッションスレッドイベントをすべて一覧表示して、完全な履歴を取得します。
for event in client.beta.sessions.threads.events.list(
thread.id,
session_id=session.id,
):
print(f"[{event.type}] {event.processed_at}")ツール権限とカスタムツール
ツール呼び出しを実行するための権限やカスタムツールの結果など、サブエージェントがクライアントからの何かを必要とする場合、そのイベントは発生元のセッションスレッドを識別するsession_thread_idとともにプライマリスレッドにも投稿されます。ツール呼び出しに権限が必要になるのは、always_askの場合、またはサーバーが判断を下せなかった場合のautoの場合です。
{
"type": "session.thread_status_idle",
"id": "sevt_01ABC...",
"session_thread_id": "sth_01DEF...",
"agent_name": "code-reviewer",
"stop_reason": {
"type": "requires_action",
"event_ids": ["sevt_01XYZ..."]
}
}user.tool_confirmation(tool_use_id付き)またはuser.custom_tool_result(custom_tool_use_id付き)を送信してください。サーバーがレスポンスを正しいスレッドに自動的にルーティングします。
autoでは、user.messageイベントによって、サーバーが本来拒否する呼び出しを許可する場合があります。サブエージェントのスレッド内のものは、あなたの意図としてはみなされません。クライアントはそこにメッセージを投稿せず、コーディネーターからサブエージェントへのメッセージもカウントされません。autoでサーバーが呼び出しを拒否した場合、何も転送されません。イベントとエラーのツール結果はサブエージェント自身のスレッドストリームにのみ表示され、サブエージェントは実行を続けます。
次の例は、ツール確認ハンドラーを拡張して返信をルーティングします。同じパターンがuser.custom_tool_resultにも適用されます。
for event_id in stop.event_ids:
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
}
],
)Was this page helpful?