Code Reader
首页
帮助
设计文档
首页
帮助
设计文档
  • Claude Code 多智能体协调与任务执行系统分析

Claude Code 多智能体协调与任务执行系统分析

1. 多智能体架构总览

Claude Code 实现了一个完整的多智能体(multi-agent)编排系统,核心思想是 coordinator(协调者)调度多个 worker(工人)并行执行任务。整个系统围绕三个层次构建:

  1. Coordinator 模式 — 编排层,决定"谁做什么"
  2. Task 类型系统 — 执行层,统一管理异步任务的生命周期
  3. Agent Tool — 桥接层,LLM 通过工具调用发起子智能体

2. Coordinator 模式设计

2.1 双角色模型

Claude Code 支持两种操作模式(src/coordinator/coordinatorMode.ts:36-41):

  • Normal 模式 — 默认模式,LLM 同时负责思考和执行,直接调用所有工具
  • Coordinator 模式 — LLM 仅负责编排,通过 Agent 工具将实际工作委派给 worker
// coordinatorMode.ts:36-41
export function isCoordinatorMode(): boolean {
  if (feature('COORDINATOR_MODE')) {
    return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
  }
  return false
}

2.2 Coordinator 的工具集

协调者的工具被严格限制为"编排专用"(src/constants/tools.ts:107-112):

export const COORDINATOR_MODE_ALLOWED_TOOLS = new Set([
  AGENT_TOOL_NAME,           // 发起新 worker
  TASK_STOP_TOOL_NAME,       // 停止运行中的 worker
  SEND_MESSAGE_TOOL_NAME,    // 给已有 worker 发消息(继续对话)
  SYNTHETIC_OUTPUT_TOOL_NAME // 结构化输出
])

Worker 工具集则通过 ASYNC_AGENT_ALLOWED_TOOLS 定义,包含 Bash、Read、Edit 等标准工具,但排除了 Agent 和 TaskStop 等编排工具,形成严格的角色分离。

2.3 Coordinator 系统提示词

coordinatorMode.ts:111-369 定义了协调者的完整行为规范:

核心职责(第 116-124 行):

  • 作为协调者,调度 worker 研究、实现和验证代码变更
  • 综合结果并与用户沟通
  • 能直接回答的问题不要委派

任务四阶段工作流(第 200-228 行):

阶段执行者目的
ResearchWorkers(并行)调研代码库,定位文件,理解问题
SynthesisCoordinator阅读发现,理解问题,撰写实现规范
ImplementationWorkers按规范做定向修改并提交
VerificationWorkers验证变更有效

并行是协调者的核心优势(第 213-218 行):

  • 只读任务(研究)可以自由并行
  • 写入密集任务(实现)每个文件集一次只能一个
  • 验证有时可以和实现并行(不同文件区域)

2.4 Continue vs Spawn 决策

协调者在收到 worker 结果后,需要选择"继续该 worker"还是"新发起一个"(第 282-293 行):

场景机制原因
研究探索的文件正好需要编辑ContinueWorker 已有文件上下文 + 获得清晰计划
研究宽泛但实现窄Spawn fresh避免拖入探索噪音
纠正失败或扩展近期工作ContinueWorker 有错误上下文
验证另一个 worker 刚写的代码Spawn fresh验证者需要全新视角
完全不同的任务Spawn fresh没有可复用的上下文

2.5 会话模式管理

matchSessionMode()(第 49-78 行)处理 --resume 时的模式匹配:如果恢复的会话是 coordinator 模式但当前是 normal,自动切换环境变量以保持一致。

3. Task 类型系统

3.1 TaskType 枚举

定义于 src/Task.ts:6-13:

export type TaskType =
  | 'local_bash'           // 本地 Shell 命令
  | 'local_agent'          // 本地子智能体
  | 'remote_agent'         // 远程云端会话
  | 'in_process_teammate'  // 同进程队友(团队模式)
  | 'local_workflow'       // 本地工作流(feature-gated)
  | 'monitor_mcp'          // MCP 监控(feature-gated)
  | 'dream'                // 自动记忆巩固

