接上回:用 LLM 审查 LLM:yoloClassifier 的两阶段安全架构。
单 Agent 的天花板很低。
一个 Agent 同一时间只能做一件事——读文件、跑命令、写代码。给它一个复杂任务("重构这个模块的测试框架"),它会串行地做完所有事情:先读文件,再分析,再改代码,再跑测试。每一步都要等上一步完成。
Claude Code 的解决方案:三种并行模式,解决三种不同的场景。
全景:三种模式的选择
| 模式 | 场景 | 特点 | 成本 |
|---|---|---|---|
| Fork | 把一个任务拆成并行子任务 | 继承父上下文,共享 prompt cache | 极低 |
| Subagent | 独立任务,从零开始 | 干净的上下文,专注的系统提示词 | 中等 |
| Coordinator | 复杂项目,纯调度 | 自己不写代码,只指挥 | 高 |
| Swarm | 多 Agent 并行的物理执行 | tmux/iTerm 可视化 | 取决于 Agent 数 |
让我逐个拆解。
Fork:零成本的影分身
Fork 是 Claude Code 最优雅的并行设计。
核心思想
不指定 subagent_type → 创建 Fork(继承父对话的全部上下文和 prompt cache)。
主线程 ──→ Agent(prompt: "研究 auth 模块") ──→ Fork 子进程
↑ │
│ [共享 system prompt + 对话历史] │
│ [prompt cache 直接命中] │
│ ↓
主线程 ←── <task-notification> 完成 ──────────── 返回结果
为什么说"零成本"?因为 Fork 子进程继承了父的完整消息历史——Anthropic API 的 prompt cache 按前缀匹配,所以子进程的 API 请求会直接命中父进程建立的缓存。启动一个 Fork 几乎不需要额外的输入 token 费用。
防递归:10 条军规
Fork 子进程收到的第一条消息是一段硬编码的"身份声明":
STOP. READ THIS FIRST.
You are a forked worker process. You are NOT the main agent.
然后是 10 条不可违反的规则:
- 不要再 Fork——你就是 Fork,直接执行
- 不要对话——不要问问题、不要建议下一步
- 不要评论——不要加元信息
- 直接用工具——Bash、Read、Write,静默执行
- 如果改了文件,commit——报告 commit hash
- 工具调用之间不要说话——用完工具再统一报告
- 严守范围——指令范围之外的发现最多一句话
- 报告 500 字以内
- 以 "Scope:" 开头——强制格式
- 报告事实,然后停
第 1 条是核心——Fork 子进程的系统提示里也有"可以创建 Fork"的指导,如果不加约束,它会无限递归。解决方案很简单:在消息历史中搜索 <fork-boilerplate> 标签,找到就说明已经在 Fork 里了:
export function isInForkChild(messages: MessageType[]): boolean {
return messages.some(m => {
if (m.type !== 'user') return false
return m.message.content.some(
block => block.type === 'text' &&
block.text.includes(`<${FORK_BOILERPLATE_TAG}>`)
)
})
}
Cache 共享的工程细节
为了让多个 Fork 子进程之间也能共享 cache,消息的构造非常讲究:
// 所有 Fork 子进程使用完全相同的 tool_result 占位符
const FORK_PLACEHOLDER_RESULT = 'Fork started — processing in background'
// 构造消息:[...历史, assistant(所有tool_use), user(占位结果..., 指令)]
// 只有最后一个 text block(指令)不同,最大化 cache 命中
所有 Fork 的 tool_result 占位符都是同一个字符串——这样不同 Fork 的消息前缀完全相同,直到最后的 directive 才不同。前缀越长、越一致,cache 命中率越高。
另一个细节:Fork 不重新调用 getSystemPrompt()——它直接使用父进程已经渲染好的 system prompt 字节。因为 GrowthBook(Feature Flag 系统)在不同时间点可能返回不同值,重新生成 system prompt 可能导致内容不同、cache 失效。
// 注释原文:
// Reconstructing by re-calling getSystemPrompt() can diverge
// (GrowthBook cold→warm) and bust the prompt cache; threading
// the rendered bytes is byte-exact.
内置 Agent 类型
Claude Code 预定义了几种专用 Agent:
Explore Agent:只读的代码侦探
export const EXPLORE_AGENT = {
agentType: 'Explore',
model: process.env.USER_TYPE === 'ant' ? 'inherit' : 'haiku',
omitClaudeMd: true, // 不需要项目配置
disallowedTools: [Agent, FileEdit, FileWrite, NotebookEdit],
}
Explore Agent 有几个关键设计决策:
严格只读。 不能创建、修改、删除任何文件。连临时文件都不行。系统提示词用全大写强调:
=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
外部用户用 Haiku(便宜快),内部员工用父模型。 这是一个成本/质量的权衡——Explore 是高频操作(搜索代码),用小模型够了。
跳过 CLAUDE.md。 Explore 只搜索代码,不需要知道项目的 commit 规范、lint 规则等。跳过 CLAUDE.md 进一步节省 token。
并行是核心要求:
You must make efficient use of tools — wherever possible you should try
to spawn multiple parallel tool calls for grepping and reading files.
Verification Agent:对抗式验证
这是整个代码库里我最佩服的一段提示词。
Verification Agent 的使命不是"确认代码能用"——而是"尝试把代码弄坏":
Your job is not to confirm the implementation works — it's to try to break it.
它的系统提示词直接指出了 AI 验证的两个经典失败模式:
失败模式 1:验证回避。 面对需要检查的东西,找理由不跑——读代码、描述"我会测试什么"、写 PASS、收工。
失败模式 2:被前 80% 迷惑。 看到 UI 很漂亮、测试通过了,就觉得没问题。没注意到一半按钮不工作、状态刷新丢失、后端在坏输入时崩溃。
然后列出了一系列自我欺骗识别清单:
- "The code looks correct based on my reading" → 读代码不是验证,跑它
- "The implementer's tests already pass" → 实现者也是 LLM,独立验证
- "This is probably fine" → probably 不是 verified,跑它
- "I don't have a browser" → 你检查过有没有 playwright MCP 吗?
- "This would take too long" → 不是你决定的
每种变更类型都有专门的验证策略——前端(启动 dev server + 浏览器自动化 + curl 子资源)、后端(curl endpoint + 验证响应结构 + 测试错误处理)、重构(测试套件不改动必须通过 + public API 表面不变)、数据库迁移(up + 验证 schema + down + 测试可逆性)。
还有对抗性探测要求:
- Concurrency: 并行请求 create-if-not-exists → 有重复吗?
- Boundary: 0, -1, 空字符串, 超长字符串, unicode, MAX_INT
- Idempotency: 同一个 mutating 请求发两次 → 重复创建了吗?
- Orphan: 删除/引用不存在的 ID
最后有一条防止过度 FAIL 的规则:
Before reporting FAIL, check:
- Already handled: 其他地方有防御性代码吗?
- Intentional: CLAUDE.md 或注释说这是故意的吗?
- Not actionable: 这是不可修复的限制吗?
公正的验证不只是找 bug——也包括不冤枉正确的设计。
Coordinator 模式:纯调度器
当开启 Coordinator 模式时,Claude Code 完全变成一个调度器:
用户 ←→ Coordinator(分析、综合、沟通)
│
├── Worker A(研究)
├── Worker B(实现)
└── Worker C(验证)
角色分工
Coordinator 只有几个工具:
Agent— 启动 WorkerSendMessage— 给已有 Worker 发消息TaskStop— 停止偏离方向的 Worker
Coordinator 不写代码、不读文件、不执行命令。 它的全部工作是:理解用户需求 → 分析 Worker 的报告 → 撰写下一步指令 → 跟用户沟通。
四阶段工作流
| 阶段 | 谁做 | 目的 |
|---|---|---|
| Research | Workers(并行) | 调查代码库,理解问题 |
| Synthesis | Coordinator | 综合发现,制定实施计划 |
| Implementation | Workers | 按照 spec 改代码、commit |
| Verification | Workers | 测试改动是否正确 |
Synthesis 阶段是 Coordinator 最重要的职责。提示词反复强调:
Never write "based on your findings" or "based on the research."
These phrases delegate understanding to the worker instead of
doing it yourself.
如果你写 "基于你的调查结果,修复 auth bug"——这是偷懒。你应该写 "修复 src/auth/validate.ts:42 的空指针。Session 类型(src/auth/types.ts:15)的 user 字段在 session 过期但 token 仍被缓存时为 undefined。在 user.id 访问前加 null check——如果为 null,返回 401 'Session expired'。Commit 并报告 hash。"
理解是 Coordinator 的工作,不是 Worker 的。
并行是超能力
Parallelism is your superpower. Workers are async. Launch independent workers
concurrently whenever possible — don't serialize work that can run simultaneously.
Coordinator 的价值不在于它比 Worker 更聪明——而在于它能同时指挥多个 Worker 并行工作。研究阶段同时派出多个 Worker 调查不同方面,实现阶段按文件分组并行改动,验证阶段跟实现并行进行。
Continue vs. Spawn 决策
如果 Worker 已有的上下文对下一步有用 → SendMessage 继续它
如果下一步需要干净的开始 → 新启 Agent
继续 Worker 复用它已经建立的文件理解和上下文,省 token。但如果 Worker 的上下文已经偏离了下一步的方向,不如从头开始。
Swarm:物理层的并行
前面三种模式都是逻辑层的——多个 Agent 在进程级别并行。Swarm 是物理层的——每个 Agent 一个可视化的终端面板。
export const TEAM_LEAD_NAME = 'team-lead'
export const SWARM_SESSION_NAME = 'claude-swarm'
export const TMUX_COMMAND = 'tmux'
三种后端:
| 后端 | 环境 | 特点 |
|---|---|---|
| tmux | 任何终端 | 每个 teammate 一个 tmux pane |
| iTerm | macOS | 原生 iTerm tab |
| in-process | 任何环境 | 进程内运行,无可视化 |
每个 teammate 有自己的颜色标识(TEAMMATE_COLOR_ENV_VAR),可以在 tmux 的分割面板中实时看到每个 Agent 在做什么。
Swarm 还支持 PLAN_MODE_REQUIRED_ENV_VAR——要求 teammate 在实施之前先进入 Plan Mode 获得批准。这是一个安全约束:你可以看到每个 Agent 打算做什么,然后决定是否批准。
每个 Swarm session 用 PID 隔离(claude-swarm-${process.pid}),多个 Claude Code 实例不会互相干扰。
Agent 间通信:XML 协议
Worker 完成任务后,通过 <task-notification> XML 通知 Coordinator:
<task-notification>
<task-id>agent-a1b</task-id>
<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>8</tool_uses>
<duration_ms>12000</duration_ms>
</usage>
</task-notification>
这个通知被包装成 user-role message 注入 Coordinator 的对话——看起来像用户消息,但有 <task-notification> 标签标识。Coordinator 的系统提示词明确说:
Worker results arrive as user-role messages containing <task-notification> XML.
They look like user messages but are not. Distinguish them by the opening tag.
为什么用 XML 而不是 JSON?
推测:XML 的 tag 结构对 LLM 更友好。<task-notification> 和 <result> 这样的标签有明确的语义,模型不容易搞混。JSON 的花括号和引号在 LLM 的 token 表示中不如 XML 标签直觉。
Agent 列表外移:10.2% 的 Cache 优化
前面在架构篇提过,Agent 列表从 tool description 移到了 attachment message。这里详细说说为什么。
原来 AgentTool 的 description 包含所有可用 agent 类型的列表。问题是:
- MCP 服务器连接/断开 → agent 的工具集变化 → description 变化
- 权限模式切换 → agent 的可用性变化 → description 变化
- 用户配置了新的自定义 agent → description 变化
每次 description 变化,整个 tool schema 的 prompt cache 就失效。
// 注释原文:
// The dynamic agent list was ~10.2% of fleet cache_creation tokens
解决方案:shouldInjectAgentListInMessages() 控制是否把 agent 列表从 description 移到 conversation 中的 attachment。这样 tool schema 变成纯静态的——永远不变。
Agent 列表变成一个 agent_listing_delta attachment,只在列表真正变化时更新。而且 attachment 在消息历史的末尾,不影响前面的缓存前缀。
设计原则提炼
1. 缓存共享是多 Agent 系统的核心竞争力
Fork 的"零成本启动"完全依赖 prompt cache 共享。不是每个框架都有这个优势——这是 Anthropic 同时控制 API 和客户端的"垂直整合"红利。
2. Agent 的系统提示词就是它的灵魂
Explore Agent 的"只读侦探"、Verification Agent 的"对抗式破坏者"——每种 Agent 的行为完全由其系统提示词定义。好的 Agent 设计 = 好的提示词设计。
3. 理解不可委托
Coordinator 模式的核心原则:"never write based on your findings"。理解研究结果、综合信息、制定计划——这些是 Coordinator 的工作,不能偷懒甩给 Worker。
4. 对抗自己的弱点
Verification Agent 的系统提示词直接列出 AI 的经典失败模式,然后要求它"认出自己正在找借口"。这是一种元认知提示——不是说"请仔细验证",而是说"你会想偷懒,这是你偷懒的具体方式,识别并抵抗它"。
下一篇
Agent 编排讲完了。下一篇深入 Claude Code 的"大脑"——QueryEngine:46K 行的 LLM 调用核心。
流式响应解析、tool_use 循环、token 预算管理、消息标准化(5,500 行的 messages.ts)。以及一个 1,295 行的入口文件是怎么驱动整个 AI 交互循环的。
📚 CC解构系列
| 篇目 | 日期 | 主题 |
|---|---|---|
| 序 | 2026-03-31 | 一个 .map 文件的蝴蝶效应 |
| 第 1 篇 | 2026-04-01 | 380K 行代码的骨架 |
| 第 2 篇 | 2026-04-02 | 灵魂工程:System Prompt 的七层设计 |
| 第 3 篇 | 2026-04-03 | 40 个工具的统一抽象 |
| 第 4 篇 | 2026-04-04 | 用 LLM 审查 LLM:yoloClassifier 两阶段安全架构 |
| 第 5 篇 | 2026-04-05 | 三种并行模式:Fork、Coordinator、Swarm |
| 第 6 篇 | 2026-04-06 | QueryEngine:46K 行的 LLM 核心引擎 |
| ... | ... | 持续更新 |

![[CC解构] 三种并行模式:Fork、Coordinator、Swarm](/claude-code-agent-orchestration/cover.jpg)