SUBAGENTS:何时以及如何使用它们(读书笔记)

作者:ALICE MOORE

2026年2月3日


你的代理花了15分钟探索,找到了你需要的东西,然后忘记了你的请求。现在你正在滚动400行日志,试图找出哪里出了问题。

你已经尝试过规则。你已经尝试过命令和技能。它们有帮助,但没有解决根本问题:一个上下文窗口在变得混乱之前只能容纳这么多内容。

解决方案是子代理。这里有一些实用的建议,关于什么是子代理,何时使用它们,以及如何为你的工作流程优化它们。


什么是子代理

子代理是一个你定义的专业代理,你的主代理可以生成它来执行专注的、隔离的工作,然后报告结果。

这就是整个功能。干净的上下文是你在工作变得嘈杂时保持主线程可读性的方式。对于高级用户,子代理还提供并行性、工具范围和混合模型的能力,将单个对话变成一个协调的团队。

在Builder中,你可以通过在.builder/agents/中创建一个包含名称、描述和工具列表的markdown文件来定义一个子代理。一旦定义,你可以在聊天中按名称调用它,或者同时生成多个子代理进行并行工作。

你可以在Builder的文档中阅读所有关于使用子代理的信息。


为什么子代理在实践中感觉良好

大多数代理IDE都共享相同的工作流程循环。你描述意图,代理探索,它更改代码,然后你需要验证。

问题是探索和验证产生最多的输出。

所以主聊天最终会持有:

  • 搜索结果
  • 测试输出
  • 一半的计划
  • 一个"完成"的声明

这就是你最终像阅读日志文件一样重新阅读自己的聊天历史记录的原因。

子代理让你将嘈杂的工作移动到自己的上下文中,然后只拉回有用的摘要。


子代理与技能

如果你已经有了一个良好的技能设置,不要扔掉它。技能仍然是可重复程序的最好默认选择。

如果你想要一个清晰的心智模型,从代理技能与规则与命令的分解开始。这是你在构建时可以使用的简短版本:

  • 当你希望当前代理遵循更好的程序时,使用技能
  • 当你需要不同的工作配置文件时,使用子代理

"不同的配置文件"意味着以下之一:

  • 你需要干净的上下文
  • 你需要不同的工具访问权限,比如只读探索
  • 你需要一个不共享实现者偏见的怀疑性验证器
  • 你想要并行工作

如果这些都不成立,技能更容易维护。


如何定义自定义子代理

大多数支持子代理的工具都使用相同的基本模式:带有YAML前matter的markdown文件,存储在~.[provider-name]/agents/(用户级代理)或.[provider-name]/agents/(项目级代理)。

例如,在Builder中,你会创建.builder/agents/repo-scout.md:

---
name: repo-scout
description: 只读探索者。找到正确的文件并返回路径和简要说明。
tools: Read, Grep, Glob
---
Return:
  - status: ok | needs_info
  - relevant_paths: 5到12个路径的列表
  - notes: 每个路径1到2句话
  - open_questions: 父代理需要向用户提问的问题列表

前matter定义了契约。markdown正文变成了系统提示,而不是普通的提示。

将项目特定的子代理存储在你的仓库中,以便你的团队共享它们。将个人子代理存储在你的主目录中,这样它们可以跨项目跟随你。


系统提示的陷阱

系统提示与你输入到聊天中的普通提示不同。代理首先应用这些背景指令,在处理你的对话提示之前塑造每个响应和代理的核心行为。

普通的提示是你当下给予的任务。它回答"你现在应该做什么?"系统提示为整个会话设置持久的策略、角色和约束。它回答"你是谁,你能做什么?"

这种区别对优化很重要。系统提示应该在许多任务中保持稳定。如果你在系统提示中嵌入特定任务的细节,你会过度拟合一个工作流程,当上下文变化时子代理就会崩溃。

例如,如果你的系统提示说"总是使用Stripe API进行支付",当你要求它在使用PayPal的项目上工作时,这个子代理就会崩溃。将"使用Stripe"放在该特定任务的普通提示中。

保持系统提示专注于角色、范围和工具策略。当你调用子代理时,将具体的任务指令放在普通提示中。


你会不断使用的两种子代理模式

一旦你有了子代理,大多数有用的工作流程都简化为两种模式。

链式调用

链式调用是解决"我的代理忘记了我要求什么"问题的最好方法。不是让一个代理在同一个上下文中尝试研究、实现和验证,而是将工作分成一个管道。

这是它的工作原理:一个仓库侦察员找到文件并返回路径。然后,你或另一个代理,用新鲜的上下文实现。最后,一个验证器在没有实现偏见的情况下检查工作。每次交接都会重置上下文。研究噪音不会泄漏到实现中,实现细节也不会影响验证。

明确告诉你的父代理序列:"首先使用仓库侦察员来查找文件。然后实现更改。然后使用验证器来确认。"如果你发现自己反复输入这个,可以将其保存为可重用的命令或技能。

扇出

当人们说"多代理"时,他们指的是扇出。你将工作分成块,同时运行几个子代理。

这对于以下情况很棒:

  • 扫描多个模块以查找相同类型的问题
  • 为设计决策收集选项
  • 将约束转换为不同的形式,如检查清单和代码补丁计划

如果你不小心,这也是你可能会浪费大量时间和令牌的地方。

