Claude Platform Docs
Managed Agents高级编排

多智能体编排

在单个会话中协调多个智能体。

"Multiagent orchestration"(多智能体编排)让一个智能体能够与其他智能体协作完成复杂的工作。各智能体可以在各自隔离的上下文中并行运行,这有助于提升输出质量,也可以缩短完成时间。

不确定多智能体方案是否适合您的问题?请参阅何时使用多智能体系统(以及何时不使用)

工作原理

所有智能体共享同一个沙箱、文件系统和 vault 凭证,但每个智能体都在自己的 session thread(会话线程)中运行,这是一个上下文隔离的事件流,拥有自己的对话历史。协调者在 primary thread(主线程)中报告活动(主线程与会话级事件流相同);当协调者委派工作时,会在运行时生成额外的线程。

线程是持久的:协调者可以向之前调用过的智能体发送后续消息,而该智能体会保留其先前所有轮次的内容。

每个智能体使用自己的配置:模型、系统提示、工具、MCP 服务器和技能。会话级智能体配置覆盖是例外;它们适用于协调者及其 self 副本。工具、MCP 服务器和上下文不共享。

委派什么

多智能体协调最适合复杂任务,这类任务要么需要跨多种界面开展工作,要么由多个范围明确的子任务共同服务于一个总体目标。

效果良好的模式:

  • 并行化: 同时分发相互独立的子任务(搜索多个来源、分析不同的文件),并由协调者综合结果。
  • 专业化: 将任务路由到具有领域专注型系统提示和工具的智能体,例如安全智能体或文档智能体,而不是让单个智能体承载所有能力。
  • 升级: 针对一部分复杂子任务,咨询能力更强的智能体或模型。

配置协调者

定义您的智能体时,设置 multiagent 以声明协调者可以委派的智能体名册:

ant beta:agents create < coordinator.agent.yaml
coordinator.agent.yaml
name: Engineering Lead
model: claude-opus-5
system: You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.
tools:
  - type: agent_toolset_20260401
multiagent:
  type: coordinator
  agents:
    - type: agent
      id: $REVIEWER_AGENT_ID # replace before running command
    - type: agent
      id: $TEST_WRITER_AGENT_ID # replace before running command

multiagent.agents 可以接受以下任意形式:

  • {"type": "agent", "id": agent.id} 通过 ID 引用先前创建的 agent。如果未指定 version,该引用会固定到创建协调者时该智能体的最新版本。
  • {"type": "agent", "id": agent.id, "version": agent.version} 固定到特定的智能体版本。
  • {"type": "self"} 允许协调者生成自身的副本。如果会话是使用智能体配置覆盖创建的,这些覆盖也适用于这些副本;通过 ID 引用的名册条目不受影响。
  • {"type": "advisor", "model": "<model id>"} 为会话的主线程提供一个可在轮次中途咨询的顾问。每个名册最多一个顾问条目。请参阅为会话配置顾问

协调者的配置(包括其 multiagent.agents 名册)会在协调者创建或更新时生成快照。被引用的智能体会固定在当时解析出的版本,不会自动获取其定义的后续更新。若要委派给被引用智能体的较新版本,请更新协调者,使其名册引用该版本。

协调者只能委派给一层智能体;引用一个自身拥有 multiagent.agents 名册的智能体会导致创建或更新请求因验证错误而失败。multiagent.agents 中最多可列出 20 个不同的智能体,但协调者可以调用每个智能体的多个副本。

当智能体固定了推理地理位置智能体定义中的 model.inference_geo)时,协调者的固定值与每个名册成员的固定值必须全部设置为相同的值,或者全部不设置。不匹配的名册会被拒绝并返回 400 验证错误,无论是在保存智能体时,还是在会话创建覆盖更改了任何固定值时。

为会话配置顾问

multiagent.agents 中的顾问条目为会话的主线程提供一个 advisor(顾问):一个可在轮次中途咨询以获取战略指导的模型,例如规划方法、摆脱困境或在完成前审查工作。该条目恰好有两个字段,typemodel

cURL
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"}
      ]
    }
  }'