3.2 TaskStatus 生命周期

定义于 src/Task.ts:15-29:

export type TaskStatus =
  | 'pending'    // 已注册但尚未开始
  | 'running'    // 正在执行
  | 'completed'  // 成功完成
  | 'failed'     // 执行失败
  | 'killed'     // 被用户或系统终止

export function isTerminalTaskStatus(status: TaskStatus): boolean {
  return status === 'completed' || status === 'failed' || status === 'killed'
}

生命周期流转:

3.3 TaskStateBase 共享基类

所有任务状态的公共字段(src/Task.ts:45-57):

export type TaskStateBase = {
  id: string              // 唯一 ID(含类型前缀)
  type: TaskType          // 任务类型
  status: TaskStatus      // 当前状态
  description: string     // 人类可读描述
  toolUseId?: string      // 触发此任务的工具调用 ID
  startTime: number       // 启动时间戳
  endTime?: number        // 结束时间戳
  totalPausedMs?: number  // 暂停总时长
  outputFile: string      // 输出文件路径
  outputOffset: number    // 已消费的输出偏移量
  notified: boolean       // 是否已发送完成通知
}

3.4 Task ID 命名方案

每种任务类型有唯一的前缀(src/Task.ts:79-106):

const TASK_ID_PREFIXES = {
  local_bash: 'b',
  local_agent: 'a',
  remote_agent: 'r',
  in_process_teammate: 't',
  local_workflow: 'w',
  monitor_mcp: 'm',
  dream: 'd',
}

ID 格式:<prefix><8-char-random>(例如 a3k8f2m1x),使用大小写不敏感的字母表(0-9a-z),36^8 ≈ 2.8 万亿种组合,足以抵抗暴力符号链接攻击。

4. 任务注册表与调度

4.1 注册表结构

src/tasks.ts 是任务注册中心:

// tasks.ts:22-32
export function getAllTasks(): Task[] {
  const tasks: Task[] = [
    LocalShellTask,      // 'local_bash'
    LocalAgentTask,      // 'local_agent'
    RemoteAgentTask,     // 'remote_agent'
    DreamTask,           // 'dream'
  ]
  if (LocalWorkflowTask) tasks.push(LocalWorkflowTask)  // feature-gated
  if (MonitorMcpTask) tasks.push(MonitorMcpTask)        // feature-gated
  return tasks
}

export function getTaskByType(type: TaskType): Task | undefined {
  return getAllTasks().find(t => t.type === type)
}

每个 Task 实现只需提供 name、type 和 kill() 方法(src/Task.ts:72-76):

export type Task = {
  name: string
  type: TaskType
  kill(taskId: string, setAppState: SetAppState): Promise<void>
}

4.2 任务框架(framework.ts)

src/utils/task/framework.ts 提供统一的任务管理基础设施:

  • registerTask() — 注册任务到 AppState.tasks,发出 task_started SDK 事件
  • updateTaskState() — 不可变更新任务状态(引用相等时跳过重渲染)
  • evictTerminalTask() — 从 AppState 中驱逐已完成任务(含 30 秒面板宽限期 PANEL_GRACE_MS)
  • pollTasks() — 轮询循环,检测输出增量并驱逐完成任务
  • generateTaskAttachments() — 为有新输出的任务生成推送通知

4.3 统一停止逻辑

src/tasks/stopTask.ts 提供统一的停止入口(第 38-99 行):

export async function stopTask(taskId, context): Promise<StopTaskResult> {
  // 1. 查找任务
  // 2. 验证状态为 running
  // 3. 通过 getTaskByType 获取类型实现
  // 4. 调用 taskImpl.kill()
  // 5. Bash 任务抑制 exit code 通知
  // 6. 返回停止结果
}

5. 各任务实现详解

5.1 LocalAgentTask — 本地子智能体

文件: src/tasks/LocalAgentTask/LocalAgentTask.tsx(683 行)

这是最核心的任务类型,管理所有本地子智能体的执行。