要使扇出工作,告诉父代理如何分割工作以及每个子代理应该返回什么。例如:"对于每个模块,生成一个扫描已弃用API使用情况的子代理,并返回包含文件路径和行号的发现列表。"


子代理何时会让事情变得更糟

子代理不是魔法。它们引入了新的故障模式,可能会让你比开始时更糟。

混乱的交接导致上下文膨胀

当一个子代理返回一大段文本而不是结构化的摘要时,你没有解决上下文问题。你只是移动了它。父代理仍然必须阅读、总结或忽略那个输出。如果交接格式在调用之间漂移,父代理会花费令牌重新解析而不是行动。定义严格的输出契约并强制执行它。

给子代理太多权限

具有干净上下文窗口的子代理仍然与父代理共享相同的文件系统、数据库和API密钥。如果你默认给它写访问权限、Bash或模型上下文协议(MCP)工具,它可以在不了解更广泛上下文的情况下删除文件、运行危险命令或调用生产API。

更糟糕的是,子代理缺乏父代理对完整对话历史的意识。子代理可能会覆盖父代理最近编辑的文件,或者运行父代理已经应用的迁移。如果没有明确的所有权边界,子代理会互相干扰对方的工作,并制造出比原始任务更难清理的混乱。

并行性增加了成本和速率限制风险

扇出感觉像是免费的加速,直到你达到提供商的速率限制或耗尽你的令牌预算。三个并行运行的子代理使用三倍的令牌。十个子代理可能会触发速率限制,使你的整个工作流程停滞。

如果没有对并发性的硬性限制,你可能会对自己发起拒绝钱包攻击。从低限制开始,只有当你有证据表明协调开销值得成本时才提高它。


如何优化子代理

子代理故障是协调故障。护栏是通过限制可能性以便你可以调试剩余部分来优化非确定性系统的方法。

  • 保持职责不重叠。如果两个子代理可以编辑同一个东西,它们会互相争斗。给它们清晰的角色。
  • 使契约明确。在每个子代理提示中,明确说明它必须返回什么。固定的输出形状胜过长的提示。
  • 限制并行性。设置硬性限制。三个并发子代理是一个好的默认值。
  • 将输出视为未经验证的。子代理的目的是提出建议。验证器的目的是确认。
  • 将只读子代理用作安全边界。当抓取网络内容或读取不受信任的来源时,使用只读子代理来隔离风险。它可以摄取内容并返回结构化的摘要,但不能执行隐藏的命令或编辑文件。然后父代理在行动之前验证这些发现,创建一个自然的决策点,打破提示注入链。

如何调试子代理

当一个子代理出轨时,你的第一反应可能是调整提示措辞。但最有效的调试工具是范围缩减。

代理在巨大的可能性空间中运行。与传统代码中错误有特定原因不同,代理可以以无数种方式失败。调试的第一步总是缩小那个可能性空间。

将子代理缩减为只读工具,测试它,然后一次添加一个功能。当你找到重现故障的最小集合时,你就已经隔离了问题。

对于持续存在的问题,构建评估。创建一个具有代表性任务的小型测试仓库,并连续运行你的子代理。评估将"感觉检查"变成可测量的信号。你会知道你最新的提示更改是否有帮助,或者是否改变了故障模式。


工具在子代理方面的差异

跨工具的子代理使用相同的想法:分离的上下文,分离的角色。目前唯一的区别是后台执行、嵌套支持和模型灵活性。

但总的来说,如果你深入学习一个工具,子代理模式是可以转移的。你主要会转换配置格式。

模型灵活性

Claude Code限制你只能在子代理中使用Claude模型。

Builder、OpenCode和Cursor允许你将任何模型定义为子代理,这让你可以使用每个LLM做它们最擅长的事情。

后台与前台

Claude Code和Cursor支持后台子代理,这些子代理可以在不阻塞你与主代理的持续对话的情况下运行。

这对于告诉主代理在后台运行长期任务(如测试和类型检查)很有用,这样子代理可以在主对话继续的同时修复代码。

如果你的工具没有后台代理,你仍然可以在同一个分支或工作树上启动一个单独的聊天,获得类似的效果。

子代理生成子代理

OpenCode明确支持嵌套子代理。子代理可以创建自己的子会话,你可以在父代理和子代理之间导航。

这是一个很酷的高级用户功能,但除非你正在使用OpenCode来跟踪你的代理去了哪里以及它们做了什么,否则它会变得难以调试。

因此,其他工具不支持这个功能。


关于子代理的最终建议

你真的不需要为所有事情都使用子代理。

从技能开始。它们更简单,而且功能强大。

当你的代理不断忘记你的要求,当你需要并行工作,或者当你想要一个不受第一次尝试偏见影响的第二个意见时,才使用子代理。但不要只是为了感觉高效而生成子代理。

否则你就是在用一个混乱换取另一个混乱,创造了协调开销而没有解决上下文膨胀问题。

将你的子代理描述保持在一句话,并在开始之前确切地知道"完成"是什么样子。没有明确成功标准的子代理会游荡,产生噪音,并返回一个污染你主上下文的未完成答案。

把契约做对,子代理就会成为你可以信任的专业人士。做错,你就会回到滚动日志,想知道一切都出了什么问题。

今天就在Builder中尝试它们。


#标签 #AI代理 #子代理 #软件开发 #工作流程优化 #Builder #ClaudeCode #Cursor #OpenCode