claudecode学习 第 9 章 · Subagents

2 阅读8分钟

目标:讲清 Claude Code 的 subagent 架构——本质(独立的微型 agent 会话)、Agent 工具参数、内置 agent 类型、Task 系统、三种隔离模式、SendMessage 通信、硬限制。这是从"单 agent"到"多 agent 协作"的跃迁。 受众:专业程序员。本机版本 2.1.220。


9.1 本质定义

从单 agent 到多 agent

Claude Code 默认是单 agent 模式——你和一个 agent 一对一聊天。但复杂任务需要并行和分工:

主 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 工具输入:

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-guideClaude Code 问题专家"Claude Code 怎么用"这类问题
statusline-setup状态栏配置配置终端状态栏

每个类型背后是一套预定义的 system prompt + 工具子集。例如 Explore 被限制为只读(不允许 Edit/Write),Plan 不允许执行 shell 命令。

自定义 Agent 类型

在 .claude/agents/ 目录下创建 Markdown 文件:

.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 确认了依赖机制:

interface TaskUpdateInput {
  addBlocks?: string[];     // 此任务完成后才解锁的任务
  addBlockedBy?: string[];  // 此任务等待的前置任务
}

这让 agent 可以编排复杂工作流:"先搜索文件(Task 1),搜完了并行审查(Task 2 + 3 + 4),审查完了合并报告(Task 5 依赖 2/3/4)。"

任务状态流转

pending  →  in_progress  →  completed
                ↓
             deleted    (手动删除)

主 agent 通过 TaskList 查看进度,通过 TaskGet 获取具体输出。


9.5 Agent 生命周期

① 主 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 隔离模式

三种模式对比

默认worktreeremote
文件系统共享git worktree 副本云端隔离
网络共享共享云端独立
启动开销零~200-500ms + 磁盘网络延迟
适用场景只读分析并行写文件远程执行环境
子 agent 类型任意通常配合 fork任意

worktree 详解

worktree 隔离的本质:

① 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 工具

{
  "to": "bug-finder",
  "summary": "深挖第3个潜在bug",
  "message": "你之前找到的第3个null check问题,去读 src/auth/login.ts 验证一下"
}
  • to: 接收方 agent 的 name(不是 ID)。名字语义化,新同名 agent 覆盖旧的
  • summary: 5-10 词简要描述,UI 预览
  • message: 实际消息内容

可以发给谁

目标用法
命名的子 agentSendMessage({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 状态醒来复用。二进制中确认了:

subagent-park              ← park 机制
SUBAGENT_PARK_REASON       ← park 原因(超时/主动park/资源压力)
isSubagentParkAbort        ← 是否因 abort 而 park
subagentParkAbortReason    ← abort 的具体原因

9.9 关键认知

  1. 子 agent 不知道自己是子 agent。 这是设计选择——信息最小化,每个 agent 只看到完成自己任务需要的信息。

  2. 上下文不共享 = 可以线性扩展。 单 agent 200K 上下文有限。10 个子 agent 各 50K ≠ 500K 上下文——它们的上下文是独立的,不共享 token 池。

  3. Agent 类型 = system prompt + 工具集 + 模型默认值。 选对类型不仅影响输出质量,也影响 token 成本(Explore 比 general-purpose 便宜)。

  4. 隔离是昂贵的。 worktree 有磁盘和初始化开销,只在并行写文件时才用。默认共享模式已经足够应对绝大多数场景。

  5. Task 系统是 Agent 的记账簿。 它让主 agent 知道谁在跑、跑完没、结果在哪——不需要靠"记忆"来追踪子任务。