深入 Claude Code 源码(六):多智能体——Coordinator 与 AgentTool 深度解析

单个 AI Agent 的局限是明显的:上下文窗口是固定的,一次只能处理有限量的信息;任务是串行的,做完一件事才能开始下一件;注意力是单一的,无法同时从多个角度分析同一个问题。

当任务足够复杂------比如同时重构多个模块、并行跑多条研究思路、让一个「策略层」和多个「执行层」分工合作------单个 Agent 就开始捉襟见肘了。

Claude Code 对这个问题的答案是:让多个 Claude 实例协同工作。具体有两种实现方式,一种是工具级别的子代理(AgentTool),另一种是进程级别的协调者模式(Coordinator Mode)。本文带大家把这两套机制都搞清楚。


一、两种多智能体模式的本质区别

先把这两种模式的区别说清楚,因为它们经常被混淆。

AgentTool(工具调用子代理)

主代理通过调用 Agent 工具(工具名 Agent)来派发子任务。子代理在一个独立的 queryLoop 里运行,有自己的消息历史和上下文,完成后把结果返回给主代理,主代理继续它的任务。这本质上是一种串行嵌套------主代理暂停,等子代理完成,再继续。

Coordinator Mode(协调者模式)

通过环境变量 CLAUDE_CODE_COORDINATOR_MODE=1 激活。此时 Claude 变成一个「协调者」,它不直接执行代码,而是把任务分发给一组可以真正并行运行的 worker agents(工人代理)。Worker agents 有各自独立的进程,可以同时执行,协调者统筹全局。

用一个建筑工程的比喻:AgentTool 像一个包工头在现场盯着活干,做完一道工序再做下一道;Coordinator Mode 像一个项目经理,把土建、水电、装修三队同时派出去,自己负责协调进度和验收结果。


二、AgentTool:子代理的完整生命周期

src/tools/AgentTool/AgentTool.tsx 是子代理系统的核心。