一个名册最多可以包含一个顾问条目,可与其他任意名册形式并存。该条目占用保留的名册名称 anthropic.advisor:如果名册同时列出了顾问条目和一个字面名称为 anthropic.advisor 的成员,则会被拒绝并返回 400 验证错误。在响应中,无论提交时位于何处,顾问条目都会在名册中最后回显。

顾问模型必须满足最低能力门槛,且智能体自身的模型不得比其顾问能力更强;能力相同的模型可以配对。无效的配对会在保存智能体时被拒绝并返回 400 验证错误。有效配对遵循顾问工具的模型兼容性表。

顾问也可作为 Messages API 上的服务器工具使用。Managed Agents 界面在配置和交付方式上有所不同:名册条目没有 max_usesmax_tokenscaching 字段,且建议通过线程事件送达,而非 advisor_tool_result 块。

咨询如何运作

每次咨询都作为一个由平台生成、名为 anthropic.advisor 的线程运行,该线程在咨询完成时自行终止,建议则以 agent.thread_message_received 事件的形式送达主线程。一次咨询会发出标准的线程事件,以保留名称 anthropic.advisor 标识(线程生命周期事件将其作为 agent_name 携带,建议送达事件将其作为 from_agent_name 携带),通常按以下顺序:

  1. session.thread_created
  2. session.thread_status_running
  3. agent.thread_message_received(建议)
  4. session.thread_status_idlestop_reason: end_turn
  5. 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_iduser.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 适用于每个线程)。这对您的集成有两点影响:

  • 要对 MCP 服务器进行身份验证,请为所有智能体使用的每个 MCP 服务器都包含一个 vault 凭证。
  • 要限制某个智能体的访问权限,请仅在其智能体定义中声明它所需的服务器。

创建会话时的智能体配置覆盖可以替换协调者及其 self 副本的 MCP 服务器。

research_agent = client.beta.agents.create(
    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"}],
)

coordinator = client.beta.agents.create(
    name="coordinator",
    model="claude-opus-5",
    tools=[{"type": "agent_toolset_20260401"}],
    multiagent={
        "type": "coordinator",
        "agents": [{"type": "agent", "id": research_agent.id}],
    },
)

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 是所有智能体活动的聚合;如果至少有一个线程处于 running,则整个会话状态也为 running

会话预算是会话所有线程共享的单一上限。达到上限时,各线程独立暂停,每个线程的成本按该线程自身所用的模型定价。

按如下方式列出与会话关联的所有线程:

for thread in client.beta.sessions.threads.list(session.id):
    print(f"[{thread.agent.name}] {thread.status}")

完整列表包含主线程。主线程的 parent_thread_id 为 null。

主线程事件

这些事件在 /v1/sessions/{session_id}/events/stream 的主线程上呈现多智能体活动。消息方向类事件的命名是相对于它们所出现的线程流而言的:agent.thread_message_received 表示有一条消息从另一个线程到达此线程,agent.thread_message_sent 表示此线程发送了一条消息。例如,协调者委派的任务会以 agent.thread_message_received 事件的形式到达子线程自己的流。

类型描述
session.thread_created创建了一个线程。包含 session_thread_idagent_name
session.thread_status_running一个线程开始活动。
session.thread_status_idle与该线程关联的智能体正在等待输入。包含一个 stop_reason,指示智能体停止的原因。
session.thread_status_terminated一个线程已被归档或遇到终止性错误。
agent.thread_message_received在主线程上,某个智能体向协调者发送了报告或问题。包含 from_session_thread_idfrom_agent_namecontent
agent.thread_message_sent在主线程上,协调者向另一个智能体发送了任务或后续消息。包含 to_session_thread_idto_agent_namecontent

顾问咨询会以保留名称 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

工具权限和自定义工具

如果子智能体需要您的客户端提供某些内容,例如运行 always_ask 工具的权限,或自定义工具的结果,该事件会被交叉发布到主线程,并通过 session_thread_id 标识发起的会话线程。

{
  "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);服务器会自动将响应路由到正确的线程。

以下示例扩展了工具确认处理程序以路由回复。同样的模式也适用于 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?