AI 子代理(Subagents):何时用、怎么用完全指南
写在前面
本文已收录到 AI编程一站式导航。本文链接:[03.3 AI 子代理使用完全指南](code.ai80.vip/ai-tool-gui… AI 子代理使用完全指南) 强烈推荐:AI编程巴士网站:稳定纯净的ClaudeCode套餐供应;
你的 Agent 花了 15 分钟探索,找到了你需要的东西,然后忘了你的请求。现在你在 400 行日志里滚来滚去,试图找出哪里出了问题。
你试过规则(Rules)。试过命令和技能(Commands and Skills)。它们有帮助,但没解决根本问题:一个上下文窗口能装的东西有限,装太多就乱了。
解决方案是子代理(Subagents)。这里有一些关于子代理是什么、何时用、怎么优化的实战建议。
你可能会好奇:
- 子代理到底是什么?
- 跟技能(Skills)有什么区别?
- 什么时候该用子代理?
- 怎么定义和优化子代理?
- 有哪些常见坑?
什么是子代理
子代理是你定义的专家 Agent,主 Agent 可以生成它来做聚焦、隔离的工作,然后把结果报告回来。
就这么简单。干净的上下文是让主线程保持可读的关键,而工作本身可以很嘈杂。对于高级用户,子代理还提供了并行性、工具范围控制、混合模型的能力,把单个对话变成一个协作团队。
在 Builder 里,你可以通过在 .builder/agents/ 创建一个 Markdown 文件来定义子代理,包含名称、描述和工具列表。定义好后,你可以在聊天中按名称调用它,或者一次生成多个子代理来并行工作。
你可以在 Builder 文档里读到所有关于使用子代理的内容。
为什么子代理在实践中感觉很好
大多数 Agent IDE 共享相同的工作流循环。你描述意图,Agent 探索,它改代码,然后你需要验证。
问题是探索和验证产生最多的输出。
所以主聊天最后包含:
- 搜索结果
- 测试输出
- 半个计划
- 一个"完成"的声明
这就是为什么你最后像读日志文件一样重读自己的聊天记录。
子代理让你把嘈杂的工作移到它自己的上下文里,然后只拉回有用的摘要。
子代理 vs 技能
如果你已经有一个好的技能设置,不要扔掉它。技能仍然是可重复流程的最佳默认选择。
如果你想要一个清晰的心智模型,从 Agent 技能 vs 规则 vs 命令的分解开始。这里是你在构建时可以用的简短版本:
- 使用技能:当你想让当前 Agent 遵循更好的流程
- 使用子代理:当你需要不同的工作者配置
"不同配置"意味着以下之一:
- 你需要干净的上下文
- 你需要不同的工具访问权限,比如只读探索
- 你需要一个持怀疑态度的验证者,它不共享实现者的偏见
- 你想要并行工作
如果这些都不是,技能更容易维护。
如何定义自定义子代理
大多数支持子代理的工具使用相同的基本模式:带有 YAML frontmatter 的 Markdown 文件,存储在 ~/.[provider-name]/agents/ 用于用户级 Agent,或 .[provider-name]/agents/ 用于项目级 Agent。
例如,在 Builder 中你可以创建 .builder/agents/repo-scout.md:
name: repo-scout
description: Read-only explorer. Find the right files and report back with paths and brief notes.
tools: Read, Grep, Glob
Return:
- status: ok | needs_info
- relevant_paths: list of 5 to 12 paths
- notes: 1 to 2 sentences per path
- open_questions: list of questions for the parent to ask the user
frontmatter 定义了契约。Markdown 正文成为系统提示(System Prompt),而不是普通提示。
把项目特定的子代理存在你的仓库里,这样你的团队可以共享它们。把个人子代理存在你的主目录,这样它们跟着你跨项目。
系统提示的坑
系统提示的工作方式跟你在聊天里输入的普通提示不同。Agent 先应用这些背景指令,在处理你的对话提示之前塑造每个响应和 Agent 的核心行为。
普通提示是你当下给的任务。 它回答"你现在应该做什么?"系统提示设置整个会话的持久策略、角色和约束。 它回答"你是谁、你能做什么?"
这个区别对优化很重要。系统提示应该在多个任务中保持稳定。如果你在系统提示里嵌入任务特定的细节,你就过拟合到一个工作流了,上下文改变时子代理就坏了。
例如,如果你的系统提示说"总是使用 Stripe API 处理支付",当你让它在使用 PayPal 的项目上工作时,那个子代理就坏了。把"使用 Stripe"放在那个特定任务的普通提示里。
把系统提示聚焦在角色、范围和工具策略上。把特定的任务指令放在你调用子代理时的普通提示里。
你会经常用的两个子代理模式
一旦你有了子代理,大多数有用的工作流归结为两个模式。
链式(Chaining)
链式是修复"我的 Agent 忘了我问什么"问题的最佳方法。不是一个 Agent 试图在同一个上下文里研究、实现和验证,你把工作拆分成流水线。
工作方式是这样的:一个 repo scout 找到文件并返回路径。然后你,或另一个 Agent,用新鲜的上下文实现。最后,一个验证者检查工作,没有实现偏见。每次交接都重置上下文。研究噪音不会泄漏到实现里,实现细节不会让验证产生偏见。
明确告诉你的父 Agent 序列:"先用 repo-scout 找文件。然后实现改动。然后用验证者确认。"如果你发现自己反复输入这个,把它保存为可重用的命令或技能。
扇出(Fan-out)
扇出就是人们说"多 Agent"时的意思。你把工作拆成块,同时运行几个子代理。
这很适合:
- 扫描多个模块寻找同样的问题类型
- 为设计决策收集选项
- 把约束翻译成不同形式,比如清单和代码补丁计划
如果你不小心,这也是你可能烧掉大量时间和 token 的地方。
要让扇出工作,明确告诉父 Agent 如何拆分工作以及每个子代理应该返回什么。例如:"对于每个模块,生成一个子代理,扫描废弃的 API 使用,返回包含文件路径和行号的发现列表。"
什么时候子代理会让事情变糟
子代理不是魔法。它们引入了新的失败模式,可能让你比开始时更糟。
混乱的交接创造上下文臃肿
当子代理返回一墙文本而不是结构化摘要时,你没有解决上下文问题。你只是移动了它。父 Agent 仍然要读、总结或忽略那个输出。如果交接格式在调用之间漂移,父 Agent 花 token 重新解析而不是行动。定义严格的输出契约并强制执行。
给子代理太多权限
上下文窗口干净的子代理仍然跟父 Agent 共享同样的文件系统、数据库和 API 密钥。如果你默认给它写权限、Bash 或 MCP 工具,它可以删除文件、运行危险命令或调用生产 API,而不理解更广泛的上下文。
更糟的是,子代理缺乏父 Agent 对完整对话历史的意识。子代理可能覆盖父 Agent 最近编辑的文件,或者运行父 Agent 已经应用的迁移。没有清晰的所有权边界,子代理互相踩工作,制造比原始任务清理起来更久的混乱。
并行性倍增成本和速率限制风险
扇出感觉像免费的加速,直到你碰到提供商速率限制或烧完你的 token 预算。三个并行运行的子代理使用三倍的 token。十个子代理可以触发速率限制,让你整个工作流停滞。
没有并发硬上限,你有对自己发起拒绝钱包攻击的风险。从低限制开始,只有在你有证据表明协调开销值得成本时才提高。
如何优化子代理
子代理失败是协调失败。护栏是你在非确定性系统中优化的方式,通过限制可能性,这样你可以调试剩下的部分。
- 保持职责不重叠。 如果两个子代理可以编辑同样的东西,它们会打架。给它们干净的角色。
- 让契约明确。 在每个子代理提示里,详细说明它必须返回什么。固定的输出形状胜过长提示。
- 限制并行度。 设置硬限制。三个并发子代理是个好默认值。
- 把输出当作未验证的。 子代理的重点是提议。验证者的重点是确认。
- 使用只读子代理作为安全边界。 当抓取网页内容或读取不可信来源时,使用只读子代理来隔离风险。它可以摄取内容并返回结构化摘要,但不能执行隐藏命令或编辑文件。父 Agent 然后在行动前验证那些发现,创造一个自然的决策点,打破提示注入链。
如何调试子代理
当子代理偏离轨道时,你的第一反应可能是调整提示措辞。但最有效的调试工具是范围缩减。
Agent 在巨大的可能性空间中运作。不像传统代码那样 bug 有特定原因,Agent 可以以无数种方式失败。调试的第一步总是缩小那个可能性空间。
把子代理削减到只读工具,测试它,然后一次添加一个能力。 当你找到能重现失败的最小集合时,你就隔离了问题。
对于持续性问题,构建 evals。创建一个有代表性任务的小测试仓库,持续对它运行你的子代理。Evals 把"感觉检查"变成可测量的信号。你会知道你最新的提示改动是帮助了还是转移了失败模式。
工具之间的子代理差异
跨工具的子代理使用相同的想法:独立的上下文、独立的角色。现在唯一的差异是后台执行、嵌套支持和模型灵活性。
但总体来说,如果你深入学习一个工具,子代理模式是可以转移的。你主要是翻译配置格式。
模型灵活性
Claude Code 限制你只能使用 Claude 模型作为子代理。
Builder、OpenCode 和 Cursor 让你定义任何模型作为子代理,这让你可以为每个 LLM 使用它们最擅长的。
后台 vs 前台
Claude Code 和 Cursor 支持后台子代理,这些子代理可以在不阻塞你跟主 Agent 持续对话的情况下运行。
这对告诉主 Agent 在后台运行长任务(比如测试和类型检查)很有用,这样子代理在主对话继续的同时修复代码。
如果你的工具没有后台 Agent,你仍然可以在同一个分支或 worktree 上开始独立聊天,获得大致相同的效果。
子代理生成子代理
OpenCode 明确支持嵌套子代理。子代理可以创建自己的子会话,你可以在父和子之间导航。
这是个很酷的高级用户功能,但除非你在监测 OpenCode 以追踪你的 Agent 去了哪里、做了什么,否则调试起来会很乱。
因此,其他工具不支持这个。
关于子代理的结语
你真的不需要为所有事情都用子代理。
从技能开始。它们更简单,也足够强大。
当你的 Agent 一直忘记你问了什么、当你需要并行工作、或者当你想要一个不被第一次尝试偏见的第二意见时,才用子代理。但不要只为了感觉有生产力就生成子代理。
否则你只是在用一个混乱换另一个混乱,创造协调开销却没有解决上下文臃肿问题。
把你的子代理描述保持在一句话,在开始之前确切知道"完成"长什么样。 没有清晰成功标准的子代理会游荡、产生噪音,交回一个半成品答案污染你的主上下文。
契约搞对了,子代理就成了你可以信任的专家。搞错了,你又回到滚日志想知道哪里出问题了。
常见问题
Q: 子代理和技能(Skills)有什么区别?
A: 技能是让当前 Agent 遵循更好流程的指令(Markdown 文件)。子代理是主 Agent 可以生成的专家 Agent,用于独立的工作。当你需要干净上下文、不同工具权限、独立验证或并行工作时用子代理。当你只是想优化流程时用技能。
Q: 什么时候应该用子代理?
A: 当以下任一情况成立时用子代理:(1)Agent 一直忘记你问了什么(上下文太乱);(2)需要不同的工具访问权限(比如只读探索);(3)需要独立验证(不被实现偏见);(4)需要并行工作(扫描多个模块)。如果这些都不是,技能更简单。
Q: 如何定义子代理?
A: 创建带有 YAML frontmatter 的 Markdown 文件,存储在 .builder/agents/(项目级)或 ~/.builder/agents/(用户级)。frontmatter 定义名称、描述、工具列表。Markdown 正文是系统提示,定义输出契约和行为规则。
Q: 子代理的两个核心模式是什么?
A: 链式(Chaining) :顺序流水线(Scout → Implement → Verify),每次交接重置上下文,避免噪音泄漏。扇出(Fan-out) :并行执行多个子代理,适合扫描多个模块或收集选项,但要注意成本和速率限制。
Q: 子代理会带来什么新问题?
A: (1)混乱交接:子代理返回墙文本而非结构化摘要,上下文臃肿只是被移动了;(2)权限过大:子代理可能删文件、覆盖父 Agent 的工作;(3)成本倍增:并行扇出会烧 token、触发速率限制。需要定义严格契约、限制权限、控制并发度。
Q: 如何调试子代理?
A: 范围缩减是关键。把子代理削减到只读工具,测试,然后一次添加一个能力。找到能重现失败的最小集合。对于持续性问题,构建 evals(小测试仓库),把"感觉检查"变成可测量信号。
Q: 不同工具的子代理有什么区别?
A: 核心思想相同(独立上下文、独立角色),主要差异在:(1)模型灵活性:Claude Code 只能用 Claude 模型,Builder/OpenCode/Cursor 可以混合模型;(2)后台执行:Claude Code/Cursor 支持,其他工具可用独立聊天模拟;(3)嵌套支持:OpenCode 支持子代理生成子代理,但调试复杂。
本文已收录到 AI编程一站式导航。本文链接:[03.3 AI 子代理使用完全指南](code.ai80.vip/ai-tool-gui… AI 子代理使用完全指南) 强烈推荐:AI编程巴士网站:稳定纯净的ClaudeCode套餐供应;