主题
Claude Code SubAgent 深度调研
一、概述
Claude Code 的 SubAgent(子智能体)系统是其多智能体架构的核心。当主 Agent(父 Agent)遇到适合委派的任务时——如代码搜索、验证检查、并行编辑——它通过调用 Agent Tool(旧名 Task)来生成一个完全独立的子 Agent。子 Agent 拥有独立的对话循环、工具集、权限边界和中止控制器,完成工作后仅返回最终结果,父 Agent 看不到子 Agent 的内部推理过程。
核心设计理念: "Less scaffolding, more model"——信任模型的推理能力,而非构建复杂的编排系统。
二、核心架构
2.1 三层架构
Primary Agent(父 Agent)
│
├── spawn ──► SubAgent-1(独立上下文窗口)──► 返回结果
├── spawn ──► SubAgent-2(独立上下文窗口)──► 返回结果
├── spawn ──► SubAgent-3(独立上下文窗口)──► 返回结果
└── 合并/综合结果2.2 核心设计原则
| 原则 | 说明 |
|---|---|
| 上下文隔离 | 每个 SubAgent 拥有独立的 200K token 上下文窗口,防止父 Agent 被中间结果淹没 |
| 并行执行 | 最多同时运行 10 个 SubAgent,支持 Fan-out/Fan-in 模式 |
| 工具专用化 | 不同 Agent 类型根据角色拥有特定工具集 |
| 结果聚合 | SubAgent 仅返回单条摘要消息,保持父 Agent 上下文干净 |
| 后台执行 | SubAgent 可在后台运行,不阻塞父 Agent 的工作 |
2.3 核心源码文件
子智能体系统的编排层跨越约 40 个文件,分布在以下目录:
| 文件/目录 | 职责 |
|---|---|
tools/AgentTool/AgentTool.tsx | 模型面向的工具接口,包含路由决策树 |
tools/AgentTool/runAgent.ts | 子 Agent 的 15 步生命周期实现(约 400 行) |
tools/AgentTool/builtInAgents.ts | 内置 Agent 类型注册 |
tools/SendMessageTool/ | Agent 间通信 |
tasks/ | 任务状态管理 |
coordinator/ | 协调器模式 |
utils/swarm/ | 多智能体集群 |
utils/forkedAgent.ts | SubAgent 上下文创建 |
loadAgentsDir.ts | 自定义 Agent 加载 |
三、AgentTool 定义
3.1 输入参数 Schema
AgentTool 注册名为 "Agent",保留旧别名 "Task" 以向后兼容。Schema 通过 lazySchema() 延迟编译,分为基础字段和扩展字段两层:
基础字段(始终存在):
| 字段 | 类型 | 必填 | 用途 |
|---|---|---|---|
description | string | 是 | 3-5 词的任务摘要 |
prompt | string | 是 | 完整的任务描述 |
subagent_type | string | 否 | 指定使用哪种特化 Agent |
model | enum('sonnet','opus','haiku') | 否 | 模型覆盖 |
run_in_background | boolean | 否 | 异步启动 |
扩展字段(多 Agent 模式激活时):
| 字段 | 类型 | 用途 |
|---|---|---|
name | string | 使 Agent 可通过 SendMessage({to: name}) 寻址 |
team_name | string | 团队上下文 |
mode | PermissionMode | 权限模式 |
isolation | enum('worktree','remote') | 文件系统隔离策略 |
cwd | string | 工作目录覆盖 |
关键设计: Schema 由功能开关动态塑形。模型看不到它不该使用的字段——"移除字段比在提示词中写'不要使用此字段'更有效"。
3.2 输出 Schema
输出是带判别的联合类型:
{ status: 'completed', prompt, ...AgentToolResult }— 同步完成,返回最终输出{ status: 'async_launched', agentId, description, prompt, outputFile }— 异步启动确认
async_launched 中包含 outputFile 路径,父 Agent 可轮询或监听该文件获取结果,提供了一个基于文件系统的通信通道,甚至能跨进程重启存活。
3.3 call() 路由决策树
在 runAgent() 被调用之前,call() 方法先完成路由:
1. 是否是 teammate 生成?(team_name + name 都设置了)
YES → spawnTeammate() → 返回 teammate_spawned
NO → 继续
2. 解析有效 Agent 类型
- 提供了 subagent_type → 使用它
- 未提供且 fork 启用 → undefined(fork 路径)
- 未提供且 fork 未启用 → "general-purpose"(默认)
3. 是否是 fork 路径?(effectiveType === undefined)
YES → 递归 fork 守卫检查 → 使用 FORK_AGENT 定义
4. 从 activeAgents 列表解析 Agent 定义
- 按权限 deny 规则过滤
- 按 allowedAgentTypes 过滤
- 未找到或被拒绝则抛错
5. 检查所需 MCP 服务器(等待最多 30 秒)
6. 解析隔离模式(参数覆盖 Agent 定义)
- "remote" → teleportToRemote() → 返回 remote_launched
- "worktree" → createAgentWorktree()
- null → 正常执行
7. 判断同步 vs 异步
shouldRunAsync = run_in_background || selectedAgent.background ||
isCoordinator || forceAsync || isProactiveActive
8. 组装 worker 工具池
9. 构建系统提示词和提示消息
10. 执行(异步 → registerAsyncAgent + void lifecycle; 同步 → 迭代 runAgent)四、runAgent 15 步生命周期
runAgent() 是一个异步生成器(async generator),驱动子 Agent 的完整生命周期。所有子 Agent——fork、内置、自定义、coordinator worker——都流经这同一个函数。
函数签名(17 个参数)
typescript
export async function* runAgent({
agentDefinition, // 什么类型的 Agent
promptMessages, // 告诉它什么
toolUseContext, // 父 Agent 的执行上下文
canUseTool, // 权限回调
isAsync, // 后台还是阻塞?
canShowPermissionPrompts,
forkContextMessages, // 父 Agent 的历史(仅 fork)
querySource, // 来源追踪
override, // 系统提示、中止控制器、Agent ID 覆盖
model, // 调用方的模型覆盖
maxTurns, // 轮次限制
availableTools, // 预组装的工具池
allowedTools, // 权限范围
onCacheSafeParams, // 后台摘要的回调
useExactTools, // fork 路径:使用父 Agent 的精确工具
worktreePath, // 隔离目录
description, // 人类可读的任务描述
}: { ... }): AsyncGenerator<Message, void>15 步详解
Step 1: 模型解析
解析链:调用方覆盖 > Agent 定义 > 父 Agent 模型 > 默认- Explore Agent 默认使用 Haiku(最便宜最快)
- 父 Agent 可在工具调用中传
model参数覆盖 Agent 定义的偏好 - 设计原则:显式覆盖 > 声明 > 继承 > 默认,贯穿整个生命周期
Step 2: Agent ID 创建
- 格式:
agent-<hex>,hex 来自crypto.randomUUID() - 使用品牌类型
AgentId防止类型层面的字符串混淆 - 恢复的 Agent 保留原始 ID 以确保转录连续性
Step 3: 上下文准备
- Fork Agent:克隆父 Agent 的完整对话历史 + 过滤不完整的 tool_call(
filterIncompleteToolCalls()) - 普通 Agent:从空消息列表开始
- 文件状态缓存:Fork 浅拷贝(共享文件内容引用,节省内存),普通 Agent 创建新缓存
Step 4: CLAUDE.md 剥离
- 只读 Agent(Explore、Plan)设置
omitClaudeMd: true - 搜索类 Agent 不需要项目约定(commit 消息格式、PR 规范、lint 规则等)
- 同时剥离 gitStatus(可达 40KB)
- 成本影响:在 Explore 每周 3400 万次生成的规模下,每个不必要的 token 都会累积成可观成本
Step 5: 权限隔离(最复杂的步骤)
四个关注点分层叠加:
| 关注点 | 机制 |
|---|---|
| 权限模式级联 | 父 Agent 在 bypassPermissions/acceptEdits/auto 模式时,父的模式总是胜出 |
| 提示回避 | 后台 Agent 无法显示权限对话框,自动拒绝而非阻塞。但 bubble 模式例外 |
| 自动检查排序 | bubble 模式的后台 Agent 先运行分类器和权限钩子,只在自动解决失败时才打扰用户 |
| 工具权限范围 | allowedTools 替换整个会话级 allow 规则,防止父 Agent 的批准泄漏到子 Agent |
Step 6: 工具解析
- Fork Agent:
useExactTools: true,传递父 Agent 的精确工具数组(缓存优化) - 普通 Agent:分层过滤
tools: ['*']= 全部工具;tools: ['Read', 'Bash']= 仅这些disallowedTools从池中移除指定工具- 异步 Agent 额外过滤
ASYNC_AGENT_ALLOWED_TOOLS
Step 7: 系统提示词
- Fork Agent 接收父 Agent 预渲染的精确字节(避免重新计算导致缓存失效)
- 普通 Agent 调用
getAgentSystemPrompt()生成
Step 8: 中止控制器隔离
override → 使用覆盖值(用于恢复或特殊生命周期管理)
异步 Agent → 新建独立控制器(用户按 Escape 不影响后台 Agent)
同步 Agent → 共享父 Agent 的控制器(Escape 同时终止两者)Step 9: Hook 注册
- Agent 定义可在 frontmatter 中声明生命周期 Hook
- Hook 通过
agentId范围限定,Agent 终止时自动清理 - 安全控制:
strictPluginOnlyCustomization时,用户自定义 Agent 的 Hook 被静默跳过
Step 10: Skill 预加载
- frontmatter 可指定
skills: ["my-skill"] - 三种解析策略:精确匹配、插件名前缀、后缀匹配
- 加载的 Skill 作为用户消息前置到对话中(Agent 先"阅读"技能指令,再看任务提示)
Step 11: MCP 初始化
- Agent 可定义自己的 MCP 服务器,与父 Agent 的客户端叠加
- 两种形式:按名称引用(共享/记忆化客户端)、内联定义(Agent 结束时清理)
- 只有新创建的客户端会被清理,共享客户端持续存在
Step 12: 上下文创建
通过 createSubagentContext() 组装新的 ToolUseContext,隔离决策如下:
| 关注点 | 同步 Agent | 异步 Agent |
|---|---|---|
setAppState | 共享(父 Agent 可见变更) | 隔离(父 Agent 的副本是 no-op) |
setAppStateForTasks | 共享 | 共享(任务状态必须到达根节点) |
setResponseLength | 共享 | 共享 |
readFileState | 独立缓存 | 独立缓存 |
abortController | 父 Agent 的 | 独立 |
thinkingConfig | Fork: 继承 / 普通: 禁用 | Fork: 继承 / 普通: 禁用 |
messages | 独立数组 | 独立数组 |
Step 13: 缓存安全参数回调
- 供后台摘要服务使用
- 异步 Agent 运行时,摘要服务可 fork 其对话,使用精确相同的参数构造缓存一致的请求前缀
- 实现周期性进度摘要而不干扰主对话
Step 14: 查询循环
typescript
for await (const message of query({
messages: initialMessages,
systemPrompt: agentSystemPrompt,
// ... 其他参数
})) {
// 转发 API 请求启动指标
// Yield 附件消息
// 记录到侧链转录(append-only JSONL 文件)
// Yield 可记录的消息给调用方
}- 与主 Agent 使用同一个
query()函数 - 每条消息通过
recordSidechainTranscript()记录到侧链转录——支持恢复
Step 15: 清理(finally 块)
typescript
finally {
await mcpCleanup() // 关闭 Agent 专用 MCP 服务器
clearSessionHooks(rootSetAppState, agentId) // 移除 Agent 范围的 Hook
cleanupAgentTracking(agentId) // Prompt 缓存追踪状态
agentToolUseContext.readFileState.clear() // 释放文件状态缓存内存
initialMessages.length = 0 // 释放 fork 上下文(GC 提示)
unregisterPerfettoAgent(agentId) // Perfetto 追踪层级
clearAgentTranscriptSubdir(agentId) // 转录子目录映射
rootSetAppState(prev => { ... }) // 移除 Agent 的 todo 条目
killShellTasksForAgent(agentId, ...) // 终止孤立的 bash 进程
}这是代码库中最全面的清理序列。异步生成器协议保证 finally 块在正常完成、中止或错误时都会执行。
异步生成器架构的四大能力
| 能力 | 说明 |
|---|---|
| 流式传输 | 消息增量流动,可实时更新进度指示器、转发指标 |
| 取消 | 返回异步迭代器触发 finally 块,15 步清理无论如何都会执行 |
| 后台化 | 同步 Agent 运行过慢时可中途切换为后台——迭代器从前台交接到异步上下文,Agent 不重启 |
| 进度追踪 | 每个 yield 的消息是一个观察点,用于更新任务状态机和计算进度百分比 |
五、内置 Agent 类型
共 6 种内置 Agent,各自在 5 个维度做出不同选择:
5.1 General-Purpose(通用型)
- 模型:默认 SubAgent 模型
- 工具:全部工具(除 Agent 工具本身——禁止递归生成)
- 上下文:完整(含 CLAUDE.md)
- 同步/异步:均可
- 用途:兜底工作马,当模型不确定需要哪种 Agent 时使用
- 系统提示:完成导向——"完全完成任务,不要镀金,但也不要半途而废"
5.2 Explore(探索型)
- 模型:Haiku(最便宜最快)
- 工具:只读工具(移除 FileEdit、FileWrite、NotebookEdit、Agent)
- 上下文:剥离 CLAUDE.md 和 git status
- 同步/异步:同步
- 用途:快速文件发现、代码搜索、代码库探索
- 规模:每周约 3400 万次生成——最频繁的内置 Agent
- 优化:标记为 one-shot Agent,跳过 agentId/SendMessage 说明/使用尾注,每次节省约 135 字符(每周约 46 亿字符的 prompt token 节省)
5.3 Plan(规划型)
- 模型:继承父 Agent(架构设计需要与实现同等的推理能力)
- 工具:只读(同 Explore)
- 上下文:剥离 CLAUDE.md 和 git status
- 同步/异步:同步
- 用途:软件架构师 Agent,四步结构化流程
- 理解需求
- 深入探索
- 设计方案
- 详细计划(必须以"实现关键文件"列表结尾)
5.4 Verification(验证型)
- 模型:继承父 Agent
- 工具:只读
- 上下文:完整
- 同步/异步:始终异步(
background: true) - 显示:终端中红色显示
- 用途:对抗性测试 Agent
- 独特设计:
- 约 130 行系统提示,最复杂的内置 Agent
- 反回避编程:明确列出模型可能找的借口并指示"做相反的事"
- 每个检查必须包含实际终端输出——不允许手动跳过
- 必须至少包含一个对抗性探测(并发、边界、幂等、孤立清理)
criticalSystemReminder_EXPERIMENTAL:在每个工具结果后注入提醒,防止模型从"验证"漂移到"修复"
5.5 Claude Code Guide(指南型)
- 模型:Haiku
- 工具:只读 + Web
- 权限:
dontAsk(无需用户提示) - 上下文:动态——包含项目的自定义技能、Agent、MCP 服务器、插件命令等
- 用途:关于 Claude Code 自身的文档查询
- 排除条件:SDK 入口时排除(SDK 用户不会问 Claude Code 怎么用)
5.6 Statusline Setup(状态栏配置型)
- 模型:Sonnet
- 工具:仅 Read + Edit
- 显示:橙色
- 用途:终端状态栏配置
- 设计原则:专用 Agent 比通用 Agent + 更多上下文更好——更快、更便宜、更可靠
5.7 Worker(Coordinator 模式特有)
- 非
built-in/目录,在 coordinator 模式激活时动态加载 - 替换所有标准内置 Agent
- 全部工具访问权限
- coordinator 决定每个 worker 做什么
5.8 对比总览
| Agent | 模型 | 工具 | 上下文 | 同步/异步 | 核心用途 |
|---|---|---|---|---|---|
| General-Purpose | 默认 | 全部 | 完整 | 均可 | 兜底委派 |
| Explore | Haiku | 只读 | 精简 | 同步 | 快速搜索 |
| Plan | 继承 | 只读 | 精简 | 同步 | 架构设计 |
| Verification | 继承 | 只读 | 完整 | 始终异步 | 对抗测试 |
| Guide | Haiku | 只读+Web | 动态 | 同步 | 文档查询 |
| Statusline | Sonnet | Read+Edit | 最小 | 同步 | 配置任务 |
六、Fork Agent——Prompt Cache 利用
6.1 核心问题
当父 Agent 并行生成多个子 Agent 时,每个请求约 99.75% 是相同的(系统提示、工具定义、对话历史、触发消息)。Anthropic 的 prompt cache 要求字节精确匹配(不是语义等价),一个空格的差异就会导致整个缓存未命中。
6.2 解决方案
Fork Agent 确保并行子 Agent 间的请求前缀字节完全一致。Fork 子 Agent 从父 Agent "通过引用或字节精确拷贝"继承四项内容:
- 系统提示词:通过
override.systemPrompt线程传递父 Agent 已渲染的精确字节(不重新计算) - 工具数组:
useExactTools: true传递父 Agent 的精确工具数组 - 对话历史:完整克隆
- 思考配置:继承
thinkingConfig
6.3 成本影响
以典型 fork 为例(80,000 共享 token + 每个子 Agent 200 token):
- 无缓存:约 $4(5 个并行子 Agent)
- 有缓存:约 $0.50(90% 折扣应用于子 Agent 2-5)
6.4 递归保护
Fork 子 Agent 保留 Agent 工具(为了缓存一致的工具定义),但有两道防护:
querySource === 'agent:builtin:fork'(主要防护,快速可靠)isInForkChild(messages)扫描对话历史中的标记标签(后备)
七、自定义 Agent
7.1 文件位置
| 位置 | 优先级 | 说明 |
|---|---|---|
.claude/agents/*.md | 最高(项目级) | 随项目版本控制 |
~/.claude/agents/*.md | 较低(用户级) | 跨项目共享 |
7.2 Frontmatter 字段
yaml
---
name: pr-reviewer # 必填,小写字母和连字符
description: "Review PRs..." # 必填,何时调用;含 "PROACTIVELY" 则自动触发
tools: # 可选,省略则继承全部工具
- Read
- Bash
- Grep
disallowedTools: # 可选,禁止的工具
- FileWrite
model: haiku # haiku/sonnet/opus/inherit
permissionMode: dontAsk # default/acceptEdits/dontAsk/bypassPermissions/plan
maxTurns: 50 # 最大 Agent 轮次
skills: # 预加载的技能
- my-custom-skill
mcpServers: # MCP 服务器
- slack
- my-server:
command: node
args: ["./server.js"]
hooks: # 生命周期 Hook
PreToolUse:
- command: "echo validating"
event: PreToolUse
color: blue # CLI 输出颜色
background: false # 后台运行
isolation: worktree # worktree/remote 文件系统隔离
effort: high # 推理努力程度
---
# My Custom Agent
You are a specialized agent for...
(Markdown 正文成为系统提示词)7.3 Agent 定义来源(优先级从高到低)
- 内置 Agent — TypeScript 硬编码,始终可用(受功能开关控制)
- 用户 Agent —
.claude/agents/中的 Markdown 文件 - 插件 Agent — 通过
loadPluginAgents()加载 - 策略 Agent — 通过组织策略设置加载
7.4 安全信任边界
| 来源 | 信任级别 | Hook 限制 | MCP 限制 |
|---|---|---|---|
| 内置 | Claude Code 二进制的一部分 | 无限制 | 无限制 |
| 插件/策略 | 管理员信任 | 无限制 | 无限制 |
| 用户 | 用户控制 | strictPluginOnlyCustomization 时被跳过 | 策略激活时被跳过 |
设计原则:优雅降级——Agent 在能力受限时仍可运行,只是没有不受信任的扩展。
八、执行模式
8.1 同步执行
- 父 Agent 阻塞等待子 Agent 完成
- 共享父 Agent 的
abortController(用户按 Escape 同时终止两者) - 共享
setAppState(状态变更立即双向可见) - 适用场景:"做完这个,然后我继续"
8.2 异步执行(后台模式)
- 通过
run_in_background: true或 Agent 定义的background: true触发 - 也可在 CLI 中通过
Ctrl+B将正在运行的 Agent 切换到后台 - 独立的
AbortController(用户按 Escape 不影响后台 Agent) - 隔离的
setAppState(防止父 Agent UI 意外跳动) - 结果写入
outputFile,父 Agent 可轮询/监听 - 适用场景:"做这个,同时我做其他事"
8.3 Split-and-Merge(Fan-out/Fan-in)模式
┌───────────────────────────────────────────┐
│ Orchestrator (父 Agent) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │SubAgent1│ │SubAgent2│ │SubAgent3│ │
│ │(Task A) │ │(Task B) │ │(Task C) │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────┐ │
│ │ Merge Results │ │
│ └──────────────────┘ │
└───────────────────────────────────────────┘三个阶段:
- Split:编排器分析任务,拆分为独立子任务
- Fan-out:通过 Task 工具同时委派给多个子 Agent(最多 10 个)
- Merge:编排器收集输出并综合为最终结果
关键要求: 所有 Task 调用必须在单条 assistant 消息中发起,才能实现真正的并行。
8.4 Git Worktree 隔离
当多个 Agent 并发操作同一仓库时,可能产生竞态条件。Git worktree 提供三种隔离:
| 隔离类型 | 说明 |
|---|---|
| 文件系统隔离 | Agent 间不能覆盖彼此的文件 |
| 分支隔离 | 提交只落在预期分支上 |
| 安装隔离 | 一个 worktree 的 npm install 不会破坏另一个的 node_modules |
使用方式:
bash
claude --worktree feature-auth # 命名 worktree
claude --worktree # 自动生成名称
claude --worktree bugfix-123 & # 多个并行会话SubAgent 可通过 isolation: "worktree" 在隔离环境中运行。
九、上下文管理与压缩
9.1 三层压缩系统
| 层级 | 触发方式 | 机制 |
|---|---|---|
| 微压缩 (Microcompaction) | 自动 | 将大体积工具结果保存到磁盘,上下文中只保留引用 |
| 自动压缩 (Auto-compaction) | 空间不足时 | 当空闲空间低于保留阈值时触发,周期性检查而非逐 token 检查 |
| 手动压缩 (Manual compaction) | 用户触发 | /compact 命令,可带焦点提示引导摘要 |
9.2 压缩契约
压缩不仅是摘要,而是"摘要 + 上下文恢复":
- 摘要对话历史
- 重新读取最近的文件
- 恢复任务列表(todos)
- 注入延续指令
- 保留"工作状态"——原始用户请求 + 下一步行动
9.3 SubAgent 与上下文隔离的关系
SubAgent 是防止"上下文腐烂"的核心机制。当父 Agent 需要搜索大量文件时,如果直接在主上下文中操作,搜索结果、日志、文件内容会充斥上下文窗口,淹没真正重要的信息。SubAgent 在独立上下文中完成工作,仅返回摘要,保持父 Agent 的上下文干净聚焦。
十、Agent Teams(实验性多智能体协作)
10.1 与 SubAgent 的区别
| 维度 | SubAgent | Agent Teams |
|---|---|---|
| 通信方向 | 仅向父 Agent 报告 | 队友间可直接通信 |
| 协作能力 | 聚焦型任务 | 全面协作——分享发现、协调工作 |
| 适用场景 | 只需结果的聚焦任务 | 需要讨论和协调的复杂工作 |
10.2 七个核心原语
| 原语 | 用途 |
|---|---|
TeamCreate | 创建团队 |
TaskCreate | 定义工作单元 |
TaskUpdate | 领取和完成任务 |
TaskList | 查找可用工作 |
Task (with team_name) | 生成队友 |
SendMessage | 队友间直接点对点通信 |
TeamDelete | 清理 |
10.3 启用方式
json
// settings.json 或环境变量
{
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": true
}需要 Claude Code v2.1.32+,目前为实验性功能。
十一、功能开关系统
SubAgent 系统拥有代码库中最复杂的功能开关。至少 12 个功能标志和 GrowthBook 实验控制不同方面:
| 功能开关 | 控制范围 |
|---|---|
FORK_SUBAGENT | Fork Agent 路径 |
BUILTIN_EXPLORE_PLAN_AGENTS | Explore 和 Plan Agent |
VERIFICATION_AGENT | Verification Agent |
KAIROS | cwd 覆盖、assistant 强制异步 |
TRANSCRIPT_CLASSIFIER | 交接分类、auto 模式覆盖 |
PROACTIVE | 主动模块集成 |
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS | 禁用后台任务 |
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS | Agent Teams 功能 |
CLAUDE_CODE_COORDINATOR_MODE | Coordinator 模式 |
两种开关类型:
- 编译时(Bun 死代码消除):字符串替换,未启用的代码路径从分发二进制中完全移除
- 运行时(GrowthBook A/B 测试):允许实时实验,如
tengu_amber_stoat测试移除 Explore/Plan Agent 的影响
十二、Agent 设计的五个维度
Claude Code 的内置 Agent 展示了一套 Agent 设计的模式语言:
维度 1: 能看到什么?(上下文)
omitClaudeMd、git status 剥离、Skill 预加载控制 Agent 的感知范围- 核心洞察:上下文不是免费的。每个 token 都有成本并占用工作记忆
维度 2: 能做什么?(工具)
tools和disallowedTools设置硬边界- 双重目的:安全性(Verification Agent 不能"修复"它发现的问题)+ 聚焦(工具更少 = 决策更快)
- 防御纵深:工具级限制 + 系统提示解释
维度 3: 如何与用户交互?(权限)
permissionMode+canShowPermissionPrompts决定是否请求权限、自动拒绝还是冒泡到父 Agent 终端
维度 4: 与父 Agent 的关系?(执行模式)
- 同步 = 阻塞 + 共享状态("做完这个然后我继续")
- 异步 = 独立运行("你做你的我做我的")
- Fork = 继承完整上下文("你知道我所知道的一切,去处理这部分")
维度 5: 成本多少?(经济性)
- 模型选择 × 思考配置 × 上下文大小 = 成本
- Haiku 用于廉价只读工作,Sonnet 用于中等任务,继承父 Agent 模型用于需要同等推理能力的任务
- 非 Fork Agent 禁用 thinking(扩展推理 token)以控制输出成本——"父 Agent 负责思考,子 Agent 负责执行"
十三、关键设计洞察总结
统一生命周期:所有 Agent 类型(无论多么不同)都流经同一个
runAgent()的 15 步——Agent 类型不是编码在控制流中,而是编码在配置中。这使系统具有可扩展性:添加新 Agent 类型只需写定义,不需修改生命周期。Schema 即指令:从 Schema 中移除字段比在提示词中说"不要用"更有效——模型无法滥用它看不到的东西。
经济性是核心架构考量:在每周 3400 万次 Explore 生成的规模下,135 字符的节省等于每周 46 亿字符的 prompt token 节省。成本不是优化目标——它是可行产品与不可负担产品的分界线。
异步生成器是正确性要求:不是便利——它保证清理代码在所有情况下都会执行,使后台化和取消成为可能。
上下文隔离是架构基石:SubAgent 的核心价值不是并行——而是防止父 Agent 的上下文被中间结果污染。
信任边界精确追踪:Agent 定义的
source不只是元数据——它门控真实行为,实现优雅降级。
参考资料
- Anthropic 官方文档 - Create custom subagents
- Claude Code from Source - Ch 8: Spawning Sub-Agents
- Claude Code from Source - Ch 9: Fork Agents and the Prompt Cache
- Anthropic 官方文档 - Agent Teams
- Dive into Claude Code: The Design Space (arXiv 2604.14228)
- Claude Code Architecture Guide
- Claude Code Sub-Agent Patterns