Coordinator:多智能体编排

📑 目录

在 Claude Code 的源码体系中,coordinator/ 目录虽然只有一个核心文件 coordinatorMode.ts(约 19KB),但它承载了整个多智能体编排系统的灵魂。本文将深入解析 Coordinator 如何从传统的单 Agent 对话模式,演进到支持多 Agent 并行协作的 Swarm 架构,以及这一过程中涉及的状态管理、通信协议和任务调度机制。

一、Coordinator 的定位:从单 Agent 到多 Agent 的演进

1.1 单 Agent 模式的局限

传统的 Claude Code 会话是单 Agent 对话模式:用户与单个 Claude 实例交互,所有工具调用、文件操作、代码编辑都在同一个上下文中串行执行。这种模式在处理复杂工程任务时面临明显的瓶颈:

  • 上下文窗口膨胀:随着对话轮次增加,历史消息不断累积,有效推理空间被压缩
  • 任务串行化:即使多个子任务之间没有依赖关系,也只能逐个执行
  • 工具调用冲突:读操作和写操作混杂在一起,难以实现精细化的权限控制

1.2 Coordinator 模式的诞生

coordinatorMode.ts 通过环境变量 CLAUDE_CODE_COORDINATOR_MODE 和 feature gate COORDINATOR_MODE 控制 Coordinator 模式的启用:

// src/coordinator/coordinatorMode.ts (第 38-44 行)
export function isCoordinatorMode(): boolean {
  if (feature('COORDINATOR_MODE')) {
    return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
  }
  return false
}

当 Coordinator 模式激活时,Claude Code 的角色发生根本性转变:它不再是一个直接与用户交互的执行者,而是一个编排者(Orchestrator)。用户的每一条消息首先到达 Coordinator,Coordinator 分析任务后,决定是自行处理还是分发给一个或多个 Worker Agent 并行执行。

1.3 内部工具与 Worker 工具的分离

Coordinator 模式引入了一套**内部工具(Internal Worker Tools)**的概念,这些工具只有 Coordinator 才能使用,Worker 无权访问:

// src/coordinator/coordinatorMode.ts (第 35-40 行)
const INTERNAL_WORKER_TOOLS = new Set([
  TEAM_CREATE_TOOL_NAME,    // 创建团队
  TEAM_DELETE_TOOL_NAME,    // 解散团队
  SEND_MESSAGE_TOOL_NAME,   // 向 Worker 发送消息
  SYNTHETIC_OUTPUT_TOOL_NAME,
])

Worker 可用的工具则通过 ASYNC_AGENT_ALLOWED_TOOLS 过滤内部工具后动态生成:

// src/coordinator/coordinatorMode.ts (第 65-72 行)
const workerTools = Array.from(ASYNC_AGENT_ALLOWED_TOOLS)
  .filter(name => !INTERNAL_WORKER_TOOLS.has(name))
  .sort()
  .join(', ')

这种设计确保了权限的层级分离:Coordinator 掌握团队的生杀大权,而 Worker 专注于具体的代码执行任务。

flowchart TD
    subgraph Coordinator["Coordinator (编排者)"]
        A[用户消息接收]
        B[任务分析与分解]
        C[AgentTool 创建 Worker]
        D[SendMessageTool 调度 Worker]
        E[TaskStopTool 终止 Worker]
    end
    
    subgraph WorkerPool["Worker Agent 集群"]
        W1[Worker A: 调研任务]
        W2[Worker B: 实现任务]
        W3[Worker C: 验证任务]
    end
    
    A --> B
    B --> C
    C --> W1
    C --> W2
    C --> W3
    D -.->|状态同步| W1
    D -.->|状态同步| W2
    D -.->|状态同步| W3
    W1 -.->|task-notification| A
    W2 -.->|task-notification| A
    W3 -.->|task-notification| A

二、CoordinatorAgentStatus:多 Agent 状态的实时监控

