1. 项目概述:Claude Code 多 Agent 协调器架构解析
今天我们来深入探讨一个工业级的多 Agent 系统实现——Claude Code 的 Coordinator-Worker 架构。这个系统已经在生产环境中稳定运行,其设计思路和实现细节对于构建可靠的 AI 协作系统具有重要参考价值。
Claude Code 2.1.88 版本采用 TypeScript 实现,整个项目包含 4756 个文件,其中 1884 个是 .ts/.tsx 源文件。这套架构最核心的特点是将系统明确划分为 Coordinator(协调器)和 Worker(工作者)两个角色,通过清晰的职责分离来实现高效的任务协作。
提示:本文分析的源码是通过 npm 发布包(@anthropic-ai/claude-code)内附带的 source map 还原得到的,仅用于技术研究目的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 架构总览:Coordinator 与 Worker 的角色分离
2.1 角色定义与职责划分
Claude Code 的多 Agent 架构将系统分为两个明确的角色:
Coordinator(协调器) 是整个系统的"大脑",主要负责:
- 理解用户意图
- 分解复杂任务
- 综合多个 Worker 的结果
- 与用户直接沟通
值得注意的是,协调器本身不执行任何具体的文件操作或命令执行,它只拥有三个核心工具:
AgentTool:用于派生新的 WorkerSendMessageTool:向已有 Worker 发送后续指令TaskStopTool:终止运行中的 Worker
Worker(工作者) 是由协调器异步派生的"执行者",每个 Worker 都拥有:
- 独立的上下文环境
- 特定的工具集
- 明确的生命周期
Worker 负责执行具体的研究、实现和验证任务。这种职责分离的设计使得系统更加模块化,也更容易控制各个组件的权限和行为。
2.2 协调器模式的控制机制
协调器模式通过环境变量 CLAUDE_CODE_COORDINATOR_MODE 控制开关,在 coordinatorMode.ts 文件中定义了协调器的系统提示:
typescript复制export function getCoordinatorSystemPrompt(): string {
return `You are Claude Code, an AI assistant that orchestrates
software engineering tasks across multiple workers.
You are a **coordinator**. Your job is to:
- Help the user achieve their goal
- Direct workers to research, implement and verify code changes
- Synthesize results and communicate with the user
- Answer questions directly when possible — don't delegate work
that you can handle without tools`
}
系统还支持会话恢复时的模式匹配——如果恢复的会话是协调器模式,当前环境会自动切换:
typescript复制export function matchSessionMode(
sessionMode: 'coordinator' | 'normal' | undefined,
): string | undefined {
if (sessionIsCoordinator) {
process.env.CLAUDE_CODE_COORDINATOR_MODE = '1'
} else {
delete process.env.CLAUDE_CODE_COORDINATOR_MODE
}
}
这种设计确保了会话状态的持久性和一致性,即使用户中断后重新连接,系统也能保持原有的工作模式。
3. 任务模型:完整的生命周期管理
3.1 任务类型与状态机
Task.ts 文件定义了任务的类型体系和状态机。任务类型包括:
typescript复制export type TaskType =
| 'local_bash' // 本地 Shell 任务
| 'local_agent' // 本地 Agent 子任务
| 'remote_agent' // 远程 Agent(CCR 环境)
| 'in_process_teammate' // 进程内协作者
| 'local_workflow' // 本地工作流
| 'monitor_mcp' // MCP 监控任务
| 'dream' // 后台推理任务
任务状态则是单向转换的:
typescript复制export type TaskStatus =
| 'pending' | 'running' | 'completed' | 'failed' | 'killed'
系统通过 isTerminalTaskStatus 函数判断任务是否已进入终态,防止向已结束的 Worker 注入消息:
typescript复制export function isTerminalTaskStatus(status: TaskStatus): boolean {
return status === 'completed' || status === 'failed' || status === 'killed'
}
3.2 任务 ID 生成机制
任务 ID 采用类型前缀 + 随机字符的方式生成,设计非常巧妙:
typescript复制const TASK_ID_PREFIXES: Record<string, string> = {
local_bash: 'b',
local_agent: 'a',
remote_agent: 'r',
in_process_teammate: 't',
local_workflow: 'w',
monitor_mcp: 'm',
dream: 'd',
}
const TASK_ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
export function generateTaskId(type: TaskType): string {
const prefix = getTaskIdPrefix(type)
const bytes = randomBytes(8)
let id = prefix
for (let i = 0; i < 8; i++) {
id += TASK_ID_ALPHABET[bytes[i]! % TASK_ID_ALPHABET.length]
}
return id
}
这种设计有几个优点:
- 从 ID 前缀即可判断任务类型(如
a开头的是 Agent 任务) - 36^8 ≈ 2.8 万亿种组合,提供了足够的唯一性
- 源码注释中提到这是为了"抵御暴力符号链接攻击"
4. Worker 派生机制详解
4.1 Agent 类型与定义
Claude Code 支持三类 Agent 定义:
-
内置 Agent(built-in):代码中硬编码的 Agent,如:
general-purpose:通用目的 AgentExplore:只读的快速搜索专家Plan:规划专用 Agent
-
自定义 Agent(custom):用户通过 Markdown 或 JSON 文件定义
-
插件 Agent(plugin):通过插件系统注册的 Agent
以 general-purpose Agent 为例,其定义结构如下:
typescript复制export const GENERAL_PURPOSE_AGENT: BuiltInAgentDefinition = {
agentType: 'general-purpose',
whenToUse: 'General-purpose agent for researching complex questions,
searching for code, and executing multi-step tasks.',
tools: ['*'], // 可使用所有工具
source: 'built-in',
baseDir: 'built-in',
getSystemPrompt: getGeneralPurposeSystemPrompt,
}
而 Explore Agent 则是一个受限的只读 Agent:
typescript复制export const EXPLORE_AGENT: BuiltInAgentDefinition = {
agentType: 'Explore',
disallowedTools: [
AGENT_TOOL_NAME, // 不能再派生子 Agent
FILE_EDIT_TOOL_NAME, // 不能编辑文件
FILE_WRITE_TOOL_NAME, // 不能写入文件
NOTEBOOK_EDIT_TOOL_NAME, // 不能编辑 Notebook
],
model: 'haiku', // 使用更快的小模型
omitClaudeMd: true, // 不加载项目记忆文件
getSystemPrompt: () => getExploreSystemPrompt(),
}
这种设计体现了"最小权限原则"——每个 Agent 只拥有完成其任务所需的最小工具集。
4.2 工具过滤系统
agentToolUtils.ts 中的 filterToolsForAgent 实现了多层工具过滤:
typescript复制export function filterToolsForAgent({
tools, isBuiltIn, isAsync, permissionMode
}): Tools {
return tools.filter(tool => {
// MCP 工具对所有 Agent 开放
if (tool.name.startsWith('mcp__')) return true
// 全局禁止列表
if (ALL_AGENT_DISALLOWED_TOOLS.has(tool.name)) return false
// 自定义 Agent 额外禁止列表
if (!isBuiltIn && CUSTOM_AGENT_DISALLOWED_TOOLS.has(tool.name))
return false
// 异步 Agent 只允许白名单内的工具
if (isAsync && !ASYNC_AGENT_ALLOWED_TOOLS.has(tool.name))
return false
return true
})
}
过滤逻辑分为四层:
- MCP 工具豁免
- 全局黑名单检查
- 自定义 Agent 额外黑名单
- 异步 Agent 白名单检查
这种分层设计确保了不同类型的 Agent 拥有恰当的能力边界,既保证了灵活性,又确保了安全性。
4.3 Worker 派生流程
AgentTool.tsx 中的 call 方法是 Worker 派生的入口,整个流程可以分为以下步骤:
- 权限检查:验证 Agent 类型是否被权限规则拒绝
- MCP 依赖检查:如果 Agent 声明了
requiredMcpServers,等待相关服务器连接就绪 - 系统提示构建:根据 Agent 定义生成系统提示,附加环境信息
- 工具集组装:根据 Agent 定义过滤可用工具
- 执行模式选择:同步执行或异步后台执行
- Agent 运行:调用
runAgent启动独立的对话循环
MCP 依赖检查的实现采用了轮询等待模式:
typescript复制if (hasPendingRequiredServers) {
const MAX_WAIT_MS = 30_000
const POLL_INTERVAL_MS = 500
const deadline = Date.now() + MAX_WAIT_MS
while (Date.now() < deadline) {
await sleep(POLL_INTERVAL_MS)
// 提前退出:如果任何必需服务器已失败
const hasFailedRequiredServer = currentAppState.mcp.clients.some(
c => c.type === 'failed' && requiredMcpServers.some(...)
)
if (hasFailedRequiredServer) break
if (!stillPending) break
}
}
这种设计确保了系统在依赖服务不可用时能够优雅降级或快速失败,而不是无限期等待。
5. Fork 子代理:基于上下文继承的特殊派生模式
5.1 Fork 模式的设计动机
除了常规的 Agent 派生,Claude Code 还实现了一种名为 Fork 的特殊派生模式(定义在 forkSubagent.ts 中)。与常规派生不同,Fork 模式让子代理继承父代理的完整对话上下文和系统提示。
Fork Agent 的定义如下:
typescript复制export const FORK_AGENT = {
agentType: 'fork',
tools: ['*'],
maxTurns: 200,
model: 'inherit', // 继承父代理的模型
permissionMode: 'bubble', // 权限提示冒泡到父终端
getSystemPrompt: () => '', // 不使用自己的系统提示
}
这种模式特别适合需要基于当前对话状态进行并行工作的场景,比如:
- 同时探索多个解决方案路径
- 并行验证不同假设
- 分解大型任务为独立子任务
5.2 Prompt Cache 优化技术
Fork 模式的一个关键设计目标是最大化 API 请求的 prompt cache 命中率。实现方式很巧妙:
typescript复制export function buildForkedMessages(
directive: string,
assistantMessage: AssistantMessage,
): MessageType[] {
// 保留完整的父 assistant 消息(所有 tool_use 块)
const fullAssistantMessage = { ...assistantMessage, uuid: randomUUID() }
// 为每个 tool_use 生成相同的占位符 tool_result
const toolResultBlocks = toolUseBlocks.map(block => ({
type: 'tool_result',
tool_use_id: block.id,
content: [{ type: 'text', text: FORK_PLACEHOLDER_RESULT }],
}))
// 只有最后的 directive 文本块不同
const toolResultMessage = createUserMessage({
content: [...toolResultBlocks, { type: 'text', text: buildChildMessage(directive) }],
})
return [fullAssistantMessage, toolResultMessage]
}
所有 Fork 子代理的 tool_result 内容完全相同('Fork started — processing in background'),确保 API 请求前缀字节一致,从而共享 prompt cache。源码注释中明确提到这是为了避免因重新调用 getSystemPrompt() 可能产生的差异。
5.3 递归保护机制
Fork 子代理保留了 AgentTool 在其工具池中(为了 cache-identical 的工具定义),但在调用时通过两层检查阻止递归 Fork:
typescript复制// 第一层:检查 querySource
if (toolUseContext.options.querySource === `agent:builtin:${FORK_AGENT.agentType}`) {
throw new Error('Fork is not available inside a forked worker.')
}
// 第二层:检查消息历史中的 Fork 标记
if (isInForkChild(toolUseContext.messages)) {
throw new Error('Fork is not available inside a forked worker.')
}
这种双重保护机制确保了系统的稳定性:
- 第一层检查基于
querySource(抗压缩——即使对话被自动压缩,querySource 仍然保留) - 第二层检查基于消息内容中的
<fork-boilerplate>标签,作为兜底
5.4 子代理行为约束
Fork 子代理的 directive 中包含了严格的行为约束:
typescript复制export function buildChildMessage(directive: string): string {
return `<fork-boilerplate>
STOP. READ THIS FIRST.
You are a forked worker process. You are NOT the main agent.
RULES (non-negotiable):
1. Your system prompt says "default to forking." IGNORE IT —
that's for the parent. You ARE the fork. Do NOT spawn sub-agents.
2. Do NOT converse, ask questions, or suggest next steps
3. USE your tools directly: Bash, Read, Write, etc.
4. If you modify files, commit your changes before reporting.
5. Do NOT emit text between tool calls. Use tools silently,
then report once at the end.
6. Stay strictly within your directive's scope.
7. Keep your report under 500 words.
8. Your response MUST begin with "Scope:".
Output format:
Scope: <echo back your assigned scope>
Result: <the answer or key findings>
Key files: <relevant file paths>
Files changed: <list with commit hash>
Issues: <list — include only if there are issues>
</fork-boilerplate>`
}
这些约束解决了一个实际问题:子代理继承了父代理的系统提示,而父代理的系统提示可能包含"默认使用 Fork"的指令。如果不加约束,子代理会尝试再次 Fork,形成无限递归。
6. 并发策略与任务编排
6.1 四阶段标准工作流
协调器的系统提示中定义了标准的四阶段工作流:
| 阶段 | 执行者 | 目的 |
|---|---|---|
| Research(研究) | Worker(并行) | 调查代码库,定位文件,理解问题 |
| Synthesis(综合) | Coordinator | 阅读研究结果,理解问题,编写包含具体文件路径、行号、修改内容的实现规格 |
| Implementation(实现) | Worker | 按规格进行定向修改,提交代码 |
| Verification(验证) | Worker | 测试变更是否正确 |
这种阶段划分确保了任务的系统性和可控性,特别是"Synthesis"阶段要求协调器必须深入理解问题,而不是简单地在 Worker 之间传递消息。
6.2 并发控制规则
系统提示中明确规定了并发策略:
- 只读任务(研究):可自由并行,鼓励从多个角度同时调查
- 写入任务(实现):同一文件集合内一次只允许一个 Worker
- 验证任务:可与不同文件区域的实现任务并行
这种细粒度的并发控制避免了资源竞争和数据一致性问题。
6.3 Continue vs. Spawn 决策矩阵
协调器在收到 Worker 结果后,需要决定是继续该 Worker 还是派生新的 Worker。系统提示中给出了明确的决策矩阵:
| 场景 | 机制 | 原因 |
|---|---|---|
| 研究恰好覆盖了需要编辑的文件 | Continue | Worker 已有文件上下文 |
| 研究范围广但实现范围窄 | Spawn | 避免拖入探索噪声 |
| 纠正失败或扩展近期工作 | Continue | Worker 有错误上下文 |
| 验证另一个 Worker 写的代码 | Spawn | 验证者应以全新视角审视 |
| 首次实现方向完全错误 | Spawn | 错误方向的上下文会污染重试 |
这个决策矩阵的核心逻辑是"上下文重叠度"评估,确保了任务执行的效率和正确性。
6.4 综合(Synthesis)的严格要求
系统提示中对协调器的"综合"职责有非常严格的要求:
code复制Never write "based on your findings" or "based on the research."
These phrases delegate understanding to the worker instead of
doing it yourself. You never hand off understanding to another worker.
这种设计避免了"懒惰委托"问题,强制要求协调器必须真正理解问题,而不是简单地在 Worker 之间传递消息。这是 Claude Code 架构中最值得借鉴的设计之一。
7. Worker 间通信与隔离机制
7.1 异步通知机制
Worker 的结果通过 <task-notification> XML 格式异步回传给协调器:
xml复制<task-notification>
<task-id>{agentId}</task-id>
<status>completed|failed|killed</status>
<summary>{human-readable status summary}</summary>
<result>{agent's final text response}</result>
<usage>
<total_tokens>N</total_tokens>
<tool_uses>N</tool_uses>
<duration_ms>N</duration_ms>
</usage>
</task-notification>
这些通知以 user-role 消息的形式注入协调器的对话流。协调器通过 <task-notification> 开头标签来区分真实用户消息和 Worker 通知。
7.2 Worker 继续与终止机制
通过 SendMessageTool,协调器可以向已完成的 Worker 发送后续指令,Worker 保留其完整的对话上下文继续执行。这避免了为后续任务重新构建上下文的开销。
通过 TaskStopTool,协调器可以终止运行中的 Worker。值得注意的是,被终止的 Worker 仍然可以通过 SendMessageTool 继续——这意味着"终止"更像是"暂停",Worker 的上下文不会被销毁。
7.3 隔离机制设计
Claude Code 提供了多种隔离机制来确保任务执行的独立性和安全性:
-
Worktree 隔离:
Agent 支持isolation: 'worktree'模式,在临时 git worktree 中运行,与主工作目录完全隔离:typescript复制export function buildWorktreeNotice( parentCwd: string, worktreeCwd: string ): string { return `You've inherited the conversation context above from a parent agent working in ${parentCwd}. You are operating in an isolated git worktree at ${worktreeCwd} — same repository, same relative file structure, separate working copy.` } -
Scratchpad 共享:
协调器模式下支持 Scratchpad 目录,Worker 可以在该目录中自由读写而无需权限提示,用于跨 Worker 的持久化知识共享:typescript复制if (scratchpadDir && isScratchpadGateEnabled()) { content += `\nScratchpad directory: ${scratchpadDir} Workers can read and write here without permission prompts. Use this for durable cross-worker knowledge.` } -
远程隔离:
对于内部用户,还支持isolation: 'remote'模式,将 Agent 发送到远程 CCR 环境执行,实现完全的进程级隔离。
这些隔离机制提供了不同级别的执行环境隔离,可以根据任务的安全要求和资源需求灵活选择。
8. 工程实践与设计取舍
8.1 循环依赖处理
coordinatorMode.ts 中有一段注释揭示了模块依赖管理的复杂性:
typescript复制// Checks the same gate as isScratchpadEnabled() in
// utils/permissions/filesystem.ts. Duplicated here because importing
// filesystem.ts creates a circular dependency (filesystem -> permissions
// -> ... -> coordinatorMode).
为了避免循环依赖,代码选择了"重复检查"而非"共享导入"。这种务实的取舍在大型 TypeScript 项目中很常见,虽然理论上不够完美,但在实践中能有效解决问题。
8.2 Feature Flag 机制
整个协调器模式被 feature('COORDINATOR_MODE') 包裹,支持编译时的死代码消除(DCE)。Fork 子代理同样被 feature('FORK_SUBAGENT') 控制。这意味着:
- 实验性功能的代码可以随时关闭或移除
- 外部构建中不会包含未完成的功能
- 功能开关可以在编译时而非运行时决定,减少运行时开销
8.3 进程内协作者的限制
进程内协作者(in_process_teammate)有特殊限制:
typescript复制if (isInProcessTeammate() && teamName && run_in_background === true) {
throw new Error('In-process teammates cannot spawn background agents.')
}
if (isTeammate() && teamName && name) {
throw new Error('Teammates cannot spawn other teammates —
the team roster is flat.')
}
这些限制确保了系统的可控性,防止协作者无限制地派生新 Agent 导致资源耗尽。
9. 架构总结与核心设计原则
Claude Code 的多 Agent 协调器架构展示了一套经过生产验证的设计方案,其核心设计原则可以总结为:
-
角色分离彻底:
- 协调器专注理解、分解、综合
- Worker 专注执行具体任务
- 两者不越界,行为可预测
-
上下文管理精细:
- Continue vs. Spawn 的智能决策
- Fork 子代理的 prompt cache 优化
- Worktree 隔离与 Scratchpad 共享的平衡
-
安全边界明确:
- Agent 类型的工具白名单/黑名单
- 递归派生的多层防护
- 进程内协作者的额外限制
-
工程务实:
- 循环依赖的务实处理
- Feature Flag 的灵活控制
- MCP 依赖的轮询等待机制
这套架构中最值得借鉴的是"综合"环节的强制要求——协调器必须理解 Worker 的研究结果后才能指导下一步工作。这一设计从根本上避免了多 Agent 系统中常见的"信息衰减"问题,确保了系统的可靠性和有效性。
