聊到Claude Code的Sub Agents,很多朋友会把它想成一个可以随时调用的“高级功能”,实际上用好了它就是一个能把整个开发流程重新组织的杠杆。我过去踩了不少坑,直到自己动手创建了几个子代理之后,才摸清里面的门道。这篇是Claude Code系列的第六篇,我会把Sub Agents的创建方法拆开讲清楚,从目录规范、配置格式、指令编写到调试思路,尽量把每一步都落到能抄作业的程度。如果你已经会基本的Claude Code操作,想提升复杂任务的执行质量,这篇文章就是为你准备的。如果你还完全没接触过Claude Code,建议先把主代理的基本用法过一遍,再回来读Sub Agents,效果会好很多。
1. 先搞清楚Sub Agents的运行机制
1.1 它不是插件,而是一个独立的“角色”
很多第一次接触Claude Code的朋友,会把Sub Agents理解成一个可以被调用的外部脚本,或者类似命令行参数的东西。其实从使用体验看,它更像是一个“带岗位说明书的临时工”。当你在主对话中通过@agent名提到某个Sub Agent时,Claude Code会在后台做这样几件事:读取对应agent的定义文件,把里面的system prompt注入到这次任务的运行上下文中,再按照文件里声明的工具权限去调用工具。也就是说,每一次子代理调用,都相当于在主线任务之外开了一个带有独立人设和技能约束的小环境。任务完成后,子代理会把它的结论交回给主对话,然后又回到“待命”状态。
为什么要这样设计?我自己的理解是:CLI长会话的上下文窗口虽然够大,但把所有事都塞进同一条上下文里,会让主代理的判断变得模糊。比如既让它写代码又让它审代码,写与审之间会互相干扰。拆成Sub Agents之后,每个任务在独立的上下文里完成,主代理只需要做任务分发和结果汇总,这样整体准确率会明显提升。这个设计与人类团队协作非常相似,本质上是在模型的应用层做了一次“职责边界管理”。
1.2 主代理与子代理的协作方式
要理解创建方法,先要理解分工。我用一个生活化的类比:主代理像一个项目经理,它不亲自写字,而是把需求拆成几个明确的任务,交给对应的专业工程师。工程师各自在独立办公室里干活,干完把产出拿回来。这里的“独立办公室”就是子代理的上下文,而“专业工程师”就是子代理的角色设定。
这种协作最直接的价值有三个。第一是上下文隔离,每个子代理只看到自己需要的内容,不会被无关的代码仓库历史干扰。第二是工具权限收敛,你可以只给某个子代理read和grep工具,它就只能做分析和检查,不会顺手把你的配置文件改坏。第三是并发与重试,主代理可以连续向多个子代理派发任务,某个子代理失败了,最多重新调用它,而不会污染主对话的状态。
顺着这个思路往下走,你会发现创建Sub Agents之前真正要考虑的,不是怎么写一段漂亮的提示词,而是先想清楚:我的项目里有哪些经常重复、边界清晰、适合独立执行的任务?想清楚这个问题,后面的配置文件就是水到渠成的事。换句话说,创建方法的本质是任务拆解方法,而不是配置文件语法。
2. 创建前必须摸清的目录与格式规范
2.1 放在哪里:目录结构就是你的代理仓库
Claude Code对Sub Agents的存放位置有约定俗成的标准。按我实际项目的习惯,一般是在项目根目录下建一个.claude/agents/文件夹,每个子代理单独占一个Markdown文件。比如:
my-project/ ├── .claude/ │ └── agents/ │ ├── code-reviewer.md │ ├── test-writer.md │ └── doc-generator.md └── src/如果你愿意,还可以用子目录分类:.claude/agents/review/code-reviewer.md、.claude/agents/review/security-checker.md。Claude Code会递归读取所有子代理文件,所以子目录不会影响识别。这里有一个细节:文件名会作为子代理的标识,但最终实际触发时用的名字是文件头部name字段里定义的值,有些情况下Claude Code会通过文件名兜底。为了避免混乱,我通常会让文件名和name字段保持一致。
这个文件夹还可以放到用户级目录下,实现跨项目共享。那种全局子代理要谨慎命名,因为一多起来就会互相干扰。我的经验是:项目内放那些跟当前代码库强耦合的代理,比如“订单模块审查员”;全局放那些跟仓库无关的能力型代理,比如“Shell命令解释器”。这样从根源上减少命名冲突和职责混乱。
2.2 文件格式:Markdown加YAML头
每个Sub Agents文件本质上是一份带“元数据头”的Markdown文档。头部用YAML格式定义Agent的属性,正文就写具体的指令内容。一个最小可用的文件长这样:
--- name: code-reviewer description: 在用户提出审查代码需求时使用。 tools: - read - grep --- 你是一名代码审查工程师。你的任务是……这段代码演示的是最基础的结构。description字段不要小看,主代理决定是否启用当前子代理时,主要就是靠它来判断。tools字段支持声明允许调用的工具,比如read、grep、list、edit等。没声明的工具,子代理在运行时就不会被分配到。
有朋友会问:model字段要不要写?如果你所有任务都用同一个模型,那就不写,让系统自动选择。如果你希望某些复杂分析用更强的模型,可以在配置里指定,但要清楚这个字段需要额外的授权,而且会直接影响成本。我建议刚开始一律不写,等跑顺了再慢慢调。
2.3 正文指令的写法不能偷懒
配置头负责“身份”,正文负责“能力”。正文里至少要交代清楚四件事:角色、任务边界、输出格式、限制条件。角色让子代理知道它现在是谁,不用长篇大论,一句“你是一名资深前端架构师”就足够。任务边界要明确哪些是它该做的,哪些是不该碰的,比如“只做静态分析,不修改源文件”。输出格式规定交付物的结构,审查报告、测试列表、修改建议,不同任务要不同的模板。限制条件处理不确定性,比如“不确定的地方如实标注,不要猜”。
把这些落到指令里,子代理的行为就会稳定得多。我见过太多只写“你要帮忙审查代码”的配置,结果子代理每次输出的风格和粒度都不一样,根本没法用。所以不要急着堆提示词技巧,先把这四要素写完整,观察几次输出,再迭代优化。
2.4 一个反向建议:不要一开始就追求多而全
新手最容易犯的错误,是第一天就创建五六个Agent,把什么都规划好。实际上你应该先从一两个高频任务开始,跑通以后再逐步加。理由有两个:一是子代理之间会互相影响,数量多了,主代理在选择时反而犹豫;二是你还没摸清每个Agent的脾气,批量配置只会放大问题。先做一个出现频次最高、边界最清晰的子代理,把它做到可靠,再复制这个模式去扩展其他代理。
3. 实操:手把手创建一个代码审查子代理
3.1 先定场景,再定配置
为了演示,我创建一个专门做代码审查的子代理。场景是这样:每次提交代码前,我希望有一个独立的Agent帮我把变更文件过一遍,检查明显的bug、安全隐患和风格问题。任务边界很清晰,输出也容易标准化。我先把场景用一句话写下来:“收到文件路径列表后,逐个读取并审查,最终输出结构化报告。”这句话会成为description的参考。
如果你问这个Agent和主代理自带的审查能力有什么区别,我的答案是:主代理是“泛能力”,任何话题都能聊;子代理是“专能力”,它可以被精准触发、按固定格式输出,而且不会因为主对话里的其他内容分心。这种确定性正是我们把它作为团队工作流一部分的关键。
3.2 完整配置文件逐行拆解
我在.claude/agents/review/code-reviewer.md里写下这个配置:
--- name: code-reviewer description: 对代码文件进行静态审查,擅长发现潜在bug、安全隐患和风格问题。当用户提到“审查代码”、“review”、“看看这段代码”时使用。 tools: - read - grep - list --- 你是一名资深的代码审查工程师,有超过十年的业务代码审查经验。 ## 你的任务 1. 根据用户给出的文件路径列表,逐个读取文件内容。 2. 从以下三个维度进行审查: - 正确性:是否有逻辑错误、边界条件遗漏、空值风险。 - 安全性:是否有注入风险、敏感信息泄露、危险函数调用。 - 可维护性:是否有重复代码、命名混乱、过度复杂的高耦合逻辑。 ## 输出要求 请严格按照下面的Markdown模板输出: ### 审查报告 **文件**: <路径> - **严重问题**: <列出可直接导致故障或安全问题的问题> - **建议优化**: <列出不影响运行但值得改进的问题> - **疑问点**: <列出需要开发者确认的地方> 最后用一句话总结整体风险等级(高/中/低)。 ## 约束 - 只做分析,不要修改任何源文件。 - 如果没有发现问题,也要明确写出“未发现严重问题”。 - 不要提供泛泛的建议,每条建议必须对应具体的行号或代码片段。 - 不确定的内容请标注“需人工确认”。这一步其实就是整篇博文最核心的部分。我逐段解释为什么要这么写。description里用了“当用户提到……时使用”这样的触发词,Claude Code会根据这句话来决定什么时候自动调用这个子代理。太笼统的描述会导致该用的时候不用,不该用的时候乱用。我把“审查代码”“review”“看看这段代码”都写进去,相当于给了它三个非常直觉的触发信号。
tools只给了read、grep、list,没给edit。这是刻意设计的:既然是审查,就不应该让Agent有能力改写代码。一旦工具里出现edit,它可能顺手“好心”把代码改了,反而不好。保持只读权限,从机制上保证它是安全的观察者。如果你后续需要它直接修代码,可以另建一个“自动修复Agent”,把审查和修复分成两个角色,而不是让一个Agent同时干两件事。
正文里我不只告诉它“你要审查”,还给了审查维度、输出模板和约束。这些细节决定了每次输出是否稳定、是否可复用。特别是“输出要求”里的模板,把审查结果拆成“严重问题”“建议优化”“疑问点”,这样主代理拿到结果后可以直接解析,不需要再翻译一遍。这是我做过很多次实验后觉得最省心的输出格式。
3.3 从对话里调用它
创建完文件,回到Claude Code主对话,直接输入:
@code-reviewer 请审查 src/utils/api.ts 和 src/utils/format.tsClaude Code会去读取.claude/agents/review/code-reviewer.md,把里面的指令和用户消息组合成一个独立的子对话。过一会儿,主对话里会返回子代理的完整输出,也就是刚才定义的Markdown模板。
第一次跑的时候,我建议先只传一个文件,看看输出格式是否符合预期。如果格式乱了,优先检查指令里的模板缩进,YAML头后面的正文不要故意加奇怪的换行。Claude对Markdown模板的解析其实很宽松,但输出结构是它自己决定的,如果你没有强调“必须完全按照模板”,它偶尔会自由发挥。所以在“输出要求”开头我就用了“请严格按照”这个强约束词。
3.4 参数传递的三个实用技巧
调用子代理时,除了直接说“审查某文件”外,还有几个提高准确率的小技巧。第一个是显式传递上下文。与其让子代理自己去仓库里找文件,不如把相关文件路径、函数名、需求描述直接写进调用里。比如:“请审查 src/checkout.ts,重点看支付回调里的异常处理和超时逻辑。”子代理的上下文里有了这些线索,就能直接跳到关键位置,省去很多摸索。
第二个是让主代理先收集信息再传给子代理。你可以在主对话里先让Claude跑一次grep找出所有相关文件,然后把结果粘贴成列表,再调用子代理。这样信息经过一次筛选,子代理的上下文质量更高,也不会因为无关文件而分心。
第三个是给子代理设置明确的“完成标准”。比如“审查完输出风险数后不要继续给修改建议”,避免它在输出完报告后还额外发挥一段总结。设置好边界,整个工作流才能自动化。这些技巧本质上都是“信息控制”,子代理吃什么样的上下文,就能吐出什么样的结果,别指望它去猜你脑中没说的需求。
4. 决策逻辑与常见误区:为什么你的子代理不生效
4.1 主代理为什么没选择你的子代理
很多人按照教程创建完Sub Agent,第一次调用却发现系统好像无视它,或者干脆报错。最常见的几个原因里,第一个就是description写得不像触发器。主代理在选择子代理时,会先把用户当前消息和所有子代理的description做匹配。如果你的描述里写了一堆官方文档式的内容:“该Agent用于代码审查,具备静态分析能力……”它反而不会被触发。更好的写法是把“什么时候用”说清楚:“当用户要求审查代码、review、或者检查PR时使用”。让描述变成一条规则,而不是一段职位介绍。
第二个原因是name字段冲突。比如你在项目目录和用户全局目录各放了一个code-reviewer,系统会以哪个为准?实际表现有平台差异,但为了避免踩坑,最好在所有目录里保持名字唯一。我有一次就是因为全局目录里有一个旧版Agent,导致项目里的配置始终没被加载。后来我把全局目录清掉了一些过期的Agent,只留下通用工具型,问题就解决了。
第三个原因是配置文件格式错误。YAML头里如果冒号后面少了一个空格,或者某个字段用了制表符,整个文件都可能被跳过。听起来是低级错误,但在文件多的时候很容易发生。建议创建后用最严格的方式检查一遍,宁可手动输入,也不要复制未知来源的缩进。
4.2 关于“子代理不输出我想要的格式”
如果子代理已经成功运行,但输出格式总是不稳定,问题大概率出在指令的约束强度上。用“请尽量按模板输出”这种语气,Agent往往会发挥;用“必须严格按照下面的Markdown模板输出,模板如下”这种命令式语气,效果会好很多。这不是玄学,模型对指令的强弱程度极其敏感,弱约束等于没有约束。
另外,模板本身不要太长、太复杂。一个审查报告模板如果超过十行,子代理可能会在其中自己加章节。核心字段保持在五到六个以内,让输出结果容易解析。如果确实需要很复杂的输出,可以考虑拆成两个子代理:一个生成原始分析,另一个负责整理成报告。这种做法虽然多一次调用,但每一步的可靠性都会提升。
4.3 工具权限受限导致的“它说它做不到”
有时子代理会告诉你“我没有权限读取这个路径”,其实不是真的没有权限,而是它的tools列表里没有对应的工具。比如你只给了grep,但审查时需要看文件全貌,没有read自然读不完整。这里我建议按最小权限原则来配置,但也要把任务必需的工具给全。代码审查至少需要read和list,需要跨文件搜索就加grep,如果还要统计函数调用关系,可能还要glob。
一旦遇到“它经常说做不到”的情况,先别急着加一堆工具,而是把实际报错信息读一遍,确认缺的是读文件能力还是修改能力。权限配置本身就是设计的一部分,不要为了省事全部放行。一个能做任何事的子代理,和一个只能做指定事的子代理,后者的可控性明显更好,也更适合放进自动化流程。
5. 调优:让子代理更稳定、更高效的实践清单
5.1 控制上下文大小:子代理也要“少食多餐”
子代理虽然独立,但也受同一套上下文窗口限制。如果你的仓库很大,一次把十个文件塞给它,它会分心。最好的做法是让每次调用只处理一两个相关文件,或者用grep先把可能的内容摘出来再传。我自己的一个教训是早期把整个模块的树状结构都丢给子代理,结果它在无关文件里打转,输出里全是“建议优化目录结构”这种通用话术。
后来我养成了一个习惯:每次调用前,先问自己“这次任务的最小必要信息是什么?”然后把信息范围收敛到那个程度。审查单文件就只给单文件;审查跨文件的数据流,就提供关键路径上的三五个文件。少食多餐,它的输出质量会明显提高。很多所谓的“子代理不听指挥”问题,追根溯源都是投放信息太多,把它撑迷糊了。
5.2 让子代理输出“结构化摘要”,而不是长篇大论
很多子代理默认会输出一大段分析,然后给结论。但如果你的下游还要继续用这些输出做汇总,大段散文反而难处理。我建议在指令里明确要求输出结构化摘要,比如“结论在前,证据在后;每条结论必须有文件路径和行号”。这样主代理后续拼接多条子代理结果时,能快速找出共同模式。
如果输出仍然太长,还可以让主代理在调用后做一次“压缩”:“把上面的报告压缩成五条要点。这不属于子代理的职责,属于主代理的后处理。”这样做的好处是主对话里不会堆积大段分析,后续再调用其他子代理时,上下文也更干净。
5.3 权限边界与安全实践
Sub Agents的权限配置是相对独立的,这也是它适合做自动化审查的原因。我有一个原则:任何会产生副作用的工具(edit、write、execute)只有在明确需要时才打开。比如一个自动修复问题的子代理,你可以给它写权限,但必须在指令里约束它只修改指定的匹配区域,不能碰其他代码。
有一次我需要做一个批量重命名工具,子代理的执行结果差点把几个引用关系改错了。后来我给它加了“只输出修改计划,由主代理确认后再应用”的边界,问题就解决了。说到底,Sub Agents给你带来的不仅是执行能力,还有一层安全隔离。你完全可以让一个Agent只做只读分析,另一个Agent在确认后才动文件,中间用主代理做人机确认,这个模式看起来多一步,实际比全自动稳妥得多。
5.4 常见坑位速查
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
| 调用子代理总是没反应 | description触发条件写得太泛 | 改成“当用户……时使用” |
| 子代理输出与预期差异大 | 指令里的约束词太弱 | 使用“必须”“不得”等强约束 |
| 读取文件时报无权限 | tools列表缺少相应工具 | 按需补充read或grep |
| 多个子代理之间名字冲突 | 不同目录存在同一name | 统一命名,避免重复 |
| 上下文窗口不够用 | 传递的信息太多太杂 | 收敛为最小必要信息 |
| 配置文件被跳过 | YAML头格式错误 | 检查冒号和缩进空格 |
这张表是我平时排障时最常用的路径,照着检查一遍,大部分问题都能定位。如果还解决不了,就回到主对话,让Claude自己解释一下“为什么选择调用这个子代理”,有时它会输出决策依据,能帮你找到描述里的盲点。
6. 扩展:把Sub Agents变成你的项目资产
6.1 从单一代理到多代理协作
当你熟悉了创建单个子代理之后,可以尝试让它们协作。最简单的模式是:主代理作为协调者,先调用一个“任务分解Agent”把需求拆成子任务,然后分别调用“代码实现Agent”和“测试编写Agent”,最后再调用“审查Agent”把关。每个Agent各司其职,主代理只负责粘合。
这种模式的好处是,你可以从零开始逐块替换自己以前的手动流程。一开始只加一个审查Agent,慢慢再加测试生成Agent、文档Agent,最后形成一套完整的流水线。不要试图第一天就搭一个全自动平台,风险很大。我身边有同行把整套流程跑起来之后,新功能的迭代速度确实快了不少,但代价是要花不少时间维护这些Agent的描述和权限。
6.2 团队共享子代理库
Sub Agents的配置文件是纯文本,天然适合放进Git仓库。所以它不只是个人生产力工具,也是团队资产。你可以把.claude/agents目录纳入项目仓库中,让所有协作者共享一套Agent定义。新成员加入时,不必重新学习你的prompt习惯,直接就能享受到同样质量的输出。
不过在共享时要注意两点:一是description里的触发词要统一,避免不同工程师用不同说法导致Agent行为不一致;二是工具权限要按环境区分,比如本地开发时允许execute,在CI环境里就要关掉,避免自动执行带来的风险。把这些约定写进项目的贡献文档,后续维护会轻松很多。
6.3 后面我打算继续折腾的方向
这篇文章主要围绕创建方法展开,但Sub Agents的花样远不止这些。后续我会继续写怎么把多个子代理编排成复杂工作流,以及如何通过CLI命令动态生成新的Agent配置文件,让系统能根据项目结构自动调整代理数量。如果你现在还在单个Agent的阶段,可以先从最基础的配置入手,跑通一个简单的审查代理之后,再慢慢扩展。对一个团队来说,Sub Agents不是一次性配置,而是长期演进的基础设施,值得你用心去设计。
最后说点我自己的习惯。刚开始用Sub Agents时,我总想把所有能力塞进一个代理里,结果提示词越来越长,反而容易出错。后来改成小粒度的代理,每个只干一件事,名字和描述也尽量直白,配合起来反而顺手很多。希望这篇文章能给你一些灵感,少走点弯路。