目标:讲清 Claude Code 的 subagent 架构------本质(独立的微型 agent 会话)、Agent 工具参数、内置 agent 类型、Task 系统、三种隔离模式、SendMessage 通信、硬限制。这是从"单 agent"到"多 agent 协作"的跃迁。 受众:专业程序员。本机版本
2.1.220。
9.1 本质定义
从单 agent 到多 agent
Claude Code 默认是单 agent 模式------你和一个 agent 一对一聊天。但复杂任务需要并行和分工:
bash
主 agent (你聊天的这个)
│
├─→ Agent("搜索所有日志文件", type="Explore") 子 Agent 1
├─→ Agent("审查 auth 模块", type="general-purpose") 子 Agent 2
└─→ Agent("检查性能问题", type="general-purpose") 子 Agent 3
│
▼
三个 agent 并行跑,各自有独立上下文
│
▼
主 agent 收结果、综合、回复你
Subagent = 一个独立的微型 agent 会话。 有自己的上下文窗口、自己的工具权限、自己的模型。和主 agent 的关系像"老板分活给组员"------组员只看自己那份任务,干完汇报。
为什么不一个人干完?
| 问题 | Subagent 解法 |
|---|---|
| 上下文不够用 | 每个子 agent 有独立上下文,不会共享主 agent 的 token 池 |
| 需要并行 | 多个 agent 同时跑,不是 A → B → C 串行 |
| 任务需要专注 | 子 agent 只看自己那片,不被全局信息干扰 |
| 模型省钱 | 简单搜索用 haiku,疑难分析用 opus |
| 需要隔离 | worktree 保证并行写文件不冲突 |
上下文隔离是最关键的价值。一个 200K 上下文的单 agent 和一个派了 10 个 50K 上下文子 agent 的主 agent------后者覆盖的信息量远超前者,因为这 10 个上下文不共享 token 池。
9.2 Agent 工具
工具定义
从 sdk-tools.d.ts 中确认的 Agent 工具输入:
typescript
interface AgentInput {
description: string; // 3-5 词简述任务
prompt: string; // 给子 agent 的完整任务描述
subagent_type?: string; // 专用类型(可选,默认通用)
model?: "sonnet" | "opus" | "haiku" | "fable"; // 覆盖默认模型
run_in_background?: boolean; // 默认 true(后台跑)
isolation?: "worktree" | "remote"; // 隔离模式
name?: string; // 起名,方便 SendMessage 续聊
}
关键参数说明
description
3-5 词的简短描述,用于 UI 展示和日志。不是给 agent 看的------是给你看的,让你在任务列表里知道谁在干什么。
prompt
给子 agent 的完整任务指令。这是子 agent 的"唯一的真实"------它不知道主对话在聊什么,不知道其他 agent 在干什么。它只看到这个 prompt。
subagent_type
不传则用默认的通用 agent。传入内置类型名(如 "Explore"、"Plan")或自定义类型名(.claude/agents/ 中定义的)。
model
覆盖子 agent 模型。不传则继承主 agent 的模型,或按 agent 类型定义的默认模型。注意:fork 类型的 agent 永远继承父模型,传了也会被忽略。
run_in_background
默认 true------子 agent 后台跑,主 agent 收到通知后才读结果。设为 false 时主 agent 同步等待------当你需要子 agent 的结果才能继续时用。
isolation
- 默认:共享文件系统,子 agent 可以读/写和主 agent 相同的文件
"worktree":在临时 git worktree 里跑,文件操作在隔离副本中进行。代价:~200-500ms 初始化 + 磁盘占用"remote":子 agent 在云端远程环境跑,始终后台执行
name
给子 agent 起名。之后可以 SendMessage({to: name}) 续聊。名字是语义化的(如 "bug-finder"、"code-reviewer"),不要用随机 ID。同名新 agent 会覆盖旧的。
结果约定
子 agent 的输出不直接展示给用户。SDK 的注释说:
"The agent's final report is not shown to the user --- relay what matters."
主 agent 收到子 agent 的结果后,消化整合,再以自己的话告诉用户。对用户来说是无感的------只看到最终答案,不知道背后多少 agent 在跑。
9.3 内置 Agent 类型
当前版本可用的内置类型:
| 类型 | 描述 | 适用场景 |
|---|---|---|
claude |
通用型,什么都能干 | 任何没特定要求的任务 |
general-purpose |
复杂研究、多步骤任务 | 搜索代码、执行多步操作 |
Explore |
只读搜索 agent | 扫大量文件找信息,不需要写 |
Plan |
软件架构师 | 设计实施方案,不写代码 |
claude-code-guide |
Claude Code 问题专家 | "Claude Code 怎么用"这类问题 |
statusline-setup |
状态栏配置 | 配置终端状态栏 |
每个类型背后是一套预定义的 system prompt + 工具子集 。例如 Explore 被限制为只读(不允许 Edit/Write),Plan 不允许执行 shell 命令。
自定义 Agent 类型
在 .claude/agents/ 目录下创建 Markdown 文件:
bash
.claude/agents/
└── security-reviewer.md ← 定义一个叫 "security-reviewer" 的 agent 类型
格式和 slash command 类似:YAML frontmatter 定义能力,Markdown body 定义 system prompt。定义后即可通过 Agent({subagent_type: "security-reviewer"}) 使用。
9.4 Task 系统
是什么
子 agent 是一种 Task。Task 系统是管理所有后台工作的统一框架。
六个工具
| 工具 | 作用 |
|---|---|
TaskCreate |
创建任务并加入任务列表 |
TaskList |
列出所有任务及其状态 |
TaskGet |
查某个任务的详细信息 |
TaskUpdate |
更新状态(标记完成/设置依赖/分配 owner) |
TaskStop |
终止正在运行的任务 |
TaskOutput |
读取已完成任务的输出 |
任务依赖
SDK 确认了依赖机制:
typescript
interface TaskUpdateInput {
addBlocks?: string[]; // 此任务完成后才解锁的任务
addBlockedBy?: string[]; // 此任务等待的前置任务
}
这让 agent 可以编排复杂工作流:"先搜索文件(Task 1),搜完了并行审查(Task 2 + 3 + 4),审查完了合并报告(Task 5 依赖 2/3/4)。"
任务状态流转
scss
pending → in_progress → completed
↓
deleted (手动删除)
主 agent 通过 TaskList 查看进度,通过 TaskGet 获取具体输出。
9.5 Agent 生命周期
arduino
① 主 agent 调 Agent(description, prompt, type)
│
② runtime 创建子 agent 会话
分配独立上下文窗口
加载对应 agent 类型的 system prompt
│
③ 自动创建 Task 记录
│
④ 子 agent 跑自己的 agent loop
独立 Read / Grep / Bash / Edit
独立管理自己的上下文
不知道自己是被 spawn 的
│
⑤ 子 agent 完成后返回结果(纯文本)
│
⑥ Task 标为 completed
│
⑦ 主 agent 收结果、消化、整合
│
⑧ (可选) 主 agent 用 SendMessage 续聊此 agent
或就此结束
关键认知
子 agent 不知道它是子 agent。 从它的视角看,这是一个全新的一对一会话------用户给了它一个 prompt,它完成任务返回。它不知道主对话在聊什么,不知道还有其他 agent 在并行跑。这种"信息最小化"是 subagent 设计的核心理念:不让不需要的信息占用上下文。
9.6 隔离模式
三种模式对比
| 默认 | worktree | remote | |
|---|---|---|---|
| 文件系统 | 共享 | git worktree 副本 | 云端隔离 |
| 网络 | 共享 | 共享 | 云端独立 |
| 启动开销 | 零 | ~200-500ms + 磁盘 | 网络延迟 |
| 适用场景 | 只读分析 | 并行写文件 | 远程执行环境 |
| 子 agent 类型 | 任意 | 通常配合 fork | 任意 |
worktree 详解
worktree 隔离的本质:
markdown
① git worktree add /tmp/claude-worktrees/agent-1
创建当前 repo 的轻量副本
② 子 agent 的 cwd 切换到副本
所有文件操作都在副本中进行
③ 子 agent 完成后:
- 无改动 → 自动删除副本(不留痕迹)
- 有改动 → 保留,主 agent 可以检查和合并
SDK 建议:"use ONLY when agents mutate files in parallel and would otherwise conflict"。不要滥用------每个 worktree 都有磁盘和初始化开销。
fork 类型
subagent_type: "fork" 是 worktree 的专用类型。它强制继承父 agent 的模型(忽略 model 参数)。二进制中确认了 FORK_SUBAGENT_TYPE、isForkSubagentEnabled、getForkSubagentSource 等基础设施。
9.7 Agent 间通信
SendMessage 工具
json
{
"to": "bug-finder",
"summary": "深挖第3个潜在bug",
"message": "你之前找到的第3个null check问题,去读 src/auth/login.ts 验证一下"
}
to: 接收方 agent 的 name(不是 ID)。名字语义化,新同名 agent 覆盖旧的summary: 5-10 词简要描述,UI 预览message: 实际消息内容
可以发给谁
| 目标 | 用法 |
|---|---|
| 命名的子 agent | SendMessage({to: "bug-finder"}) |
| 主对话 | SendMessage({to: "main"}) ------ 仅子 agent 用 |
同一个子 agent 可以反复续聊------每次 SendMessage 都沿用上次的上下文(前提是没被回收)。
9.8 资源限制
环境变量
| 变量 | 控制 |
|---|---|
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH |
递归深度(子 agent 可以自己 spawn 子 agent?最多几层) |
CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION |
单会话总 spawn 数上限 |
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS |
同时跑的数量上限 |
CLAUDE_CODE_SUBAGENT_MODEL |
子 agent 默认模型 |
CLAUDE_SUBAGENT_BG_SHELL_MAX_MS |
后台 shell 最长运行时间 |
CLAUDE_CODE_ENABLE_APPEND_SUBAGENT_PROMPT |
是否允许追加 prompt |
CLAUDE_CODE_FORK_SUBAGENT |
是否启用 fork 类型 |
CLAUDE_CODE_FORWARD_SUBAGENT_TEXT |
是否转发子 agent 文本 |
CLAUDE_CODE_SUBAGENT_CACHE_EVICT |
缓存驱逐策略 |
这些是硬上限------到了就抛错。目的是防止 agent loop 失控时 spawn 数千个子 agent。
Subagent Park
不常用的子 agent 上下文不会立刻销毁------它被 "park" 到磁盘。下次 SendMessage 续聊时从 park 状态醒来复用。二进制中确认了:
c
subagent-park ← park 机制
SUBAGENT_PARK_REASON ← park 原因(超时/主动park/资源压力)
isSubagentParkAbort ← 是否因 abort 而 park
subagentParkAbortReason ← abort 的具体原因
9.9 关键认知
-
子 agent 不知道自己是子 agent。 这是设计选择------信息最小化,每个 agent 只看到完成自己任务需要的信息。
-
上下文不共享 = 可以线性扩展。 单 agent 200K 上下文有限。10 个子 agent 各 50K ≠ 500K 上下文------它们的上下文是独立的,不共享 token 池。
-
Agent 类型 = system prompt + 工具集 + 模型默认值。 选对类型不仅影响输出质量,也影响 token 成本(Explore 比 general-purpose 便宜)。
-
隔离是昂贵的。 worktree 有磁盘和初始化开销,只在并行写文件时才用。默认共享模式已经足够应对绝大多数场景。
-
Task 系统是 Agent 的记账簿。 它让主 agent 知道谁在跑、跑完没、结果在哪------不需要靠"记忆"来追踪子任务。