ClaudeCode 工程化学习 · 子代理篇:Sub-Agents 核心概念与应用价值
ClaudeCode 工程化学习 · 子代理篇:Sub-Agents 核心概念与应用价值
跑完测试 → 500 行日志;搜一遍代码 → 200 行 grep;分析错误 → 一堆中间推理——这些执行过程对当下必要,对后续决策全是噪声。让 Claude 记得更少、但记得对。
一句话开场
如果让一个人同时干调研、写代码、跑测试、写文档,最后他脑子里塞满细节,已经记不清最初的目标是什么了。但如果给一个团队,每人负责一件事,做完只回一份结论——决策者拿到的是干净的报告,执行过程永远不会污染主对话。
子代理(Sub-Agents)就是给 Claude 配的那个"团队"。
为什么需要 Sub-Agents:上下文污染问题
什么是上下文污染
我们先看一个典型场景:让 Claude 跑一遍测试。
跑测试 → 500 行日志 搜代码 → 200 行 grep 分析错误 → 一堆中间推理过程这些内容有两个共同特征:
| 维度 | 表现 |
|---|---|
| 对执行过程 | 必要——少了它们 Claude 无法判断对错 |
| 对后续决策 | 噪声——主对话并不需要这些细节 |
| 持续时间 | 默认不会过期,永久占用上下文窗口 |
根因在于:Claude Code 不会自动过期临时数据,它默认把这些临时的过程数据存储为了长期决策记忆。
污染的具体后果
执行噪声越堆越多,主对话真正关心的"结论"反而被淹没。这就是上下文污染。
核心概念:主代理与子代理
什么是主代理
主代理就是当前的主对话本身。它继承了 CLAUDE.md 的全部记忆、当前任务上下文、以及所有主对话级别的工具权限。
什么是子代理
子代理是一个有独立规则、工具权限、上下文窗口、为完成某一类任务的专职助手。
类比职场:一个岗位做一件事,并且有明确的权限边界。
上下文隔离机制
关键特性:子代理天然拥有独立的上下文窗口,执行完即丢弃,只把结论带回来。这是 Claude Code 里唯一一个结构上允许"执行完即丢弃"的组件。
四句话概括子代理的核心:
- 不是为了 Claude 做得更多
- 而是为了 Claude 记得更少
- 但记得对
- 执行过程不再污染主对话
用与不用的本质区别
方式一:事必躬亲
亲自调研市场(输出 200 行分析)、亲自写代码(输出 500 行日志)、亲自测试(又是 300 行)、亲自写文档……最后主对话里塞满了各种细节,已经记不清最初的目标是什么了。
方式二:专人专岗
安排一个市场专员去调研,只需要他给你一份 1 页的报告;安排一个测试工程师去跑测试,只需要他告诉你结果是"通过"还是"有 3 个失败";安排一个技术文档专员去写文档……每个人带着明确的任务出去,完成后只把结论带回来。
对照表:
| 维度 | 事必躬亲(不用子代理) | 专人专岗(用子代理) |
|---|---|---|
| 主对话承载内容 | 全量执行过程 | 仅结论 |
| 上下文窗口 | 快速膨胀 | 保持清洁 |
| 注意力分配 | 被过程分散 | 专注决策 |
| 并行能力 | 串行 | 多任务并行 |
子代理的四大工程价值
价值一:隔离——解决上下文污染
通过独立的上下文窗口,把"对当前执行有用但对后续决策毫无价值"的日志、搜索结果、中间推理挡在主对话之外。子代理执行完即丢弃,只把结论带回来。
反例:在主对话里直接pnpm test,500 行日志直接进上下文。
正例:派test-runner子代理去跑,回报"3 个失败,在 src/auth/login.test.ts"。
价值二:约束——把行为边界变成系统规则
通过工具权限边界,把"我希望你别这么做"变成"你物理上做不到"。代码审查只能读、修 bug 才能写——角色职责不再依赖提示词自觉。
反例:主对话里加一段提示词"请不要修改 migrations 目录",Claude 大概率会忘掉。
正例:在子代理的 frontmatter 中只配置tools: Read, Grep, Glob,物理上就不能写文件。
价值三:复用——把经验沉淀为版本化资产
当子代理被定义成文件、放进版本控制后,好的使用方式就从一次性对话,变成了可共享、可迭代的工程资产。
反例:每次都口头描述"帮我跑一下测试",表述每次都略有不同。
正例:.claude/agents/test-runner.md文件在团队仓库共享,新人 clone 仓库后立刻可用。
价值四:并行——天然的多任务加速器
子代理可以后台运行,让原本串行的复杂任务同时推进。
反例:依次在主对话里调研认证逻辑、数据库设计、API 接口,每个调研都挤占主上下文。
正例:同时派 3 个子代理并行调研,最后主对话只拿到 3 份结论报告。
这四点合在一起,标志着 Claude Code 的使用方式,从"对话技巧"正式跨入"工程系统"。
什么时候该用子代理?
子代理的价值不在于"能不能用",而在于"该不该用"。判断的简单标准:主对话到底需不需要承载执行过程本身。
适合用子代理的四类任务
第一类:高噪声输出的任务
执行过程中会产生大量中间信息,但主对话真正关心的,往往只有一个结论。
- 跑测试套件(数千行输出 → “3 失败”)
- 检索大代码库(成百上千 grep 结果 → 路径列表)
- 分析错误日志(一堆中间推理 → 根因 + 修复建议)
第二类:角色边界必须明确的任务
有些事情,你只希望 Claude"看",而不希望它"动手";有些操作只能在特定目录、特定范围内发生。
- 代码审查(只能读)
- 数据库只读分析(Read-Only 工具)
- 敏感文件分析(不能写)
第三类:可以并行展开的研究型任务
当探索之间相互独立时,与其串行调研,不如并行派子代理。
- 同时调研认证、数据库、API 三个模块
- 对比多种技术方案
- 从多个视角分析同一个问题
第四类:可拆成清晰阶段的流水线式任务
每个阶段的目标、权限、输出都明确时,用子代理固定责任。
定位代码 → 代码审查 → 修改 → 测试验证不适合用子代理的场景
- 需要频繁来回讨论和即时调整的对话
- 主对话需要看到完整执行过程才能决策的情况
- 任务本身很轻,启动子代理反而增加开销
一条关键约束:子代理不能嵌套子代理
这是架构硬约束,所有编排必须由主对话完成。
这意味着:
- 如果你需要"先审查再修复",必须由主对话依次调用两个子代理,而不是让第一个子代理去调用第二个。
- 流水线的"调度中心"只有一个,就是主对话本身。
- 如果需要在子代理内复用知识,用
skills字段预加载(而非再嵌套一个子代理)。
配置详解:子代理的 frontmatter
子代理使用 Markdown + YAML frontmatter 格式:
---name:<代理名称>description:<何时被调用>tools:<工具列表>disallowedTools:<禁止工具列表>model:<sonnet|opus|haiku>permissionMode:<default|acceptEdits|bypassPermissions|plan>skills:<预加载的 skill 列表>hooks:<子代理专属生命周期 Hook>---<正文 = 子代理的系统提示词>子代理只会收到这段系统提示词和基本环境信息(工作目录等),不会继承主对话的完整系统提示词。
description 的设计艺术
description字段决定了 Claude 何时自动调用你的子代理——这是配置中最重要的设计决策。
---name:code-reviewerdescription:Review code for quality,security,and best practices. Use proactively after code modifications.tools:Read,Grep,Glob,Bash---要点:
- 说明做什么(审查代码质量、安全、规范)
- 说明什么时候用(代码修改后,或用户请求时)
Proactively关键词会鼓励 Claude 在合适的时机主动委派任务
tools vs disallowedTools:白名单与黑名单
| 表达方式 | 适用场景 |
|---|---|
tools: [Read, Grep] | 子代理只需要少数工具,白名单更清晰 |
disallowedTools: [Edit, Write] | 子代理需要大部分工具但排除个别,黑名单更简洁 |
不要同时使用两者——选一种即可。
工具权限应遵循最小权限原则:能用 Read 完成的任务,就不要给 Edit。
常见子代理的工具组合推荐:
| 子代理类型 | 推荐 tools |
|---|---|
| 代码审查 | Read, Grep, Glob |
| 测试运行器 | Bash(配合 hooks 限制命令) |
| 数据库只读 | Bash(配validate-readonly-query.sh校验) |
| 影响分析 | Read, Grep, Glob, Bash |
| 文档撰写 | Read, Write, Glob |
model:模型选择与默认值
model字段决定子代理使用哪个模型。可选sonnet/opus/haiku,留空则继承主对话模型。
权衡原则:
- 复杂推理任务(架构分析、复杂 Bug 定位)→ opus
- 常规任务(代码审查、测试运行)→ sonnet
- 简单批量任务(文件查找、格式校验)→ haiku
permissionMode:权限模式
控制子代理在执行过程中遇到需要权限的操作时如何处理:
| 模式 | 行为 |
|---|---|
default | 每次需要权限都询问 |
acceptEdits | 自动接受文件编辑 |
bypassPermissions | 跳过所有权限检查 |
plan | 先规划再执行(Plan 子代理默认) |
子代理会继承主对话的权限上下文,但可以通过此字段覆盖。
skills:为子代理预加载知识
---name:impact-analyzerdescription:Analyze impact scope of code changes on the full call chain.tools:Read,Grep,Glob,Bashskills:-chain-knowledge# 链路拓扑和 SLA 约束-recent-incidents# 近期事故记录---这是"子代理内复用知识"的正确做法——通过skills字段预加载,而不是嵌套另一个子代理。
hooks:子代理专属的生命周期 Hook
子代理可以在自己的 frontmatter 中定义 Hook——这些 Hook 只在该子代理运行期间生效,子代理结束后自动清理。
---name:db-readerdescription:Execute read-only database queries.tools:Bashhooks:PreToolUse:-matcher:"Bash"hooks:-type:commandcommand:"./scripts/validate-readonly-query.sh"---典型用法:
- PreToolUse 校验命令是否安全
- PostToolUse 记录执行日志
- 子代理结束时清理临时文件
子代理的存放位置与优先级
| 位置 | 路径 | 适用场景 |
|---|---|---|
| 项目级(仅当前项目可用) | ./.claude/agents/ | 项目特有的角色,比如针对特定框架的测试运行器 |
| 用户级(所有项目可用) | ~/.claude/agents/ | 通用角色,比如日志分析器、通用代码审查器 |
优先级:项目级覆盖用户级,同名时项目级优先生效。
创建子代理的三种方式
方式一:交互式创建
在 Claude Code 中输入/agents,按照向导操作:
- 输入
/agents - 选择 “Create new agent”
- 选择存放位置(User-level 或 Project-level)
- 选择 “Generate with Claude” 并描述功能
- 选择需要的工具
- 选择模型
- 保存
方式二:手写配置文件
直接创建.claude/agents/your-agent.md文件。优势是更精细的控制,方便版本管理,可以从其他项目复制。
方式三:CLI 参数临时创建
通过--agents参数,可以在启动 Claude Code 时传入 JSON 格式的子代理定义。这种方式创建的子代理仅在当前会话中存在,不会保存到磁盘。
特别适合 CI/CD 自动化时在流水线中临时创建任务专用的子代理:
claude--agents'{"test-runner": {"description": "Run tests", "tools": ["Bash"]}}'实战:一个最小可用的子代理配置
---name:code-reviewerdescription:Review code for quality,security,and style issues. Use proactively after any code modification.tools:Read,Grep,Globmodel:sonnetpermissionMode:default---You are a senior code reviewer. When reviewing code:1. Check for security issues (hardcoded secrets,SQL injection,XSS) 2. Check for style consistency with the codebase 3. Check for missing tests 4. Provide a structured report with severity levels (blocker / major / minor / nit) Do NOT modify code. Only report findings.配置要点解读:
description中明确"after any code modification",配合 “Use proactively” 鼓励自动触发tools只给只读工具,物理上不能修改代码(约束价值)permissionMode: default让敏感操作保持询问- 系统提示词明确职责与边界,不给它越权空间
常见陷阱速查
| 错误做法 | 后果 | 正确做法 |
|---|---|---|
| description 写得太泛 | 子代理从不触发,或触发时机不准 | 明确"做什么 + 什么时候用",用 “Proactively” 关键词 |
| tools 和 disallowedTools 同时用 | 配置冲突报错 | 二选一 |
| 想让子代理再调用子代理 | 架构不支持,主对话必须亲自调度 | 用skills字段预加载复用知识 |
| 用子代理跑小任务 | 启动开销 > 收益 | 小任务直接主对话处理 |
| 子代理配置里给太多工具 | 违反最小权限原则,行为不可控 | 只给完成任务必需的最小工具集 |
| 项目级和用户级同名子代理 | 行为不一致,调试困难 | 用命名空间区分,或明确选用哪一层 |
| 期望子代理继承主对话系统提示词 | 实际只继承工作目录和环境信息 | 把核心指令写在子代理自己的 frontmatter 与正文中 |
| 把子代理当 Skill 用 | 子代理有独立上下文,启动开销大 | 静态规则用 Skill,动态隔离任务用 Sub-Agent |
局限性声明
子代理不是万能药,几个边界必须诚实指出:
- 不能嵌套:架构硬约束,复杂流水线必须由主对话统一调度
- 启动开销:每个子代理启动都有固定 token 成本,简单任务直接交给主对话更划算
- 模型限制:子代理与主对话使用同一权限上下文,敏感操作仍需主对话授权
- 调试成本:子代理的执行过程对主对话不可见,问题排查需要看子代理的返回结果反推
- CI/CD 临时场景:临时子代理(CLI 方式)只在当前会话存在,复杂流水线需要持久化定义
- 并行数量:同时派 N 个子代理意味着 N 倍的 token 消耗,需权衡收益与成本
核心要点回顾
- 子代理的核心是隔离:通过独立的上下文窗口,把执行噪声挡在主对话之外,只回结论
- 四大工程价值:隔离、约束、复用、并行,对应内存管理、安全边界、组织效率三大经典软件工程命题
- 四类适用任务:高噪声输出 / 角色边界明确 / 可并行研究 / 流水线式阶段任务
- 架构硬约束:子代理不能嵌套子代理,所有编排由主对话完成
- 配置核心字段:
description(决定何时触发)+tools(最小权限原则)+model(性能/成本权衡) - 存放优先级:项目级覆盖用户级
子代理把"对话技巧"升级为"工程系统"——这是 Claude Code 从 ChatGPT 进化为团队编排平台的关键组件。
延伸阅读
- Claude Code 官方文档 - Sub-Agents
- Claude Code Frontmatter 规范
- Agent SDK 编程接口