2.1 CoordinatorTaskPanel 的设计

CoordinatorAgentStatus.tsx(约 36KB)的核心是 CoordinatorTaskPanel 组件,它在终端界面中渲染一个可操控的 Agent 任务面板。每当存在 local_agent 类型的任务时,该面板就会自动出现在提示输入框的下方:

// src/components/CoordinatorAgentStatus.tsx (第 18-22 行)
/**
 * CoordinatorTaskPanel — Steerable list of background agents.
 *
 * Renders below the prompt input footer whenever local_agent tasks exist.
 * Visibility is driven by evictAfter: undefined (running/retained) shows
 * always; a timestamp shows until passed. Enter to view/steer, x to dismiss.
 */

这个面板的可见性由 evictAfter 字段驱动:

  • undefined:任务正在运行或被保留,始终显示
  • timestamp:任务已结束,显示到指定时间后自动移除
  • 0:用户按下 x 键立即关闭

2.2 Agent 活跃度指标

AgentLine 组件负责渲染每一个 Worker Agent 的状态行,展示丰富的实时指标:

// src/components/CoordinatorAgentStatus.tsx (第 131-150 行,概念性提取)
const isRunning = !isTerminalStatus(task.status)
const elapsedMs = isRunning
  ? Date.now() - task.startTime - pausedMs
  : (task.endTime ?? task.startTime) - task.startTime - pausedMs
const tokenCount = task.progress?.tokenCount
const lastActivity = task.progress?.lastActivity
const queuedCount = task.pendingMessages.length

每个 Agent 的状态行包含以下信息:

