Skip to content
共伞

子代理设计

为什么 Agent 需要并行子代理——上下文隔离、模型分层与专业化的设计权衡,以及 Peri 如何落地这套设计。

这篇文章从设计角度拆解子代理:为什么需要它、它在 Agent 生态里处于什么位置、设计时需要关注什么、Peri 是怎么实施的。不讲逐个功能点,讲功能背后的决策。

为什么需要子代理

先看单 Agent 的硬约束,子代理解决的都是这些约束的后果:

一个上下文窗口。 主会话的上下文同时装着对话历史、中间检索结果和最终输出。搜索 100 个文件、读 20 份文档,中间过程全塞进一个窗口——token 成本翻倍,且上下文越长,模型对早期细节的注意力越差。这不是可以绕过的工程问题,是 LLM 的本质特性。

一个推理链。 主 Agent 一次只能做一件事。写代码时不能同时审查,审查时不能同时搜索。所有任务串行排队,总耗时是所有任务耗时之和。

一个模型。 会话绑定一个模型档位。用强模型做机械搜索是浪费,用弱模型写核心代码会出错。模型选择是全局的,无法按任务粒度差异化。

子代理的解法是承认”一个 Agent 不够”:

并行

多个子代理同时跑各自的推理链,把串行等待变成并行推进。审查、搜索、编码互不阻塞。

隔离

子代理的中间过程留在自己的上下文里,主会话只收到结论。主上下文保持干净,token 开销可控。

专业化

每个子代理可以绑定不同的模型和工具集:搜索用便宜的,实现用强的,审查用独立视角的。

在 Agent 生态中的定位

多 Agent 的谱系可以按”谁决定下一步做什么”来排:

方案谁决定并行与分工上下文关系可重放
手动开多个会话用户完全隔离
子代理主 Agent(LLM)隔离 + 结论回传
编排工作流脚本显式传递

子代理处在中间:并行与否由 LLM 在运行中判断。主 Agent 评估任务复杂度,决定要不要派、派几个、派给谁、怎么汇总。它把”并行”从用户的手工操作变成了 Agent 的运行时能力。

两个容易混淆的相邻概念,划清界限:

  • 工具调用 vs 子代理。工具调用是”同一上下文中多执行一步”,结果直接落回当前推理链。子代理是独立的 ReAct 循环——自己的系统提示词、自己的上下文窗口、自己的工具集,走完整个推理过程才把结论带回来。
  • Fork vs 子代理。Fork 继承父会话的完整上下文,适合”延续”——基于已有讨论继续推进。子代理默认隔离上下文,适合”委派”——把一件独立的事交给一个干净的执行者。前者解决上下文延续,后者解决上下文隔离。

子代理是执行单元,不是决策单元。它不决定”做什么”,只执行”怎么做”,然后带着结果回来。

设计时需要关注什么

上下文:隔离多少,共享什么

全隔离会丢环境认知——子代理不知道项目规范、当前状态、之前的讨论;全共享又回到上下文膨胀。折中是冻结快照 + 结论回传

  • 子代理出发时捕获一次环境(CLAUDE.md、Skills 摘要、git 状态),看到的世界与主 Agent 一致
  • 执行过程中的中间结果不回流,只回传最终结论

注意快照语义:子代理看到的是”出发那一刻”的世界。主会话在它执行期间的新进展,它不知道——需要让子代理用最新状态,就得等它完成后再派一轮。

模型:任务分层

子代理最大的成本杠杆是模型。机械任务(搜索、摘要、分类)用便宜模型就够,推理密集任务(实现、审查、设计)需要强模型。成本策略应该在子代理定义里显式声明,而不是让主 Agent 每次临时猜。

并发:并行上限

并行不是免费的:API 速率限制、结果洪峰、多个执行者对同一文件的写冲突。上限必须存在(默认 3 个并行),且要可调——免费档 API 需要降到 2 个避免触发限流。

安全:权限边界

子代理应有独立于主 Agent 的权限。搜索型子代理默认只读(Read、Grep、Glob),连”修改文件”的选项都不该有。权限是设计的一部分,不是事后补救。

结果契约

后台子代理的结果如何回到主会话,必须有一个可解析的结构(如 Scope / Result / Key files / Files changed),否则结论淹没在自由文本里,主 Agent 无法可靠消费。异步完成时,结果通过通知推送进主会话的消息队列,主 Agent 下一轮取到。

Peri 如何实施

内置类型按任务谱系划分。 6 种:explorer(代码搜索)、plan(方案设计)、coder(代码实现)、verification(实现验证)、web-researcher(网络研究)、general-purpose(兜底)。每种都是”模型 × 权限 × 行为”三者的显式组合——搜索用 haiku + 只读,实现用 sonnet + 可写,验证用 sonnet + 只读 + 可跑构建。类型不是任意组合的产物,是对”任务需要什么能力”的逐项决策。

执行模式由两个决策轴派生。 是否需要父会话上下文(fork)、是否要等结果(run_in_background):

  • 默认同步:独立上下文,等结果,适合单次委派
  • Fork:继承上下文快照,等结果,适合连续协作
  • 后台:独立上下文,不等结果,适合独立批处理

两个布尔值覆盖了大多数协作场景,不需要更复杂的模式体系。

自定义机制是”定义文件 + 描述驱动派发”。.claude/agents/ 下放一个 Markdown 文件就是一个新子代理:frontmatter 声明模型、工具白名单,正文是系统提示词。description 字段决定主 Agent 何时派发它——写清楚用途,派发就准;写”帮助”这种,派发就玄学。同名定义按作用域覆盖:项目级 > 用户级 > 插件级。

---
name: security-auditor
description: 审查代码变更的安全性:注入、认证绕过、数据暴露
tools: Read, Grep, Glob
model: sonnet
---
你是安全审查专家。对每个发现,标注文件、行号、风险等级和修复建议。只输出报告,不修改任何文件。

运行时是完整的多进程协作。 每个子代理一个独立上下文和独立推理循环,事件通过通道转发给父 Agent,后台任务完成时结果注入主会话消息队列。从调用方看就是一个 Agent 工具调用:

主 Agent ──Agent("explorer", "查找 src/ 中的 TODO")──▶ 子代理
▲ │
└────────────── 结构化结论注入主会话 MQ ◀───────────────┘

权衡

子代理把并行的决策权交给 LLM,换来的是灵活性,代价是不可重放:同样的任务每次派发都不同,流程无法保存、重跑、审计。当任务需要确定性时——批量、固定流程、质量门禁——应该把控制流从上下文里拿出来变成代码,这就是工作流设计的出发点。