编排逻辑 — 系统提示词驱动的主从协作模式
编排逻辑 — 系统提示词驱动的主从协作模式
源码路径:
/mnt/e/code/cc/claude-code-main/src/coordinator/coordinatorMode.ts核心文件:coordinatorMode.ts,builtInAgents.ts,AgentTool.tsx技术栈:系统提示词 + AsyncLocalStorage + Team/SendMessage 工具
1. 概述:为什么不用硬编码算法
传统的多智能体系统往往通过复杂的硬编码状态机来管理任务分配、结果聚合与流程控制。Claude Code 的做法截然不同:编排逻辑几乎完全卸载到系统提示词中,coordinatorMode.ts 导出的核心函数只有:
getCoordinatorSystemPrompt()— 返回协调者系统提示词getCoordinatorUserContext()— 注入工人工具上下文isCoordinatorMode()— 模式开关matchSessionMode()— 会话恢复时的模式对齐
这种设计的精妙之处在于:LLM 本身就擅长理解指令、执行流程和做决策。将"何时分发任务"“何时等待"“何时聚合"这些逻辑用自然语言描述,比用 if-else 状态机更灵活、更易于迭代。
2. 架构总览
┌────────────────────────────────────────────────────────────────────┐
│ User Session │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Coordinator (主控 Agent) │ │
│ │ 系统提示词定义了:角色、工具集、工作流、Worker 通信协议 │ │
│ │ │ │
│ │ 工具集: │ │
│ │ • AgentTool ──────→ Spawn Worker │ │
│ │ • SendMessageTool ─→ Continue Worker │ │
│ │ • TaskStopTool ────→ Stop Worker │ │
│ │ │ │
│ │ 工作流: │ │
│ │ Research ──→ Synthesis ──→ Implement ──→ Verify │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┼──────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Worker A │ │ Worker B │ │ Worker C │ │
│ │(Research)│ │(Research)│ │(Implement)│ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └─────────────────────────┴──────────────────────────┘ │
│ │ │
│ <task-notification> XML 消息回调 │
│ │ │
└──────────────────────────────────┼────────────────────────────────────┘
│
coordinatorMode.ts 的系统提示词驱动3. 入口控制:如何进入协调者模式
3.1 特性开关
// src/coordinator/coordinatorMode.ts
export function isCoordinatorMode(): boolean {
if (feature('COORDINATOR_MODE')) {
return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
}
return false
}两个条件同时满足才进入协调者模式:
- GrowthBook 特性开关
COORDINATOR_MODE开启 - 环境变量
CLAUDE_CODE_COORDINATOR_MODE=1设置
这提供了三层控制:
- 管理员可通过 GrowthBook 对特定用户/实验组开启
- 用户可通过环境变量自行启用
- 会话恢复时通过
matchSessionMode()自动对齐
3.2 会话恢复时的模式对齐
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
}
logEvent('tengu_coordinator_mode_switched', { to: sessionMode })
}3.3 Worker 工具上下文注入
export function getCoordinatorUserContext(
mcpClients: ReadonlyArray<{ name: string }>,
scratchpadDir?: string,
): { [k: string]: string } {
if (!isCoordinatorMode()) return {}
const workerTools = isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)
? [BASH_TOOL_NAME, FILE_READ_TOOL_NAME, FILE_EDIT_TOOL_NAME].sort().join(', ')
: Array.from(ASYNC_AGENT_ALLOWED_TOOLS)
.filter(name => !INTERNAL_WORKER_TOOLS.has(name))
.sort().join(', ')
let content = `Workers spawned via the ${AGENT_TOOL_NAME} tool have access to these tools: ${workerTools}`
if (mcpClients.length > 0) {
const serverNames = mcpClients.map(c => c.name).join(', ')
content += `\n\nWorkers also have access to MCP tools from connected MCP servers: ${serverNames}`
}
if (scratchpadDir && isScratchpadGateEnabled()) {
content += `\n\nScratchpad directory: ${scratchpadDir}\nWorkers can read and write here without permission prompts. Use this for durable cross-worker knowledge — structure files however fits the work.`
}
return { workerToolsContext: content }
}支持两种 Worker 工具集:
- SIMPLE 模式:仅 Bash、Read、Edit(适合受限场景)
- 完整模式:所有
ASYNC_AGENT_ALLOWED_TOOLS(除内部工具)
4. 核心系统提示词详解
4.1 角色定义
// src/coordinator/coordinatorMode.ts (行 116-126)
return `You are Claude Code, an AI assistant that orchestrates software engineering tasks across multiple workers.
## 1. Your Role
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
Every message you send is to the user. Worker results and system notifications are internal signals, not conversation partners — never thank or acknowledge them. Summarize new information for the user as it arrives.
`关键约束:
- Worker 结果不是对话伙伴 — 不感谢、不确认,像处理系统通知一样处理
- 自己能做的就不委托 — 避免过度工程化
- 持续向用户汇报 — 保持透明,不让用户等待
4.2 工具集与调用约束
// 行 128-140
## 2. Your Tools
- **AgentTool** - Spawn a new worker
- **SendMessageTool** - Continue an existing worker (send a follow-up to its `to` agent ID)
- **TaskStopTool** - Stop a running worker
- **subscribe_pr_activity / unsubscribe_pr_activity** (if available) - Subscribe to GitHub PR events
When calling AgentTool:
- Do not use one worker to check on another. Workers will notify you when they are done.
- Do not use workers to trivially report file contents or run commands. Give them higher-level tasks.
- Do not set the model parameter. Workers need the default model for the substantive tasks you delegate.
- Continue workers whose work is complete via SendMessageTool to take advantage of their loaded context
- After launching agents, briefly tell the user what you launched and end your response. Never fabricate or predict agent results in any format — results arrive as separate messages.调用约定是最重要的工程约束之一:
- 不设 model 参数 — Worker 默认使用主模型,确保能力一致
- 不预测结果 — Agent 结果通过
<task-notification>异步到达 - Launch 后立即告知用户 — 保持 UX 流畅
4.3 任务通知格式
Worker 完成时,主控收到的不是普通消息,而是一个特殊的 <task-notification> 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>主控 Agent 被训练识别这个格式:
<task-id>作为SendMessageTool的to参数继续该 Worker<result>包含 Worker 的最终文本响应<usage>记录资源消耗(用于监控和成本控制)
4.4 工作流四阶段
// 行 198-218
## 4. Task Workflow
Most tasks can be broken down into the following phases:
### Phases
| Phase | Who | Purpose |
|-------|-----|---------|
| Research | Workers (parallel) | Investigate codebase, find files, understand problem |
| Synthesis | **You** (coordinator) | Read findings, understand the problem, craft implementation specs |
| Implementation | Workers | Make targeted changes per spec, commit |
| Verification | Workers | Test changes work |
### Concurrency
**Parallelism is your superpower. Workers are async. Launch independent workers concurrently whenever possible — don't serialize work that can run simultaneously and look for opportunities to fan out.**四阶段分工清晰:
- Research — 并行探索,充分利用异步能力
- Synthesis — 主控亲自做,必须理解 Worker 的发现才能写好实现 spec
- Implementation — 写文件、跑测试、commit
- Verification — 独立验证,不是重跑实现者的测试
4.5 验证的真正含义
// 行 220-227
### What Real Verification Looks Like
Verification means **proving the code works**, not confirming it exists. A verifier that rubber-stamps weak work undermines everything.
- Run tests **with the feature enabled** — not just "tests pass"
- Run typechecks and **investigate errors** — don't dismiss as "unrelated"
- Be skeptical — if something looks off, dig in
- **Test independently** — prove the change works, don't rubber-stamp这段提示词直接针对"验证惰性"这个常见问题给出了具体指导。
5. Worker 提示词工程
这是协调者模式中最精华的部分——如何写出高质量的 Worker 指令。
5.1 必须合成(Synthesize)
// 行 253-270
### Always synthesize — your most important job
When workers report research findings, **you must understand them before directing follow-up work**.反模式:
AgentTool({ prompt: "Based on your findings, fix the auth bug", ... })
AgentTool({ prompt: "The worker found an issue in the auth module. Please fix it.", ... })好模式:
AgentTool({ prompt: "Fix the null pointer in src/auth/validate.ts:42. The user field on Session (src/auth/types.ts:15) is undefined when sessions expire but the token remains cached. Add a null check before user.id access — if null, return 401 with 'Session expired'. Commit and report the hash.", ... })关键:不要把理解工作委托给 Worker。Coordinator 必须先理解发现,再写出包含具体文件路径、行号和变更细节的指令。
5.2 Continue vs. Spawn 的决策矩阵
// 行 280-293
| Situation | Mechanism | Why |
|-----------|-----------|-----|
| Research explored exactly the files that need editing | **Continue** (SendMessageTool) | Worker already has the files in context |
| Research was broad but implementation is narrow | **Spawn fresh** | Avoid dragging along exploration noise |
| Correcting a failure or extending recent work | **Continue** | Worker has the error context |
| Verifying code a different worker just wrote | **Spawn fresh** | Verifier should see the code with fresh eyes |
| First attempt used wrong approach entirely | **Spawn fresh** | Wrong-approach context pollutes retry |
| Completely unrelated task | **Spawn fresh** | No useful context to reuse |这是一个非常务实的决策表——没有绝对的规则,只有基于上下文重叠度的判断。
5.3 Worker 提示词最佳实践
// 行 308-335
**Good examples:**
1. Implementation: "Fix the null pointer in src/auth/validate.ts:42. The user field can be undefined when the session expires. Add a null check and return early with an appropriate error. Commit and report the hash."
2. Precise git operation: "Create a new branch from main called 'fix/session-expiry'. Cherry-pick only commit abc123 onto it. Push and create a draft PR targeting main. Add anthropics/claude-code as reviewer. Report the PR URL."
3. Correction (continued worker, short): "The tests failed on the null check you added — validate.test.ts:58 expects 'Invalid session' but you changed it to 'Session expired'. Fix the assertion. Commit and report the hash."
**Bad examples:**
1. "Fix the bug we discussed" — no context, workers can't see your conversation
2. "Based on your findings, implement the fix" — lazy delegation
3. "Create a PR for the recent changes" — ambiguous scope
4. "Something went wrong with the tests, can you look?" — no error message好提示词的共性:具体到文件路径和行号、定义完成标准、给出错误示例。
6. Worker 管理生命周期
6.1 Spawn — 启动 Worker
// AgentTool.tsx 行 282-300
if (teamName && name) {
// 团队成员 Spawn 路径
const result = await spawnTeammate({ name, prompt, team_name, ... }, toolUseContext)
return { data: { teammate_id: result.teammateId, ... } }
}协调者模式下的 Worker 通过 AgentTool 启动,subagent_type 为 worker。
6.2 SendMessage — 继续 Worker
// AgentTool.tsx 行 681-686
const effectiveType = subagent_type ?? (isForkSubagentEnabled() ? undefined : GENERAL_PURPOSE_AGENT.agentType)
const isForkPath = effectiveType === undefined
// Worker 通过 SendMessageTool 继续
Worker 完成 Research 后,Coordinator 用 SendMessageTool 向其发送实现指令,利用 Worker 已加载的上下文。
6.3 TaskStop — 停止 Worker
// coordinatorMode.ts 行 237-249
// Use TaskStopTool to stop a worker you sent in the wrong direction
${AGENT_TOOL_NAME}({ description: "Refactor auth to JWT", prompt: "..." })
// ... returns task_id: "agent-x7q" ...
// User clarifies: "keep sessions — just fix the null pointer"
${TASK_STOP_TOOL_NAME}({ task_id: "agent-x7q" })
// Continue with corrected instructions
${SEND_MESSAGE_TOOL_NAME}({ to: "agent-x7q", message: "Stop the JWT refactor. Instead..." })停止 ≠ 丢弃——停止后的 Worker 仍可继续,只需换一套指令。
6.4 失败处理
// 行 229-233
### Handling Worker Failures
When a worker reports failure (tests failed, build errors, file not found):
- Continue the same worker with SendMessageTool — it has the full error context
- If a correction attempt fails, try a different approach or report to the user失败处理的策略:
- 继续同一个 Worker — 它有完整的错误上下文
- 换思路或上报用户 — 两次失败后不再原地打转
7. 完整协作会话示例
// 行 337-368
User: "There's a null pointer in the auth module. Can you fix it?"
You:
Let me investigate first.
AgentTool({ description: "Investigate auth bug", subagent_type: "worker", prompt: "Investigate the auth module in src/auth/. Find where null pointer exceptions could occur around session handling and token validation... Do not modify files." })
AgentTool({ description: "Research auth tests", subagent_type: "worker", prompt: "Find all test files related to src/auth/. Report the test structure, what's covered, and any gaps..." })
Investigating from two angles — I'll report back with findings.
User: (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. The user field on Session is undefined when the session expires but ...</result>
You:
Found the bug — null pointer in validate.ts:42.
SendMessageTool({ to: "agent-a1b", message: "Fix the null pointer in src/auth/validate.ts:42. Add a null check before accessing user.id — if null, return 401... Commit and report the hash." })
Fix is in progress.注意:所有 “You:” 都是协调者回复,所有 “User:” 都是 <task-notification>(系统消息,不是用户输入)。
8. 关键设计洞察
8.1 提示词即架构
整个协调者模式的"业务逻辑"都在 getCoordinatorSystemPrompt() 返回的字符串中:
- 角色定义 → 分工边界
- 工具约束 → 能力边界
- 工作流阶段 → 流程控制
- 决策矩阵 → 路由逻辑
如果要改协调策略?改提示词就行,无需改代码。
8.2 状态外部化
协调者不需要维护"当前有哪些 Worker 在运行"“谁完成了什么"这类状态——这些信息通过 <task-notification> 实时流入。协调者每次回复都是基于最新状态做决策。
8.3 上下文传递协议
Worker 无法看到主控与用户的对话。每个 Worker prompt 必须是自包含的,包含:
- 具体文件路径和行号
- 完整的上下文(不是"基于你的发现”)
- 明确的完成标准
这是整个系统最容易被破坏的接口——Coordinator 必须 discipline 自己不偷懒。
8.4 SIMPLE 降级模式
通过 CLAUDE_CODE_SIMPLE=1 环境变量,Worker 工具集可降级为仅 Bash/Read/Edit,适用于:
- MCP 服务器受限环境
- 安全性要求更高的场景
- 调试和问题定位
9. 与其他协作模式的关系
┌─────────────────────────────────────────────────────────┐
│ AgentTool 路由 │
├─────────────────────────────────────────────────────────┤
│ │
│ team_name + name ──────→ spawnTeammate (团队成员模式) │
│ │
│ subagent_type = "worker" ──→ Coordinator Worker │
│ │
│ subagent_type = "Explore/Plan" ──→ 内置专业 Agent │
│ │
│ subagent_type = "fork" ──────→ Fork 分支子代理 │
│ │
│ subagent_type = undefined ──→ general-purpose Agent │
│ │
└─────────────────────────────────────────────────────────┘协调者模式只是 AgentTool 多种工作模式之一。它与其他模式的核心区别在于:
- 团队成员模式:多个 Agent 平等协作,通过 SendMessage 通信
- 协调者模式:主从架构,主控负责任务分配与结果聚合
- Fork 模式:分支上下文并行探索,无中心协调
10. 核心文件索引
| 文件 | 职责 |
|---|---|
src/coordinator/coordinatorMode.ts | 协调者系统提示词、模式开关、上下文注入 |
src/tools/AgentTool/builtInAgents.ts | 协调者模式下动态加载 Worker Agent 定义 |
src/tools/AgentTool/AgentTool.tsx | AgentTool 入口,路由到 spawn/worker/fork 路径 |
src/tools/SendMessageTool/ | 向 Worker 发送后续指令 |
src/tools/TaskStopTool/ | 停止运行中的 Worker |
文档版本:v1.0 | 更新:2026-04-06