指标含义
nameAgent 的名称(如 researcherimplementer
status运行状态:running、completed、failed、killed
elapsed已运行时长(扣除暂停时间)
tokenCount累计消耗的 Token 数量
queuedCount待处理消息队列长度
sep运行/暂停图标(▶ 或 ⏸)

2.3 交互式导航

面板支持键盘和鼠标交互:

// src/components/CoordinatorAgentStatus.tsx (第 80-90 行,概念性提取)
const tasksSelected = useAppState(s => s.footerSelection === 'tasks')
const selectedIndex = tasksSelected ? coordinatorTaskIndex : undefined
  • 方向键:在 main(Coordinator 主会话)和各个 Worker Agent 之间切换
  • Enter:进入选中的 Agent 视图,查看其详细对话上下文
  • x:关闭选中的 Agent(若运行中则发送 stop 信号)
  • 鼠标点击:支持鼠标悬停高亮和点击进入

这种设计让用户能够在多 Agent 并行执行时,随时切入任意一个 Agent 的上下文进行 steer(引导),而不需要等待所有任务完成。

sequenceDiagram
    participant User as 用户
    participant Panel as CoordinatorTaskPanel
    participant State as AppState
    participant Agent as Worker Agent

    User->>Panel: 发送并行任务指令
    Panel->>State: 创建 Agent A / Agent B
    State->>Agent: 启动 Worker A(调研)
    State->>Agent: 启动 Worker B(实现)
    
    loop 每秒刷新
        Panel->>State: getVisibleAgentTasks()
        State-->>Panel: 返回任务列表及状态
        Panel->>Panel: 更新 elapsed / tokens / queued
    end
    
    User->>Panel: 按 ↓ 选中 Agent A
    User->>Panel: 按 Enter 进入 Agent A 视图
    Panel->>State: enterTeammateView(agentId)
    State-->>User: 显示 Agent A 的完整对话
    
    Agent A-->>State: task-notification(completed)
    State->>Panel: 更新 evictAfter 为保留时间
    User->>Panel: 按 x 关闭 Agent A 面板行
    Panel->>State: evictTerminalTask(agentId)

三、多 Agent 协作协议:通信机制与任务分配

3.1 基于 Mailbox 的异步通信

在多 Agent Swarm 中,通信不是通过共享内存或消息总线,而是通过基于文件的 Mailbox 系统实现的。每个 Agent 拥有独立的收件箱:

// src/utils/teammateMailbox.ts (第 35-38 行)
export function getInboxPath(agentName: string, teamName?: string): string {
  const team = teamName || getTeamName() || 'default'
  return join(getTeamsDir(), sanitizePathComponent(team), 'inboxes', `${sanitizePathComponent(agentName)}.json`)
}

Mailbox 路径结构为:~/.claude/teams/{team_name}/inboxes/{agent_name}.json。这种设计有几个优势:

  1. 持久化:即使进程重启,消息也不会丢失
  2. 解耦:发送方和接收方不需要同时在线
  3. 审计:所有通信记录都保存在磁盘上,便于调试
  4. 跨进程:支持 tmuxiterm2in-process 等不同后端

3.2 SendMessageTool:Worker 间的消息传递

SendMessageTool 是 Worker 之间以及 Coordinator 与 Worker 之间的核心通信机制:

// src/tools/SendMessageTool/constants.ts
export const SEND_MESSAGE_TOOL_NAME = 'SendMessage'

在 Coordinator 的系统提示中,明确指导 Coordinator 何时使用 SendMessage

// src/coordinator/coordinatorMode.ts (第 140-145 行,概念性提取)
// Continue workers whose work is complete via ${SEND_MESSAGE_TOOL_NAME}
// to take advantage of their loaded context

SendMessage 的关键作用是复用已加载的上下文。当一个 Worker 完成了调研任务,Coordinator 不需要重新创建一个新的 Worker 来执行实现任务,而是直接向同一个 Worker 发送后续指令,这样该 Worker 已经加载的文件和对话历史都可以被复用。

3.3 任务分配策略:Continue vs Spawn

Coordinator 在分配任务时,需要做出一个关键决策:是继续(Continue)现有的 Worker,还是创建(Spawn)新的 Worker?

源码中的系统提示详细说明了这一决策矩阵:

场景机制原因
调研恰好覆盖了需要编辑的文件Continue (SendMessage)Worker 已有文件上下文,加上清晰的规格说明
调研宽泛但实现聚焦Spawn fresh (Agent)避免携带探索噪音,干净的上下文更高效
修正失败或扩展近期工作ContinueWorker 拥有错误上下文
验证另一个 Worker 刚写的代码Spawn fresh验证者应以 fresh eyes 审视代码
首次实现完全错误Spawn fresh错误路径的上下文会污染重试
完全无关的任务Spawn fresh没有可复用的上下文

3.4 四阶段工作流

Coordinator 将复杂任务分解为四个标准阶段:

Research(调研)→ Synthesis(综合)→ Implementation(实现)→ Verification(验证)

Research 阶段可以高度并行。例如,当用户报告一个 auth 模块的 null pointer bug 时,Coordinator 可以同时启动两个 Worker:

// src/coordinator/coordinatorMode.ts (第 290-295 行,概念性提取)
AgentTool({ description: "Investigate auth bug", subagent_type: "worker", prompt: "..." })
AgentTool({ description: "Research auth tests", subagent_type: "worker", prompt: "..." })

Synthesis 阶段必须由 Coordinator 亲自完成。它不能将理解工作 delegation 给 Worker,而必须阅读 Worker 的返回结果,提取关键信息(文件路径、行号、类型签名),然后将其合成为具体的实现规格说明。

Implementation 阶段需要串行化写操作。源码明确警告:

"Write-heavy tasks — one at a time per set of files"

Verification 阶段要求"证明代码有效,而非仅仅确认它存在"(Prove the code works, don’t just confirm it exists)。这包括运行测试(且必须开启相关 feature)、类型检查、边缘 case 验证等。

四、Swarm 模式:何时启用与如何初始化

4.1 Swarm 的启用条件

Swarm 模式不是默认开启的,它受到多层控制:agentSwarmsEnabled.ts 中定义了严格的启用策略:

// src/utils/agentSwarmsEnabled.ts (第 20-36 行)
export function isAgentSwarmsEnabled(): boolean {
  // Ant 内部构建:始终启用
  if (process.env.USER_TYPE === 'ant') {
    return true
  }
  // 外部构建:需要显式 opt-in
  if (!isEnvTruthy(process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)
      && !isAgentTeamsFlagSet()) {
    return false
  }
  // Killswitch — 始终生效的安全开关
  if (!getFeatureValue_CACHED_MAY_BE_STALE('tengu_amber_flint', true)) {
    return false
  }
  return true
}

对于外部用户,需要同时满足两个条件:

  1. 显式 opt-in:通过环境变量 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS--agent-teams 命令行标志
  2. GrowthBook killswitch tengu_amber_flint 为 true

4.2 Swarm 初始化流程

useSwarmInitialization.ts 是 Swarm 模式初始化的核心 hook:

// src/hooks/useSwarmInitialization.ts (第 27-68 行)
export function useSwarmInitialization(
  setAppState: SetAppState,
  initialMessages: Message[] | undefined,
  { enabled = true }: { enabled?: boolean } = {},
): void {
  useEffect(() => {
    if (!enabled) return
    if (isAgentSwarmsEnabled()) {
      const firstMessage = initialMessages?.[0]
      const teamName = firstMessage && 'teamName' in firstMessage
        ? (firstMessage.teamName as string | undefined)
        : undefined
      const agentName = firstMessage && 'agentName' in firstMessage
        ? (firstMessage.agentName as string | undefined)
        : undefined

      if (teamName && agentName) {
        // 恢复会话路径
        initializeTeammateContextFromSession(setAppState, teamName, agentName)
        const teamFile = readTeamFile(teamName)
        const member = teamFile?.members.find(m => m.name === agentName)
        if (member) {
          initializeTeammateHooks(setAppState, getSessionId(), {
            teamName, agentId: member.agentId, agentName,
          })
        }
      } else {
        // 全新启动路径
        const context = getDynamicTeamContext?.()
        if (context?.teamName && context?.agentId && context?.agentName) {
          initializeTeammateHooks(setAppState, getSessionId(), {
            teamName: context.teamName,
            agentId: context.agentId,
            agentName: context.agentName,
          })
        }
      }
    }
  }, [setAppState, initialMessages, enabled])
}

这个 hook 处理两种关键场景:

  1. 恢复会话(Resume):用户通过 --resume/resume 命令恢复一个之前的 Swarm 会话。此时 teamNameagentName 存储在 transcript 的第一个消息中,系统需要从 team file 中查找对应的 agentId,并重新初始化 teammate hooks。

  2. 全新启动(Fresh Spawn):首次启动时,团队上下文已经在 main.tsx 中通过 computeInitialTeamContext() 计算好并注入到 initialState 中,这里只需要初始化 hooks 即可。

4.3 权限轮询机制

在多 Agent 环境中,权限管理变得尤为复杂。当一个 Worker 需要执行敏感操作(如 BashToolFileEditTool)时,它不能自行决定,而需要向 Coordinator(Leader)请求许可。useSwarmPermissionPoller.ts 实现了 Worker 端的权限响应轮询:

// src/hooks/useSwarmPermissionPoller.ts (第 22-24 行)
const POLL_INTERVAL_MS = 500

Worker 每 500 毫秒检查一次自己的 Mailbox,寻找来自 Leader 的权限响应。整个权限同步流程如下:

// src/utils/swarm/permissionSync.ts (第 1-30 行)
/**
 * Flow:
 * 1. Worker agent encounters a permission prompt
 * 2. Worker sends a permission_request message to the leader's mailbox
 * 3. Leader polls for mailbox messages and detects permission requests
 * 4. User approves/denies via the leader's UI
 * 5. Leader sends a permission_response message to the worker's mailbox
 * 6. Worker polls mailbox for responses and continues execution
 */

权限请求的数据结构包含丰富的上下文信息:

// src/utils/swarm/permissionSync.ts (第 52-80 行)
export const SwarmPermissionRequestSchema = lazySchema(() => z.object({
  id: z.string(),              // 请求唯一标识
  workerId: z.string(),        // Worker 的 Agent ID
  workerName: z.string(),      // Worker 名称
  workerColor: z.string().optional(),  // Worker 颜色标识
  teamName: z.string(),        // 所属团队
  toolName: z.string(),        // 请求使用的工具名
  toolUseId: z.string(),       // 原始 toolUse ID
  description: z.string(),     // 人类可读的描述
  input: z.record(z.string(), z.unknown()),  // 序列化的工具输入
  permissionSuggestions: z.array(z.unknown()),
  status: z.enum(['pending', 'approved', 'rejected']),
  resolvedBy: z.enum(['worker', 'leader']).optional(),
  resolvedAt: z.number().optional(),
  feedback: z.string().optional(),
  updatedInput: z.record(z.string(), z.unknown()).optional(),
  permissionUpdates: z.array(z.unknown()).optional(),
  createdAt: z.number(),
}))

这种设计允许 Leader 在审批时:

  • 批准(Approve):直接放行,并可附带 "Always allow" 规则
  • 拒绝(Reject):提供反馈说明,Worker 需要调整策略
  • 修改输入(Update Input):Leader 可以修改工具调用的参数后再放行

五、与 Task 系统的关系:调度与执行

5.1 Coordinator 如何调度 Task

Coordinator 并不直接操作底层 Task 系统,而是通过工具调用来间接调度。当 Coordinator 调用 AgentTool 时,实际上是在创建一个新的 Task;当调用 SendMessageTool 时,是在向一个已有的 Task 追加消息;当调用 TaskStopTool 时,是在终止一个运行中的 Task。

这些 Task 在 UI 层被 CoordinatorAgentStatus.tsx 统一展示为 Agent 任务面板。getVisibleAgentTasks 函数过滤出所有面板级 Agent 任务:

// src/components/CoordinatorAgentStatus.tsx (第 37-41 行)
export function getVisibleAgentTasks(tasks: AppState['tasks']): LocalAgentTaskState[] {
  return Object.values(tasks)
    .filter((t): t is LocalAgentTaskState => isPanelAgentTask(t) && t.evictAfter !== 0)
    .sort((a, b) => a.startTime - b.startTime)
}

5.2 LocalAgentTask 与 RemoteAgentTask

在 Swarm 架构中,存在两种类型的 Agent Task:

LocalAgentTask:运行在当前 Node.js 进程中的 Agent 任务。它们共享同一个进程空间,但拥有独立的对话上下文。这是 in-process 后端的主要执行方式。

RemoteAgentTask:运行在独立进程或终端窗格中的 Agent 任务。Swarm 支持多种后端:

// src/utils/swarm/backends/types.ts (第 8-15 行)
export type BackendType = 'tmux' | 'iterm2' | 'in-process'
  • tmux:利用 tmux 的 pane 分割功能,每个 Worker 占据一个独立的 pane,Leader 可以在主 pane 中查看所有 Worker 的输出
  • iterm2:利用 iTerm2 的原生分屏能力,通过 it2 CLI 管理 pane
  • in-process:在同一个 Node.js 进程中运行,通过代码隔离上下文,适合资源受限的环境

5.3 InProcessTeammateTask 的特殊角色

InProcessTeammateTask 是 Swarm 模式中的轻量级任务单元,它不需要启动独立的子进程,而是在当前进程的隔离上下文中执行。这种模式的优势在于启动速度快、资源开销低,但缺点是如果某个 Worker 崩溃,可能会影响整个进程。

5.4 任务生命周期

一个 Swarm 中的 Agent Task 典型生命周期如下:

  1. 创建(Spawn):Coordinator 调用 AgentTool,传入 descriptionsubagent_type: "worker" 和具体的 prompt
  2. 运行(Running):Worker Agent 开始执行,消耗 tokens,向 Mailbox 发送进度更新
  3. 通知(Notification):Worker 完成后,向 Coordinator 发送 <task-notification> XML 消息
  4. 综合(Synthesis):Coordinator 阅读结果,决定下一步行动
  5. 继续(Continue):通过 SendMessageTool 向同一 Worker 发送后续指令,或创建新的 Worker
  6. 终止(Stop):任务完成或出错时,Coordinator 调用 TaskStopTool 终止 Worker
  7. 清理(Eviction)CoordinatorTaskPanel 的 1 秒 tick 在 evictAfter 到期后清理面板行

六、架构演进:从单一会话到 Agent 集群

6.1 架构对比

回顾 Claude Code 的架构演进,可以清晰地看到从单 Agent 到多 Agent 的转变:

维度单 Agent 模式Coordinator + Swarm 模式
角色执行者编排者
并发串行并行(Research + Verification)
通信Mailbox 文件系统
权限单用户确认Leader 集中审批
上下文单一对话历史多 Agent 独立上下文
可视化CoordinatorTaskPanel
后端单一进程tmux / iTerm2 / in-process

6.2 设计哲学

Coordinator 模式的设计体现了几个核心原则:

1. 分离关注(Separation of Concerns)

Coordinator 负责"做什么"和"什么时候做",Worker 负责"怎么做"。Coordinator 不直接编辑文件,Worker 不负责任务分配。

2. 上下文复用(Context Reuse)

SendMessageTool 的设计精妙之处在于它允许 Coordinator 在 Worker 完成一个阶段后,直接复用该 Worker 已加载的上下文继续下一阶段,而不是每次都从头创建新 Agent。

3. 乐观并行(Optimistic Parallelism)

在 Research 阶段,Coordinator 被鼓励"尽可能并行地启动独立 Worker",因为调研任务通常是只读的,不会互相干扰。

4. 悲观串行(Pessimistic Serialization)

在 Implementation 阶段,写同一组文件的 Worker 必须串行执行,以避免冲突和数据不一致。

5. 人机协作(Human-in-the-loop)

即使在 Swarm 模式下,所有敏感操作的最终审批权仍然掌握在用户手中。Worker 的权限请求会汇聚到 Leader 的 UI,由用户统一审批。

七、总结

Claude Code 的 Coordinator 系统是一个精心设计的多智能体编排框架。它通过 coordinatorMode.ts 定义了角色和协议,通过 CoordinatorAgentStatus.tsx 提供了实时的可视化监控,通过 useSwarmInitialization.tsuseSwarmPermissionPoller.ts 实现了 Swarm 的初始化和权限同步,最终构建出一个能够并行调研、串行实现、集中验证的 Agent 协作生态。

这套系统的价值不仅在于提升了复杂任务的执行效率,更在于它定义了一种可扩展的多 Agent 软件工程范式:Coordinator 作为"技术主管"负责拆分任务和把控质量,Worker Agent 作为"开发工程师"负责具体实现,而 Mailbox 通信机制则相当于团队内部的"异步协作通道"。

对于正在构建 AI Agent 系统的开发者而言,Claude Code 的 Coordinator 架构提供了极具参考价值的实践经验:

  • 不要试图让所有 Agent 共享同一个上下文,独立的对话历史和基于 Mailbox 的通信才是可扩展的架构
  • 区分内部工具和外部工具,确保权限层级清晰
  • 为 Agent 状态提供实时可视化,让用户始终感知后台发生了什么
  • 为权限设计异步审批流程,不要让 Worker 阻塞等待用户输入

下一篇文章,我们将深入探讨 Swarm 模式下的后端实现——tmuxiTerm2 的 pane 管理是如何与 Agent 生命周期绑定的,敬请期待。