Claude Code 的多智能体系统由三个递进层级构成:单次 Subagent(轻量委托)→Fork Subagent(上下文克隆分身)→Swarm / Team(多进程协作群)。它们共享同一个runAgent()核心,但在隔离策略、通信方式和生命周期上各有不同。
1. 三种模式一览
| 特性 | 普通 Subagent | Fork Subagent | Swarm Teammate |
|---|---|---|---|
| 触发方式 | Agent(subagent_type=X) | Agent()不带subagent_type | Agent(name=X, team_name=Y) |
| 上下文继承 | 空 / 只从 prompt 开始 | 完整克隆父对话 + 工具结果 | 独立进程,仅通过 mailbox 通信 |
| 运行位置 | 父进程内(sync/async) | 父进程内,后台异步 | 子进程(tmux/iTerm2)或 in-process |
| AbortController | sync: 共享父的; async: 独立 | 独立 | 独立(不受领导者中断影响) |
| 权限提示 | async: 自动拒绝; sync: 气泡到父 | bubble → 气泡到父终端 | 通过 permissionSync 文件路由 |
| 通信机制 | 返回值 / Generator yield | 父 context 注入 + 返回值 | 文件信箱(mailbox) |
| sidechain 转录 | ✅ | ✅ | ✅ |
| 门控条件 | 默认启用 | feature('FORK_SUBAGENT') | isAgentSwarmsEnabled() |
2. Subagent(普通子代理)
2.1 实体:runAgent()异步生成器
src/tools/AgentTool/runAgent.ts的核心是一个AsyncGenerator,外部通过for await消费其输出消息,实现流式透传。
关键设计决策:
parent → AgentTool.call() ├── 构建 agentToolUseContext(独立 AppState 视图) ├── resolveAgentTools() ← 按定义过滤工具集 ├── getAgentSystemPrompt() ← 专属系统提示词 ├── createSubagentContext() ← 上下文隔离 └── runAgent() → query() ← 流式游历 API 轮次 ↓ yield messages → agentToolUtils.runAsyncAgentLifecycle()权限模式继承规则(优先级从高到低):
bypassPermissions/acceptEdits/auto— 父级总是赢,子代理不可覆盖agentDefinition.permissionMode— 定义文件中的声明isAsync=true→shouldAvoidPermissionPrompts=true(不弹 UI)canShowPermissionPrompts=true→awaitAutomatedChecksBeforeDialog=true(先等自动化检查)
Claude.md 裁剪优化:
Explore / Plan 等只读代理默认剥除claudeMd(省 ~5-15 Gtok/week)和gitStatus(节省上下文),通过 GrowthBook 门控tengu_slim_subagent_claudemd。
2.2 工具集解析resolveAgentTools()
agentDefinition.tools: ['*'] → 继承父工具集 agentDefinition.tools: ['Bash','Edit'] → 精确子集 agentDefinition.tools: ['!Bash'] → 排除模式 useExactTools=true → 完全跳过过滤(fork 路径专用)allowedTools参数在作用域上替换父级 session 权限(保留 cliArg 层),避免父级许可泄漏给子代理。
2.3 生命周期 finally 清理
runAgent()的finally块确保即使抛出 AbortError 也执行:
- MCP 服务器关闭(
mcpCleanup()) - Session hooks 清理(
clearSessionHooks()) - Prompt cache 追踪状态清理
- 文件状态缓存释放(
readFileState.clear()) - Todos 孤立条目删除
- 后台 Bash 进程杀死(
killShellTasksForAgent()) - Perfetto trace 注销
3. Fork Subagent(分叉子代理)
3.1 设计理念
Fork 是上下文克隆模式:子代理不是从空白对话开始,而是继承父对话的完整消息历史。核心思路是最大化利用父代理的prompt cache——子代理与父代理共享相同的 API 请求前缀,命中缓存的概率极高。
启用条件:
// 互斥约束:不能与 coordinator 模式共用feature('FORK_SUBAGENT')&&!isCoordinatorMode()&&!isNonInteractiveSession()3.2 消息构建buildForkedMessages()
父 AssistantMessage(含所有 tool_use 块) ↓ clone [fullAssistantMessage] + user 消息: [tool_result x N (全为 FORK_PLACEHOLDER)] ← 占位符让 API 认为工具已完成 + text: <fork_directive>子任务说明</fork_directive>FORK_PLACEHOLDER_RESULT是固定字符串(保证 cache 命中),子代理看到的是已有工具结果和新指令。
3.3useExactTools=true稳定化
Fork 模式传useExactTools=true:
- 直接使用父工具池,不经
resolveAgentTools()过滤 - 继承父的
thinkingConfig(思维链设置) - 继承父的
isNonInteractiveSession值 - 目的:让子代理的 API 请求前缀与父代理字节完全一致,命中 server-side prompt cache
3.4 递归 Fork 防护
// 双重检查,对抗 autocompact 改写消息后的 bypassif(toolUseContext.options.querySource===`agent:builtin:${FORK_AGENT.agentType}`||isInForkChild(toolUseContext.messages)){thrownewError('Fork is not available inside a forked worker.')}4. Swarm(群集多代理)
4.1 架构概览
Leader Process(claude REPL) │ ├── TeamFile (.claude/teams/{team}/team.json) │ members: [{ agentId, agentName, color, backendType, paneId, ... }] │ ├── Mailbox (.claude/teams/{team}/inboxes/{agent_name}.json) │ 用于 peer DM、权限请求、shutdown、idle 通知 │ ├── Backend(运行时自动选择) │ ├── tmux → 创建 tmux pane,发 claude CLI 命令 │ ├── iterm2 → it2 split pane │ └── in-process → AsyncLocalStorage 隔离,同进程运行 │ └── Leader Permission Bridge(leaderPermissionBridge.ts) module-level 全局 setter → 允许 in-process 队友使用 leader 的权限对话框4.2 后端选择策略(registry.ts)
优先级从高到低:
- tmux— 在 tmux 会话中且 tmux 可用
- iterm2— 在 iTerm2 中且
it2CLI 已安装 - in-process— 兜底(无终端分栏依赖)
选择结果在进程生命周期内固定缓存(cachedBackend)。
4.3 TeamFile:持久化团队状态
路径:~/.claude/teams/{team_name}/team.json
typeTeamFile={leadAgentId:string// 唯一领导者members:TeamMember[]// 包含 paneId、backendType、agentIdhiddenPaneIds:PaneId[]// 支持 hide/showallowedPaths:TeamAllowedPath[]// 权限沙盒}写操作均通过lockfile序列化,防止并发的多个 Claude 进程竞争写:
constLOCK_OPTIONS={retries:{retries:10,minTimeout:5,maxTimeout:100}}4.4 文件信箱(Mailbox)通信协议
路径:~/.claude/teams/{team}/inboxes/{agent_name}.json
消息格式:
typeTeammateMessage={from:string// 发送者名称text:string// 消息内容timestamp:stringread:booleancolor?:string// 发送者颜色(UI 显示用)summary?:string// 5-10 字摘要(预览用)}消息类型(teammateMailbox.ts):
| 消息类型 | 方向 | 用途 |
|---|---|---|
peer_dm | 任意→任意 | SendMessageTool 的 DM |
permission_request | worker→leader | 权限请求路由 |
permission_response | leader→worker | 权限决策回传 |
shutdown_request | leader→worker | 优雅关闭 |
idle_notification | worker→leader | 完成通知 |
sandbox_permission_request/response | worker↔leader | 沙盒权限 |
写操作原子性:通过lockfile包,10 次重试 + 指数退避,防止 N 个并发 Claude 进程同时写同一收件箱。
4.5 权限同步机制(permissionSync.ts)
Worker 遇到需要确认的工具调用 │ ├─ [in-process 路径] │ leader 的 ToolUseConfirm 队列(内存 setter) │ ← leaderPermissionBridge.getLeaderToolUseConfirmQueue() │ └─ [pane 路径] worker → writeToMailbox(leader, permission_request) │ leader 轮询检测 → UI 弹出确认对话框 │ leader → writeToMailbox(worker, permission_response) │ worker 轮询收到决策 → 继续 / 拒绝轮询间隔:PERMISSION_POLL_INTERVAL_MS = 500ms,由useSwarmPermissionPollerhook 驱动。
4.6 In-Process Teammate 隔离
通过AsyncLocalStorage实现同进程内的上下文隔离:
spawnInProcessTeammate() ├── createAbortController() ← 独立中止(不受领导者影响) ├── createTeammateContext() ← AsyncLocalStorage 上下文 ├── registerTask(taskState, setAppState) ← 在 AppState 中注册显示 └── startInProcessTeammate() ← runWithTeammateContext() 包裹 └── runAgent() 在隔离上下文中执行优点:无需额外进程,共享 API 连接和 MCP 服务器。
缺点:崩溃会影响主进程;不支持从 in-process teammate 内部再派生后台代理(限制:“In-process teammates cannot spawn background agents”)。
5. Coordinator 模式
COORDINATOR_MODE是另一套协调架构,与 Fork 互斥:
CLAUDE_CODE_COORDINATOR_MODE=1 → isCoordinatorMode() ├── getCoordinatorSystemPrompt() ← 专属系统提示词 ├── getCoordinatorUserContext() ← 专属用户上下文 ├── INTERNAL_WORKER_TOOLS ← 仅限内部工具集 └── 禁用 Fork subagent设计目标:Coordinator 是轻量级调度者,不直接执行工具,而是向 worker 发任务;与 Fork(克隆并行)策略相对。
6. 通信流汇总
┌─────────────────────────────────────────────────────────┐ │ Leader REPL │ │ ┌─────────────────────────────────────────────────┐ │ │ │ Mailbox Poller(500ms 轮询) │ │ │ │ · 收取 peer_dm → 注入为 attachment 消息 │ │ │ │ · 收取 permission_request → 弹 UI 对话框 │ │ │ │ · 收取 idle_notification → Task 状态更新 │ │ │ └─────────────────────────────────────────────────┘ │ │ ↕ 内存信号 │ │ ┌──────────────────────────────────────────────────┐ │ │ │ In-Process Teammate(AsyncLocalStorage 隔离) │ │ │ │ permission via leaderPermissionBridge (内存 fn) │ │ │ └──────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ↕ 文件 I/O(mailbox + lockfile) ┌──────────────────────────────────────────────────────────┐ │ Pane Teammate(独立进程) │ │ claude CLI 以环境变量指定 team/agent 信息 │ │ · CLAUDE_CODE_AGENT_ID / NAME / TEAM_NAME / COLOR │ │ · CLAUDE_CODE_LEADER_AGENT_ID │ └──────────────────────────────────────────────────────────┘7. 设计亮点
7.1 Prompt Cache 最大化(Fork 设计)
Fork 子代理通过useExactTools=true+ 固定 placeholder result 确保 API 请求前缀与父代理字节完全一致,最大化 server-side prompt cache 命中率。这是性能优化的核心。
7.2 工具权限隔离(allowedTools 替换语义)
parent session rules: [A, B, C] 子代理 allowedTools: [X, Y] → 子代理实际拥有: [cliArg rules, X, Y]父级 session 允许的工具不会自动泄漏给子代理,必须显式传递。cliArg层(SDK--allowedTools)始终保留,因为这是外部用户的显式意图。
7.3 文件信箱 + lockfile 并发安全
多个 Claude 进程可同时写同一信箱,通过lockfile的重试+指数退避实现可靠串行化。比共享内存队列更健壮(跨进程),比数据库更轻量。
7.4 Backend 抽象层(TeammateExecutor接口)
interfaceTeammateExecutor{spawn(config:TeammateSpawnConfig):Promise<TeammateSpawnResult>sendMessage(agentId,message):Promise<void>kill(agentId):Promise<void>}统一接口屏蔽 tmux / iTerm2 / in-process 差异,注册模式(registerTmuxBackend())避免循环依赖。
7.5 sidechain 转录(每个代理独立 JSONL)
每个子代理把消息写入subagents/{agentId}.jsonl,支持会话恢复和调试查看,且使用增量追加(lastRecordedUuid游标),不重写历史。
7.6 Claude.md 精简(读写代理分级优化)
只读代理(Explore、Plan)自动剥除 claudeMd 和 gitStatus,节省大量 token。按agentDefinition.omitClaudeMd字段在代理定义文件中声明,kill-switch 通过 GrowthBook 控制。
8. 可直接复用的设计模式
8.1 文件信箱(Mailbox + lockfile)
场景:多进程 / 多 worker 异步通信,且不想引入消息队列中间件。
// 写:序列化写,带重试退避awaitlockfile.lock(path,opts)constmsgs=JSON.parse(awaitreadFile(path))msgs.push(newMsg)awaitwriteFile(path,JSON.stringify(msgs))lockfile.unlock(path)// 读:轮询 + 标记已读constmsgs=readMailbox(agentName)constunread=msgs.filter(m=>!m.read)8.2 权限决策气泡(bubble permission mode)
场景:子任务需要弹 UI,但希望对话框出现在主进程终端而非子进程。
permissionMode: 'bubble'+leaderPermissionBridgesetter 注册- Pane 路径:mailbox 双向路由
8.3 AsyncLocalStorage 上下文隔离
场景:同进程并发运行多个"租户",每个租户有独立的 agentId、teamName、color 等上下文。
constteammateContext=newAsyncLocalStorage<TeammateContext>()runWithTeammateContext(ctx,()=>runAgent(...))// 在任意调用深度取上下文:getTeamName()→ teammateContext.getStore()?.teamName8.4 Generator 流式 + 终止信号
asyncfunction*runAgent(...):AsyncGenerator<Message>{constcontroller=isAsync?newAbortController():parent.abortControllerforawait(constmsgofquery({signal:controller.signal})){yieldmsg// 流式透传}if(controller.signal.aborted)thrownewAbortError()}消费方调用break即可中止,不需要手动清理——finally块统一清理。
8.5 懒加载工具 Schema(lazySchema())
constinputSchema=lazySchema(()=>z.object({...}))// 首次访问时才构建 Zod schema,配合 feature() 门控避免在模块加载阶段就执行条件feature()检查(build-time DCE 友好)。
8.6 Backend 注册模式(避免循环依赖)
// registry.tsletTmuxBackendClass:(new()=>PaneBackend)|null=nullexportfunctionregisterTmuxBackend(cls:new()=>PaneBackend){TmuxBackendClass=cls}// TmuxBackend.ts(在模块末尾)registerTmuxBackend(TmuxBackend)Backend 实现文件负责向 registry 注册自己,registry 不直接 import 实现,打破循环依赖。
9. 源码索引
| 职责 | 文件 |
|---|---|
| Agent 工具入口 | src/tools/AgentTool/AgentTool.tsx |
| 子代理运行核心 | src/tools/AgentTool/runAgent.ts |
| Fork 消息构建 | src/tools/AgentTool/forkSubagent.ts |
| TeamFile & 锁 | src/utils/swarm/teamHelpers.ts |
| 权限同步 | src/utils/swarm/permissionSync.ts |
| 领导者权限桥 | src/utils/swarm/leaderPermissionBridge.ts |
| In-process 运行器 | src/utils/swarm/inProcessRunner.ts |
| In-process 生成 | src/utils/swarm/spawnInProcess.ts |
| 文件信箱 | src/utils/teammateMailbox.ts |
| 内存信箱 | src/utils/mailbox.ts |
| 后端接口 | src/utils/swarm/backends/types.ts |
| 后端注册表 | src/utils/swarm/backends/registry.ts |
| Swarm 门控 | src/utils/agentSwarmsEnabled.ts |
| Coordinator 模式 | src/coordinator/coordinatorMode.ts |
| 通信时序图 | agent-swarm-communication.puml |