扩展状态(第 116-148 行):

export type LocalAgentTaskState = TaskStateBase & {
  type: 'local_agent'
  agentId: string            // 智能体唯一 ID
  prompt: string             // 给智能体的指令
  selectedAgent?: AgentDefinition  // 智能体定义
  agentType: string          // 智能体类型('general-purpose' 等)
  model?: string             // 可选模型覆盖
  abortController?: AbortController  // 取消控制
  result?: AgentToolResult   // 最终结果
  progress?: AgentProgress   // 进度信息(工具计数、token 数等)
  isBackgrounded: boolean    // 前台/后台切换
  pendingMessages: string[]  // 中途 SendMessage 队列
  retain: boolean            // UI 持有(阻止驱逐)
  messages?: Message[]       // 对话历史(缩放视图用)
  evictAfter?: number        // 驱逐宽限期截止时间
}

关键函数:

  • registerAsyncAgent()(第 466-515 行)— 注册后台智能体,创建子 AbortController(父 abort 时自动级联)
  • registerAgentForeground()(第 526-614 行)— 注册前台智能体,支持自动后台化计时器
  • backgroundAgentTask()(第 620-652 行)— 将前台智能体切到后台
  • killAsyncAgent()(第 281-303 行)— 终止智能体
  • enqueueAgentNotification()(第 197-262 行)— 生成 <task-notification> XML 消息并入队

通知格式(第 252-257 行):

<task-notification>
<task-id>a3k8f2m1x</task-id>
<tool-use-id>toolu_abc123</tool-use-id>
<output-file>/path/to/output</output-file>
<status>completed</status>
<summary>Agent "Investigate auth bug" completed</summary>
<result>Found null pointer in src/auth/validate.ts:42...</result>
<usage>
  <total_tokens>15000</total_tokens>
  <tool_uses>12</tool_uses>
  <duration_ms>45000</duration_ms>
</usage>
</task-notification>

进度追踪(第 23-104 行):

ProgressTracker 追踪工具使用次数、token 消耗和最近活动,支持 getActivityDescription() 回调给每个工具生成可读描述(如 "Reading src/foo.ts")。

5.2 RemoteAgentTask — 远程云端会话

文件: src/tasks/RemoteAgentTask/RemoteAgentTask.tsx(856 行)

管理远程 Claude.ai 会话(CCR — Claude Code Remote),支持多种远程任务类型:

const REMOTE_TASK_TYPES = [
  'remote-agent',   // 通用远程智能体
  'ultraplan',      // 远程计划生成
  'ultrareview',    // 远程代码审查
  'autofix-pr',     // PR 自动修复
  'background-pr'   // 后台 PR 处理
] as const

核心机制 — 轮询(第 538-799 行):

  • 每 1 秒轮询远程会话事件
  • 使用 lastEventId 增量获取新事件
  • 稳定空闲检测:要求连续 5 次轮询无新事件才认为会话完成(远程会话在工具调用间会短暂变为空闲)
  • 超时 30 分钟(仅 ultrareview)
  • 完成检查器(completionCheckers)支持自定义完成条件

会话恢复(第 477-532 行):

restoreRemoteAgentTasks() 在 --resume 时从 sidecar 文件读取远程智能体元数据,查询 CCR 获取实时状态,重建轮询。

5.3 LocalShellTask — Shell 命令执行

文件: src/tasks/LocalShellTask/LocalShellTask.tsx(523 行)

管理后台 Shell 命令的执行。

核心特性:

  • 前台/后台切换:registerForeground() → backgroundTask() → backgroundAll()
  • 失速看门狗(第 46-104 行):每 5 秒检查输出,45 秒无增长且尾部看起来像交互提示时发送通知
  • 交互提示检测(第 32-42 行):正则匹配 (y/n)、[y/n]、Continue? 等模式
  • Ctrl+B 批量后台化:backgroundAll() 同时处理所有前台 bash 和 agent 任务

5.4 DreamTask — 记忆巩固

文件: src/tasks/DreamTask/DreamTask.ts(157 行)