子代理的创建(forkSubagent()

当主代理调用 Agent 工具时,forkSubagent() 函数负责创建一个新的执行上下文:

  1. 从当前会话的工具列表里,按照白名单过滤出子代理可用的工具集(子代理默认不继承所有工具)
  2. 创建一个新的 AbortController,并绑定到主代理的 abort 信号------主代理被中断时,所有子代理也会联动中断
  3. 分配一个新的 agentId(UUID),用于标识这个子代理的 session、日志、文件产出
  4. 在这个独立上下文下运行 query() 循环,就像一个完整的会话,只是上下文隔离

子代理的工具限制

子代理的工具集比主代理受限,有两层控制:

  • 通用限制 :防止子代理再创建子代理(避免无限递归),AgentTool 在子代理的工具列表里默认被排除
  • Coordinator Mode 限制 :如果当前是协调者模式,worker agent 只能使用 ASYNC_AGENT_ALLOWED_TOOLS 白名单里的工具,这个白名单来自 coordinatorMode.ts,专门设计来防止 worker「越权」

子代理的进度可视化

agentColorManager.ts 为每个子代理分配一个颜色。终端 UI 里,主代理的输出和每个子代理的输出会用不同颜色区分,大家一眼就能看出「这条 Bash 命令是哪个代理执行的」。这在调试多代理任务时极大地降低了认知负担。

子代理的 Resume

子代理也有自己的 session ID,产出的 transcript 文件存储在独立路径下。通过 resumeAgent() 可以在主进程重启后恢复一个中途中断的子代理,让它继续未完成的任务。


三、Coordinator Mode:协调者的工作机制

Coordinator Mode 是一个更复杂的多代理协作框架,通过 bun:bundle 的条件编译开关(COORDINATOR_MODE)保护,只在有对应 feature flag 的构建里存在。

如何激活

typescript 复制代码
// src/coordinator/coordinatorMode.ts
export function isCoordinatorMode(): boolean {
  if (feature('COORDINATOR_MODE')) {
    return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
  }
  return false
}

设置环境变量 CLAUDE_CODE_COORDINATOR_MODE=1 即可,退出设置 0 或删除变量。

协调者的 System Prompt 注入

getCoordinatorUserContext() 会在协调者的 user context 里注入特殊指令,大意是:

你是一个协调者,你的职责是分解任务、分配给 worker agents、汇总结果。不要自己直接执行代码或编辑文件,把具体工作交给 workers。

这段指令通过 QueryEngine.submitMessage() 里的 userContext 注入,而不是放在 systemPrompt 里,是为了避免影响工具列表的序列化格式。

协调者与 Worker 的通信工具

协调者的工具箱里有几个专用工具:

工具 作用
TeamCreateTool 创建一组 worker agents,启动并行执行
TeamDeleteTool 解散 worker 团队,等待最终结果
SendMessageTool 向特定 worker 发送指令或接收其回复

这三个工具在普通的非协调者会话里不可见,只有 isCoordinatorMode() 为 true 时才会被注入到工具列表。

Scratchpad 共享目录

协调者和 worker agents 之间传递大型中间结果(比如分析报告、代码片段),通过一个共享的 scratchpad 目录完成。这个目录通过 CLAUDE_CODE_SCRATCHPAD_DIR 环境变量指定,或者由 Statsig feature gate tengu_scratch 控制是否启用。

Worker 把结果写到 scratchpad,协调者读取,这样就不需要把大量内容都放进消息里,避免撑爆各自的 context。


四、完整的多智能体协作架构

把两种模式放在一起,整体架构如图所示:
#mermaid-svg-B4ZTkwIlBC5F4N1l{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-B4ZTkwIlBC5F4N1l .error-icon{fill:#552222;}#mermaid-svg-B4ZTkwIlBC5F4N1l .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-B4ZTkwIlBC5F4N1l .marker{fill:#333333;stroke:#333333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .marker.cross{stroke:#333333;}#mermaid-svg-B4ZTkwIlBC5F4N1l svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-B4ZTkwIlBC5F4N1l p{margin:0;}#mermaid-svg-B4ZTkwIlBC5F4N1l .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .cluster-label text{fill:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .cluster-label span{color:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .cluster-label span p{background-color:transparent;}#mermaid-svg-B4ZTkwIlBC5F4N1l .label text,#mermaid-svg-B4ZTkwIlBC5F4N1l span{fill:#333;color:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .node rect,#mermaid-svg-B4ZTkwIlBC5F4N1l .node circle,#mermaid-svg-B4ZTkwIlBC5F4N1l .node ellipse,#mermaid-svg-B4ZTkwIlBC5F4N1l .node polygon,#mermaid-svg-B4ZTkwIlBC5F4N1l .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .rough-node .label text,#mermaid-svg-B4ZTkwIlBC5F4N1l .node .label text,#mermaid-svg-B4ZTkwIlBC5F4N1l .image-shape .label,#mermaid-svg-B4ZTkwIlBC5F4N1l .icon-shape .label{text-anchor:middle;}#mermaid-svg-B4ZTkwIlBC5F4N1l .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .rough-node .label,#mermaid-svg-B4ZTkwIlBC5F4N1l .node .label,#mermaid-svg-B4ZTkwIlBC5F4N1l .image-shape .label,#mermaid-svg-B4ZTkwIlBC5F4N1l .icon-shape .label{text-align:center;}#mermaid-svg-B4ZTkwIlBC5F4N1l .node.clickable{cursor:pointer;}#mermaid-svg-B4ZTkwIlBC5F4N1l .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .arrowheadPath{fill:#333333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B4ZTkwIlBC5F4N1l .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-B4ZTkwIlBC5F4N1l .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B4ZTkwIlBC5F4N1l .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-B4ZTkwIlBC5F4N1l .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .cluster text{fill:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l .cluster span{color:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-B4ZTkwIlBC5F4N1l .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-B4ZTkwIlBC5F4N1l rect.text{fill:none;stroke-width:0;}#mermaid-svg-B4ZTkwIlBC5F4N1l .icon-shape,#mermaid-svg-B4ZTkwIlBC5F4N1l .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B4ZTkwIlBC5F4N1l .icon-shape p,#mermaid-svg-B4ZTkwIlBC5F4N1l .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-B4ZTkwIlBC5F4N1l .icon-shape .label rect,#mermaid-svg-B4ZTkwIlBC5F4N1l .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B4ZTkwIlBC5F4N1l .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-B4ZTkwIlBC5F4N1l .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-B4ZTkwIlBC5F4N1l :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AgentTool 子代理(串行嵌套)
Worker Agent 2(并行)
Worker Agent 1(并行)
协调者进程
TeamCreateTool

  • SendMessageTool
    TeamCreateTool

  • SendMessageTool
    AgentTool 调用
    写入 scratchpad
    写入 scratchpad
    读取 scratchpad
    SendMessageTool 回复
    SendMessageTool 回复
    Coordinator Claude

分析任务、制定分工
Worker Claude

执行子任务 A

(独立进程,独立 context)
Worker Claude

执行子任务 B

(独立进程,独立 context)
Sub-agent Claude

在 Worker 内部

执行更细粒度子任务
Scratchpad

共享文件目录

可以看到,两种模式可以组合使用------Coordinator 用 TeamCreateTool 启动并行 Workers,Workers 内部再用 AgentTool 派发更细粒度的子代理,形成两级的层次结构。


五、任务系统(Task Tools)

独立于 AgentTool 和 Coordinator Mode 之外,Claude Code 还有一套异步任务系统 ,对应 TaskCreateToolTaskGetToolTaskListToolTaskStopToolTaskUpdateToolTaskOutputTool 这组工具。

任务系统的设计目标是让 Claude 能够创建后台长时间运行的任务,任务有自己的进程,产出 stdout/stderr 输出,主代理可以随时查询任务状态或获取输出,不需要一直等待。

这就像 Linux 的 & 后台运行------Claude 说「去跑这个测试套件,跑完了我来看结果」,然后继续做其他事情,通过 TaskGetTool 定期查询结果:

复制代码
Claude 调用 TaskCreateTool → 启动 "npm test" 后台任务
Claude 继续做其他工作(修改其他文件、写文档等)
Claude 调用 TaskGetTool → 查询任务状态:「running,已跑 47/200 个测试」
Claude 调用 TaskGetTool → 查询任务状态:「completed,所有测试通过」
Claude 汇总结果,返回给用户

任务系统和 AgentTool 的区别在于:AgentTool 的子代理是另一个 Claude 实例,有推理能力;Task 是一个普通的 shell 进程,只是执行命令。前者适合需要 AI 判断的复杂子任务,后者适合确定性的脚本执行。


六、自定义 Agent 定义

src/tools/AgentTool/loadAgentsDir.ts 负责从本地目录加载自定义 agent 定义,这个目录通常是项目的 .claude/agents/

大家可以在这里定义专属的 agent 角色,比如:

  • test-engineer.json:专注于写测试的 agent,只有文件读写和 Bash 工具权限
  • doc-writer.json:专注于写文档的 agent,只能读文件和写 markdown

每个 agent 定义包含:角色名称、系统提示词补充、工具白名单、颜色标识等。主代理在调用 Agent 工具时,可以指定要派遣哪个预定义角色,而不是每次都从零开始描述这个 agent 的职责。

这类似于公司里的岗位 JD------不用每次招人都从头描述岗位职责,直接套用预定义的岗位模板。


七、Session 模式感知与 Resume

Coordinator Mode 有一个细节值得关注:当用户用 --resume 恢复一个历史会话时,系统需要确保恢复的模式和当时的模式一致------不能把协调者会话用普通模式恢复,也不能把普通会话用协调者模式恢复。

matchSessionMode() 负责处理这个一致性:

typescript 复制代码
export function matchSessionMode(
  sessionMode: 'coordinator' | 'normal' | undefined,
): string | undefined {
  const currentIsCoordinator = isCoordinatorMode()
  const sessionIsCoordinator = sessionMode === 'coordinator'

  if (currentIsCoordinator === sessionIsCoordinator) {
    return undefined  // 模式匹配,无需处理
  }

  // 动态修改环境变量,让 isCoordinatorMode() 返回正确的值
  if (sessionIsCoordinator) {
    process.env.CLAUDE_CODE_COORDINATOR_MODE = '1'
  } else {
    delete process.env.CLAUDE_CODE_COORDINATOR_MODE
  }

  return '已切换到匹配会话的模式'
}

这种「动态修改环境变量」的做法看起来有点非常规,但是有充分理由的:isCoordinatorMode() 每次调用都是读环境变量(没有缓存),所以修改环境变量之后,下一次调用就立刻反映新的值,不需要重启进程。在 Resume 场景里,这是最干净的实现方式。


到这里为止,我们共同走完了 Claude Code 源码 Harness 工程全解析的六个篇章:

  1. 启动层:守门员检查 + 并行预热 + 编译时功能开关 + 三条执行路径
  2. 查询引擎:AsyncGenerator 流式管道 + queryLoop 状态机 + 错误恢复 + session 持久化
  3. 工具系统:统一契约 + 三层权限防护 + BashTool 的精密安全设计 + 结果大小管理
  4. 上下文管理:四层防御(Budget → Snip → Microcompact → AutoCompact)+ Token Budget 续写
  5. MCP 协议:三种传输层 + OAuth 鉴权 + Elicitation 双向通信
  6. 多智能体:AgentTool 嵌套子代理 + Coordinator Mode 并行协作 + 任务系统

Claude Code 还在快速迭代,很多实验性功能(HISTORY_SNIPCONTEXT_COLLAPSEREACTIVE_COMPACTCOORDINATOR_MODE)正在逐步走向正式发布。所以这里不是终点,而是一个全新的开始------源码永远是最准确的文档,有疑问的时候,直接去读它,比任何文章都更可靠。

祝大家都拥有一段愉快而充实的 AI 工程探索之旅!