最简单的任务类型 — 自动记忆巩固子智能体("做梦")。

export type DreamTaskState = TaskStateBase & {
  type: 'dream'
  phase: DreamPhase          // 'starting' | 'updating'
  sessionsReviewing: number  // 正在审查的会话数
  filesTouched: string[]     // 修改的文件路径
  turns: DreamTurn[]         // 助手回合(工具调用折叠为计数)
  abortController?: AbortController
  priorMtime: number         // 用于 kill 时回滚锁文件
}

Dream 任务没有模型通知路径(纯 UI 展示),所以完成/失败时直接设置 notified: true。

5.5 InProcessTeammateTask — 同进程队友

文件: src/tasks/InProcessTeammateTask/types.ts(121 行)

支持"团队模式"(team mode)下的同进程队友管理。

扩展状态:

export type InProcessTeammateTaskState = TaskStateBase & {
  type: 'in_process_teammate'
  identity: TeammateIdentity  // 身份信息(agentId、agentName、teamName)
  prompt: string
  selectedAgent?: AgentDefinition
  permissionMode: PermissionMode  // 独立权限模式
  awaitingPlanApproval: boolean
  isIdle: boolean             // 空闲状态(leader 可高效等待)
  shutdownRequested: boolean
  onIdleCallbacks?: Array<() => void>  // 空闲回调(leader 无需轮询)
  pendingUserMessages: string[]  // 待投递消息队列
  messages?: Message[]          // 对话历史(缩放视图)
  TEAMMATE_MESSAGES_UI_CAP = 50  // 消息上限(内存优化)
}

TeammateIdentity(第 13-20 行):

export type TeammateIdentity = {
  agentId: string           // "researcher@my-team"
  agentName: string         // "researcher"
  teamName: string
  color?: string
  planModeRequired: boolean
  parentSessionId: string   // Leader 的会话 ID
}

内存优化:TEAMMATE_MESSAGES_UI_CAP = 50(第 101 行)。BQ 分析显示 500+ 回合会话每个智能体约 20MB RSS,292 个并发智能体曾达到 36.8GB。

5.6 LocalMainSessionTask — 后台化主会话

文件: src/tasks/LocalMainSessionTask.ts(479 行)

当用户在查询期间按 Ctrl+B 时,主会话被"后台化":

  • 查询继续在后台运行
  • UI 清空到新提示符
  • 完成时发送通知

复用 LocalAgentTaskState 但 agentType: 'main-session',使用 's' 前缀区分任务 ID。

6. 子智能体的发起与生命周期

6.1 Agent Tool 调用流程

6.2 runAgent 核心引擎

src/tools/AgentTool/runAgent.ts(973 行)是子智能体的执行引擎:

输入参数(第 248-329 行):

  • agentDefinition — 智能体类型定义
  • promptMessages — 初始消息
  • toolUseContext — 工具执行上下文
  • canUseTool — 权限检查函数
  • isAsync — 是否异步(后台)
  • availableTools — 可用工具池
  • forkContextMessages — 分叉上下文消息

执行流程(第 330-860 行):

  1. 解析模型、权限模式、AbortController
  2. 初始化智能体专属 MCP 服务器(initializeAgentMcpServers())
  3. 预加载 frontmatter 中的 skill 和 hook
  4. 构建 agentToolUseContext(通过 createSubagentContext())
  5. 写入元数据和初始 transcript
  6. 进入 query() 循环,逐条 yield 消息
  7. 记录侧链 transcript(fire-and-forget)
  8. finally 清理:MCP 连接、session hooks、prompt cache、文件状态缓存、Perfetto 追踪、transcript 子目录、todos、shell tasks、monitor tasks

关键设计:rootSetAppState(第 337-338 行)确保嵌套 async 智能体的写入能到达根 AppState:

const rootSetAppState =
  toolUseContext.setAppStateForTasks ?? toolUseContext.setAppState

6.3 Fork 子智能体(上下文继承分叉)

src/tools/AgentTool/forkSubagent.ts(210 行)实现了一种特殊的子智能体模式:

核心思想:当 subagent_type 省略时,子智能体继承父级的完整对话上下文和系统提示词,共享 prompt cache。

// forkSubagent.ts:32-39
export function isForkSubagentEnabled(): boolean {
  if (feature('FORK_SUBAGENT')) {
    if (isCoordinatorMode()) return false    // 与 coordinator 模式互斥
    if (getIsNonInteractiveSession()) return false
    return true
  }
  return false
}

Fork 消息构建(第 107-168 行):

  1. 克隆父级助手消息(保留所有 tool_use 块)
  2. 为每个 tool_use 构建占位 tool_result(统一文本:"Fork started — processing in background")
  3. 追加每子级特有的 directive 文本

结果:[...history, assistant(all_tool_uses), user(placeholder_results..., directive)] — 只有最后的文本块不同,最大化 cache 命中率。

Fork 子级行为约束(buildChildMessage(),第 171-198 行):

  • 不要再分叉("You ARE the fork. Do NOT spawn sub-agents")
  • 不要对话、提问或建议下一步
  • 直接使用工具,不要在工具调用之间输出文本
  • 报告格式:Scope / Result / Key files / Files changed / Issues

6.4 恢复(Resume)机制

src/tools/AgentTool/resumeAgent.ts(265 行)支持恢复已中断的子智能体:

  1. 从磁盘读取 transcript 和元数据
  2. 过滤不完整工具调用、空白消息、孤立 thinking
  3. 重建 contentReplacementState(prompt cache 稳定性)
  4. 恢复 worktree(如果存在)
  5. 注册新的 LocalAgentTask,复用原有 agentId
  6. 通过 runAsyncAgentLifecycle() 运行

6.5 runAsyncAgentLifecycle — 后台智能体生命周期

src/tools/AgentTool/agentToolUtils.ts:508-686 定义了后台智能体的完整生命周期:

spawn → 进度追踪 → [可选] 后台摘要 → 完成/失败/终止 → 通知 → 清理
  • 进度追踪:每条消息更新 ProgressTracker,发出 SDK 进度事件
  • 后台摘要:startAgentSummarization() 周期性生成 1-2 句进度摘要
  • 安全分类器:classifyHandoffIfNeeded() 在完成时检查子智能体输出是否违反安全策略
  • 通知:enqueueAgentNotification() 生成 <task-notification> XML

7. 智能体间通信

7.1 通知机制

智能体间的核心通信载体是 <task-notification> XML 消息,通过消息队列(messageQueueManager)投递:

7.2 SendMessage 继续对话

Coordinator 可以通过 SendMessageTool 向已完成研究的 worker 发送后续指令:

// coordinatorMode.ts:298-301
SEND_MESSAGE_TOOL_NAME({
  to: "agent-a1b",
  message: "Fix the null pointer in src/auth/validate.ts:42..."
})

实现通过 queuePendingMessage() 将消息存入 pendingMessages 队列,在下一轮工具调用边界时由 drainPendingMessages() 取出投递。

7.3 前后台切换信号

backgroundSignalResolvers(LocalAgentTask.tsx:519)实现了一个 Promise-based 信号机制:

const backgroundSignalResolvers = new Map<string, () => void>()

// registerAgentForeground 创建 Promise
const backgroundSignal = new Promise<void>(resolve => {
  resolveBackgroundSignal = resolve
})

// backgroundAgentTask 触发 resolve
const resolver = backgroundSignalResolvers.get(taskId)
if (resolver) resolver()  // 中断 agent 循环

7.4 父子级 AbortController 级联

registerAsyncAgent()(第 486 行)支持父子级取消级联:

const abortController = parentAbortController
  ? createChildAbortController(parentAbortController)
  : createAbortController()

当父级(如同进程队友)abort 时,所有子智能体自动 abort。

8. 内置智能体类型

src/tools/AgentTool/builtInAgents.ts 注册以下内置智能体:

智能体类型文件用途
general-purposegeneralPurposeAgent.ts通用智能体,全工具权限
ExploreexploreAgent.ts只读搜索调研
PlanplanAgent.ts只读计划生成
verificationverificationAgent.ts验证代码变更
Claude Code GuideclaudeCodeGuideAgent.tsClaude Code 使用指南
statusline-setupstatuslineSetup.ts状态栏配置
fork (合成)forkSubagent.tsFork 子智能体

在 coordinator 模式下(第 35-42 行),内置智能体被替换为 coordinator 专用的 worker 定义:

if (feature('COORDINATOR_MODE')) {
  if (isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)) {
    const { getCoordinatorAgents } = require('../../coordinator/workerAgent.js')
    return getCoordinatorAgents()
  }
}

9. 关键代码路径总结

9.1 智能体发起路径

AgentTool.call()
  → resolveAgentTools()         // 过滤工具集
  → filterDeniedAgents()        // 权限检查
  → runAgent()                  // 执行引擎
    → registerAsyncAgent()      // 注册任务
    → runAsyncAgentLifecycle()  // 生命周期驱动
      → query()                 // API 调用循环
      → finalizeAgentTool()     // 结果收尾
      → enqueueAgentNotification()  // 通知入队

9.2 任务停止路径

TaskStopTool.call()
  → stopTask()
    → getTaskByType(type)       // 查找任务实现
    → taskImpl.kill()           // 调用类型特定 kill
      → abortController.abort() // 取消执行
      → updateTaskState()       // 状态 → killed
    → emitTaskTerminatedSdk()   // SDK 事件

9.3 通知投递路径

任务完成/失败/终止
  → enqueueAgentNotification() / enqueueShellNotification() / enqueueRemoteNotification()
    → 检查 notified 标记(原子操作,防重复)
    → abortSpeculation()        // 取消推测性结果
    → 构建 <task-notification> XML
    → enqueuePendingNotification()  // 入队
      → query 循环下一轮消费
        → 作为 user-role 消息投递给 LLM

9.4 恢复路径

--resume 启动
  → matchSessionMode()          // 匹配 coordinator/normal 模式
  → restoreRemoteAgentTasks()   // 恢复远程任务
  → resumeAgentBackground()     // 恢复本地智能体
    → getAgentTranscript()      // 读取 transcript
    → readAgentMetadata()       // 读取元数据
    → registerAsyncAgent()      // 重新注册
    → runAsyncAgentLifecycle()  // 重新运行

10. 设计亮点与权衡

10.1 亮点

  1. 统一的 Task 抽象:所有异步执行单元(Shell、Agent、Remote、Dream)共享同一套状态管理、通知和生命周期框架
  2. Coordinator/Worker 职责分离:协调者专注于"想",worker 专注于"做",避免上下文污染
  3. Fork 机制:共享 prompt cache 的上下文继承分叉,大幅降低并行子智能体的 token 消耗
  4. 通知去重:原子化的 notified 标记确保每条通知恰好投递一次
  5. 引用相等优化:updateTaskState() 在 updater 返回同一引用时跳过 setAppState,避免 18+ 个订阅者无谓重渲染
  6. 磁盘输出 + 内存状态双通道:大输出走磁盘(TaskOutput),状态走内存(AppState),兼顾性能和可恢复性

10.2 权衡

  1. Coordinator 模式增加延迟:每次工作需要 coordinator 解读 → 合成 → 再派发,多一轮 API 调用
  2. Worker 无对话可见性:worker 看不到 coordinator 和用户的对话,每个 prompt 必须自包含
  3. Fork 不可嵌套:fork 子级不能再次 fork(防止递归),限制了多层委派
  4. Dream 任务输出不完整:filesTouched 只是近似值,不捕获 bash 间接写入
  5. RemoteAgent 轮询开销:每秒 1 次 API 调用,30 分钟超时前共约 1800 次请求

分析基于 Claude Code 源码快照(2026-04-01),涵盖 src/coordinator/、src/Task.ts、src/tasks/、src/tasks.ts、src/tools/AgentTool/、src/utils/task/ 等核心模块。