第11章-Sub-Agent协作与编排《从Harness Engineering 到 Loop Engineering:长程任务Agent原理与实战》
第 11 章 Sub-Agent 协作与编排
核心命题:当单 Agent 的认知带宽逼近物理极限,分工不再是工程优化项,而是长程任务得以完成的唯一路径。Sub-Agent 不是"多挂几个工具"那么简单,它是一套关于职责切分、上下文隔离、结果整合的完整工程哲学。本章将从原理到实现,把 Sub-Agent 协作与编排的全貌拆解给你看。
11.0 引子:一个人写不完一本书
让我们从一个真实的场景说起。
你在写一本 30 万字的技术书。全书 15 章,每章平均 2 万字,每章内部又有 8-12 个小节,每个小节里要穿插代码、图表、案例、引文。如果你一个人顺序写下去,每天写 5000 字,需要 60 天;如果再算上调研、改稿、润色、推翻重来,保守估计 4-6 个月。
更致命的是:写到第 8 章时,你已经记不清第 2 章的细节;写到第 12 章时,前面章节的术语命名、章节风格、论证脉络早已在上下文里被压缩成模糊的影子。单 Agent 的"个人英雄主义"在长程任务面前,是一种物理上不可持续的工作方式。
这本书的写作过程,本身就是一个长程任务的缩影:
- 认知带宽受限:人脑(或单 Agent 的工作记忆)同时能处理的概念数量有限
- 上下文窗口有限:前文信息会被压缩、遗忘或失真
- 专业分工必要:调研、写作、审校、配图、排版,是不同的技能栈
- 并行机会存在:第 3 章和第 7 章之间如果没有强依赖,可以并行推进
解决这个问题的工程答案,就是 Sub-Agent 协作与编排。把一个长程任务,按职责、按阶段、按依赖关系切分给多个专职 Agent,每个 Agent 拥有独立的上下文、独立的工具、独立的会话,最后由一个协调者把结果整合起来——这本质上是把人类组织架构的智慧搬到 Agent 系统里。
但这里有一个深刻的不对称:人类组织架构是几千年试错沉淀的产物,而 Agent 编排是个新事物,我们还没有足够的时间去沉淀"最佳实践"。本章要做的,就是把已有的认知(包括 Claude Code、AutoGen、LangGraph、OpenAI Swarm 等框架的实践)系统化、原理化,让你能据此设计自己的 Sub-Agent 系统。
11.1 为什么需要 Sub-Agent
11.1.1 单 Agent 的认知带宽限制
我们先做一个思想实验。假设你有一个拥有 200K token 上下文窗口的强大 Agent,你让它完成一个复杂任务:“调研 5 个 AI 框架的最新进展,对比它们的架构差异,写一份 5000 字的评估报告,并给出选型建议”。
这个任务看起来不大,但展开后其实包含:
- 5 次独立的调研子任务(每个框架一次 web 搜索 + 文档阅读 + 信息抽取)
- 1 次横向对比(把 5 份调研结果放在一起做矩阵分析)
- 1 次报告撰写(按用户指定的结构组织输出)
- 1 次选型推理(基于对比矩阵做决策)
每一步都消耗上下文。光是 5 次调研,把搜索结果原文都塞进上下文,可能就吃掉了 80K token。等到要写报告时,前面的细节已经模糊;等到要做选型推理时,对比矩阵的某些单元格已经被覆盖。
这就是认知带宽限制的本质:单 Agent 在长程任务中,不是"能力不足",而是"注意力不足"。模型参数足够大、推理能力足够强,但上下文窗口是物理边界,超过这个边界的信息要么被压缩、要么被遗忘、要么根本进不来。
金句:单 Agent 的极限不是模型能力,是上下文窗口。Sub-Agent 不是用来"变强"的,是用来"扩容"的。
11.1.2 上下文窗口的物理约束
让我们把上下文窗口这件事讲透。
| 模型 | 上下文窗口 | 等价于多少页书 |
|---|---|---|
| GPT-3 (2020) | 4K token | 约 8 页 |
| Claude 2 (2023) | 100K token | 约 200 页 |
| GPT-4 Turbo (2024) | 128K token | 约 256 页 |
| Claude Sonnet 4 (2025) | 200K token | 约 400 页 |
| Gemini 1.5 Pro (2024) | 1M token | 约 2000 页 |
| Claude (with auto compact) | 实际有效 ~1M | 约 2000 页 |
看起来很大?不。我们来看看真实任务的上下文消耗:
| 任务类型 | 单次上下文消耗 | 备注 |
|---|---|---|
| 一次简单问答 | 1-3K | 几乎不消耗 |
| 一次代码修改(读 1 文件 + 改 + 写) | 5-15K | 中等 |
| 一次 web 搜索(含搜索结果原文) | 10-30K | 单次搜索就吃掉 |
| 一次多文件重构(10 个文件) | 50-150K | 接近窗口上限 |
| 一次端到端 bug 修复(含日志、堆栈、相关代码) | 30-80K | 中等偏上 |
| 一次长文档生成(30K 字 + 引用资料) | 80-200K | 极易触顶 |
也就是说,即便你有 200K 的窗口,做一个像样的多步骤任务,也常常逼近上限。一旦逼近上限,会发生什么?
- 自动压缩(auto-compact)触发:早期的对话被总结成几句话,细节丢失
- 注意力衰减:即便信息还在窗口里,模型对靠前位置的细节注意力下降("lost in the middle"现象)
- 指令遵循降级:当上下文里塞满参考资料,模型对原始指令的遵循度下降
- 幻觉概率上升:找不到的信息,模型可能"脑补"补齐
Sub-Agent 的价值,就在于把一个 200K 都装不下的任务,切成 5 个 40K 能装下的子任务。每个 Sub-Agent 在自己的窗口里干净利落地完成本职工作,主 Agent 只需要接收"结果摘要"而非"原始资料"。
金句:上下文窗口是"房间大小",Sub-Agent 是"分房间办公"。与其让一个人挤在一间屋子里处理所有资料,不如分给五个人各占一间,每间屋子里只放该做的事。
11.1.3 专业分工的工程必然
工程世界里,分工从来不是奢侈品,是必需品。看看软件工程的组织方式:
| 时代 | 组织方式 | 分工粒度 |
|---|---|---|
| 1950s | 一个程序员包打天下 | 无分工 |
| 1970s | 系统分析师 + 程序员 | 2 个角色 |
| 1990s | PM + 架构师 + 开发 + 测试 + 运维 | 5 个角色 |
| 2010s | 前端 + 后端 + DBA + SRE + 安全 + 数据 | 6+ 个角色 |
| 2020s | 全栈 + DevOps + SRE + 安全 + ML + 平台 | 更细 |
为什么分工越来越细?不是因为人越来越懒,而是因为系统复杂度上升,单一角色的认知带宽撑不住。一个"全栈工程师"在 2010 年还能 cover 一个小项目的前后端,到 2024 年的微服务 + K8s + 前端框架升级 + 安全合规 + 数据中台,全栈已经是不可能完成的任务。
Agent 系统正在重走这条路。早期的 Agent 是"一个 Agent 包打天下"——一个 Claude/GPT 加上几个工具,就能处理大部分任务。但随着任务复杂度上升:
- 需要搜索?加 web 工具
- 需要执行代码?加 Python runtime
- 需要改文件?加 fs 工具
- 需要看图?加 vision
- 需要长记忆?加 retrieval
- 需要多步推理?加 chain-of-thought
工具越加越多,问题随之而来:
- 工具描述本身就吃掉大量上下文(每个工具 schema 200-500 token,30 个工具就是 6-15K)
- 模型在工具选择上出错(30 个工具里选 1 个比 5 个工具里选 1 个难得多)
- "工具膨胀"导致决策质量下降(心理学上的"选择悖论"在 LLM 上同样存在)
Sub-Agent 是分工的工程答案:与其让一个 Agent 拿着 30 个工具样样都做,不如让 5 个 Sub-Agent 各拿 6 个工具各做一样。这就是"专业分工的工程必然"在 Agent 世界的投射。
金句:工具数量和上下文消耗是一对矛盾。Sub-Agent 不是把工具变多,是把工具分门别类地装进不同的脑袋。
11.1.4 “一个人写不完一本书”——多 Agent 并行分工
回到开头的"写书"例子。这件事特别能体现 Sub-Agent 的两大价值:
价值一:并行。一本书 15 章,如果章与章之间弱耦合,理论上可以 15 个 Sub-Agent 同时开写。即使每个 Sub-Agent 写一章需要 1 小时,15 章顺序写要 15 小时,并行写只要 1 小时多。并行带来的不是边际加速,是数量级加速。
价值二:隔离。第 3 章的 Sub-Agent 不需要知道第 11 章在写什么,它的上下文里只有"第 3 章的提纲 + 第 3 章的参考资料 + 第 3 章的写作要求"。这种隔离让每个 Sub-Agent 都能在自己的窗口里充分展开,不会因为"全书上下文"而被压缩。
但并行和隔离都是有代价的:
- 并行需要结果合并策略(15 份初稿怎么拼成一本连贯的书?)
- 隔离需要接口规范(每章的 Sub-Agent 必须遵守统一的术语、风格、引文格式)
- 失败需要统一处理(第 7 章 Sub-Agent 写崩了怎么办?整本书卡住还是跳过?)
这些代价,正是"Sub-Agent 协作与编排"要解决的核心问题。本章后半部分会逐一展开。
11.2 Sub-Agent 的设计哲学
哲学不是空话。Sub-Agent 的设计哲学决定了你写出来的代码长什么样、能扛多大任务、出问题时怎么排错。这一节是全章的"道",后面的"术"都从这里推导。
11.2.1 单一职责原则
Single Responsibility Principle, SRP——这个概念来自软件工程的 SOLID 原则,原意是"一个类应该只有一个引起它变化的原因"。把它迁移到 Sub-Agent 上:
一个 Sub-Agent 应该只承担一类职责,只对一类任务负责。
"一类职责"是什么粒度?看下表:
| 粒度 | 例子 | 评价 |
|---|---|---|
| 过粗 | “代码 Sub-Agent” | 一个 Agent 既写代码、又审代码、又部署,等于没分 |
| 适中 | “code-reviewer Sub-Agent” | 专门做代码审查,输出审查意见 |
| 适中 | “web-researcher Sub-Agent” | 专门做 web 调研,输出结构化调研报告 |
| 过细 | “Python-函数-命名-Sub-Agent” | 只负责给 Python 函数起名,过度细化 |
判断粒度是否合适的经验法则:
- 能否一句话描述这个 Sub-Agent 的职责? 不能 → 过粗
- 这个 Sub-Agent 的输出是否能被主 Agent 直接使用? 不能 → 过细
- 它是否需要多个工具协同? 不需要 → 可能不需要 Sub-Agent
- 它是否拥有独立的"专业知识"(系统提示)? 没有 → 可能不需要 Sub-Agent
金句:单一职责不是"只做一件事",是"只对一类目标负责"。code-reviewer 可能做很多事(读代码、跑 lint、查规范),但它的目标只有一个——给出审查意见。
11.2.2 松耦合通信
Sub-Agent 之间不应该"互相窥探对方的脑子"。松耦合意味着:
- 主 Agent 与 Sub-Agent 之间通过明确的消息通信,而非共享变量
- Sub-Agent 之间默认不直接通信,需要时通过主 Agent 中转或共享黑板
- Sub-Agent 的内部状态不暴露给外部,只暴露输入/输出契约
看一个对比:
紧耦合(反模式):
主 Agent 调用 coder Sub-Agent
→ coder 直接读取 reviewer 的内部 reasoning
→ reviewer 直接修改 coder 的代码文件
→ 两个 Sub-Agent 共享同一份工作内存
松耦合(正模式):
主 Agent 调用 coder Sub-Agent
→ coder 返回代码 diff
主 Agent 调用 reviewer Sub-Agent(输入:coder 的 diff)
→ reviewer 返回审查意见
主 Agent 调用 coder Sub-Agent(输入:审查意见 + 原 diff)
→ coder 返回修改后的 diff
松耦合的代价是消息往返开销,但收益是可推理、可重放、可独立测试。当一个 Sub-Agent 出问题,你不需要看其他 Sub-Agent 的状态,只需要看输入和输出。
11.2.3 独立上下文
每个 Sub-Agent 应该有:
- 独立的 session id:不复用主 Agent 的对话历史
- 独立的系统提示:根据职责定制
- 独立的工具集:只装它需要的工具
- 独立的工作目录(如果涉及文件):避免互相覆盖
- 独立的 token 配额:避免一个 Sub-Agent 把预算吃光
独立上下文最深刻的价值,是"心态隔离"。一个 Agent 在做"创意发散"时,它的系统提示、温度参数、上下文都倾向于"打开思路";而做"严格审查"时,又倾向于"挑刺"。如果把两个角色塞进同一个 Agent,模型会在两种心态之间来回切换,结果是既发散得不彻底,也审查得不到位。
金句:Agent 也有"心态"。把发散者和收敛者放进同一个脑子,等于让一个人同时扮演天使和魔鬼——结果必定是平庸的折中。
11.2.4 可独立验证
一个设计良好的 Sub-Agent,应该能够被单独调用、单独测试、单独评估。这意味着:
- 它的输入是结构化的(JSON schema 或明确的文本契约)
- 它的输出是结构化的(可被程序解析或下一个 Agent 直接使用)
- 它有独立的测试用例(golden case + edge case)
- 它有独立的可观测性(日志、metrics、trace)
如果某个 Sub-Agent 必须依赖主 Agent 的"前置思考"才能工作,那它不是一个好的 Sub-Agent,应该重新设计接口。
┌──────────────────────────────────────────────────────────┐
│ Sub-Agent 设计四原则的依赖关系 │
│ │
│ 单一职责 ──┐ │
│ ├──> 独立上下文 ──> 可独立验证 │
│ 松耦合 ────┘ │
│ │
│ 单一职责是前提;松耦合是手段; │
│ 独立上下文是结构保证;可独立验证是工程落地。 │
└──────────────────────────────────────────────────────────┘
11.3 Sub-Agent 的角色分类
Sub-Agent 不是"随便切几刀"。根据职责性质,可以归为四大类。不同类别的 Sub-Agent,设计要点完全不同。
11.3.1 执行型 Sub-Agent
特征:负责"把事情做出来",输出是产物(代码、文档、数据)。
| 代表角色 | 输入 | 输出 | 典型工具 |
|---|---|---|---|
| coder | 需求描述 + 文件路径 | 代码 diff / PR | fs, bash, git |
| researcher | 调研问题 | 调研报告 | web_search, fetch |
| tester | 代码 + 测试要求 | 测试用例 + 执行结果 | bash, pytest |
| doc-writer | 主题 + 大纲 | 文档 | fs, web_search |
| data-analyst | 数据集 + 分析目标 | 分析报告 + 图表 | python, pandas |
执行型 Sub-Agent 的设计要点:
- 工具集要"够用且只够用":coder 不需要 web_search(除非要查 API 文档),researcher 不需要 fs 写权限
- 输出契约要明确:coder 输出 diff 还是完整文件?researcher 输出 markdown 还是 JSON?提前定死
- 失败要可识别:执行型 Sub-Agent 失败是常态(代码跑不通、搜索没结果),必须有明确的失败信号
11.3.2 验证型 Sub-Agent
特征:负责"检查别人做的事对不对",输出是判断 + 理由。
| 代表角色 | 输入 | 输出 | 设计要点 |
|---|---|---|---|
| code-reviewer | 代码 diff | 审查意见 + approve/request_changes | 不能修改代码,只能给意见 |
| critic | 论证或方案 | 批评意见 + 改进建议 | 系统提示偏"挑刺",温度低 |
| judge | 多个候选方案 | 排序 + 选择理由 | 需要明确评分标准 |
| fact-checker | 声明 + 来源 | 真伪判定 + 证据 | 必须给可验证的证据 |
| security-auditor | 代码 / 配置 | 漏洞列表 + 修复建议 | 专注于安全维度 |
验证型 Sub-Agent 的设计要点:
- 只读权限:验证型 Sub-Agent 默认不应有写权限,否则它会"自己改自己批"
- 独立的系统提示:偏严格、偏挑刺、低温(0-0.3)
- 必须给理由:不能只输出"通过/不通过",必须给可追溯的依据
- 可对抗:让验证型 Sub-Agent 和执行型 Sub-Agent 形成对抗,避免合谋
金句:验证型 Sub-Agent 的核心价值,是给系统装上"怀疑的镜子"。它不是来夸你的,是来照出你看不到的瑕疵的。
11.3.3 协调型 Sub-Agent
特征:负责"调度其他 Agent",输出是任务分派 + 结果整合。
| 代表角色 | 输入 | 输出 | 设计要点 |
|---|---|---|---|
| orchestrator | 总任务 | 子任务列表 + 分派计划 | 需要规划能力 |
| planner | 模糊目标 | 可执行的步骤树 | 需要拆解能力 |
| router | 用户请求 | 路由到哪个 Agent | 需要分类能力 |
| summarizer | 多份结果 | 整合后的最终输出 | 需要归纳能力 |
协调型 Sub-Agent 的设计要点:
- 不做具体活:协调型 Agent 不应该自己写代码、自己搜索,它只调度
- 拥有全局视图:它需要看到所有 Sub-Agent 的状态和结果摘要
- 决策可解释:分派决策要可追溯(“为什么把这个子任务给 coder 而不是 researcher”)
协调型 Sub-Agent 是最玄学的一类。协调得好,整个系统丝滑顺畅;协调得差,整个系统陷入"Agent 互相对话死循环"。AutoGen 早期的多 Agent 对话模式,就常常出现两个 Agent 互相客套十几个回合还没干正事的现象。
11.3.4 专项型 Sub-Agent
特征:针对特定领域或特定工具进行深度定制,输出是该领域的专业产出。
| 代表角色 | 专项领域 | 为什么独立 |
|---|---|---|
| web-researcher | 网页搜索 + 内容抽取 | 搜索结果原文巨大,必须独立窗口处理 |
| browser-agent | 浏览器自动化 | 需要状态机式的页面操作 |
| vision-agent | 图像理解 | 需要多模态能力 |
| sql-agent | 数据库查询 | 需要 schema 感知 + SQL 生成专精 |
| devops-agent | 部署运维 | 需要 K8s/Docker 专业知识 |
| legal-agent | 法律文本 | 需要法律领域知识库 |
专项型 Sub-Agent 的设计要点:
- 领域知识注入:系统提示里要塞领域知识(“你是一个资深 SRE,熟悉 K8s…”)
- 领域工具配套:sql-agent 配 SQL 执行器,devops-agent 配 kubectl
- 领域边界明确:不要让 sql-agent 去写代码,也不要让 devops-agent 去查数据库
11.3.5 四类角色的对比
| 维度 | 执行型 | 验证型 | 协调型 | 专项型 |
|---|---|---|---|---|
| 主要产出 | 产物 | 判断 | 调度 | 专业产出 |
| 工具数量 | 中 | 少(只读) | 少(无业务工具) | 多(领域工具) |
| 系统提示风格 | 务实 | 严格 | 全局 | 专业 |
| 温度参数 | 中(0.3-0.7) | 低(0-0.3) | 中低(0.2-0.5) | 领域相关 |
| 失败概率 | 高 | 中 | 低 | 中 |
| 是否可并行 | 是 | 是 | 否 | 是 |
| 典型数量 | 多 | 少(1-2) | 1 | 视任务 |
金句:四类角色不是"四种 Agent",是"四种职责"。一个真实的 Sub-Agent 可能同时具备多个职责(如 coder 兼具执行 + 自验证),但主职责必须只有一个。
11.4 编排模式谱系
有了 Sub-Agent,还要决定怎么把它们组织起来。这就是"编排模式"。编排模式决定了系统的复杂度、可靠性、延迟、成本——它是 Sub-Agent 系统的"骨架"。
11.4.1 串行编排(Pipeline)
形态:Sub-Agent 顺序执行,前一个的输出是后一个的输入。
[主 Agent]
│
▼
[coder] ──diff──> [reviewer] ──review──> [fixer] ──final──> [主 Agent]
适用场景:
- 任务有天然的阶段顺序(写→审→改)
- 每阶段的输出是下阶段的明确输入
- 不需要并行加速
优点:
- 简单,最容易实现
- 每阶段可独立调试
- 失败定位容易(卡在哪一阶段一目了然)
缺点:
- 总延迟 = 各阶段延迟之和
- 没有并行加速
- 任意阶段失败会阻塞整条流水线
典型例子:
- 写代码 → 代码审查 → 修复 → 再次审查
- 调研 → 写稿 → 润色 → 校对
- 数据采集 → 清洗 → 分析 → 报告
11.4.2 并行编排(Fan-out / Fan-in)
形态:主 Agent 把任务拆成多个独立子任务,分派给多个 Sub-Agent 并行执行,最后汇总结果。
┌── [researcher-A] ──┐
│ │
[主 Agent] ────┼── [researcher-B] ──┼──> [summarizer] ──> [主 Agent]
│ │
└── [researcher-C] ──┘
适用场景:
- 子任务之间相互独立(不强依赖)
- 子任务粒度相似(避免长尾拖累整体)
- 需要并行加速
优点:
- 总延迟 ≈ 最慢子任务的延迟(而非总和)
- 吞吐量高
- 容错性好(一个 Sub-Agent 挂了不影响其他)
缺点:
- 结果合并复杂(5 份调研怎么去重、消歧、整合?)
- 主 Agent 的整合负担重
- 子任务粒度不均时容易"短板效应"
典型例子:
- 多源调研(5 个框架各派一个 researcher)
- 多文件并行修改(10 个文件分给 10 个 coder)
- 多语言翻译(一份文档分给多种语言的 translator)
11.4.3 层级编排(Hierarchical)
形态:Sub-Agent 嵌套,主 Agent 调用中层 Agent,中层 Agent 再调用底层 Agent,形成树状结构。
[主 Agent / orchestrator]
/ \
[planner-A] [planner-B]
/ \ / \
[coder] [tester] [researcher] [doc-writer]
适用场景:
- 任务复杂度极高,单层编排装不下
- 存在天然的层级结构(“项目 → 模块 → 任务”)
- 不同层级需要不同的协调粒度
优点:
- 可扩展性强(可以无限嵌套)
- 局部失败局部处理,不污染全局
- 每层只关心自己这层的事,认知负担小
缺点:
- 实现复杂度激增
- 调用链长,端到端可观测性差
- 容易过度设计(“为了编排而编排”)
- token 消耗大(每层协调都要消耗)
典型例子:
- 大型软件项目的"总指挥 → 模块负责人 → 工程师"结构
- 多 Agent 写书:“主编 → 章节编辑 → 段落作者”
- 复杂科研:“总研究方向 → 子课题 → 具体实验”
11.4.4 对抗编排(Maker-Checker)
形态:两个角色对立的 Sub-Agent 互相博弈,一个生成、一个挑战,多轮迭代直到收敛。
┌───────> [maker 生成] ───────┐
│ │
│ ▼
[主 Agent] [checker 挑战]
▲ │
│ │
└────── [修改并迭代] <─────────┘
适用场景:
- 任务质量要求高,单次生成不可靠
- 存在明确的"好坏标准"可被 checker 验证
- 愿意为质量付出多轮迭代成本
优点:
- 输出质量高(多轮打磨)
- 自动收敛到质量标准
- 自带质量保证(checker 就是质量门禁)
缺点:
- 成本高(多轮调用)
- 可能不收敛(maker 一直改不好,checker 一直不满意)
- 需要明确的收敛条件(否则死循环)
典型例子:
- 代码生成 + 安全审计的对抗
- 论文写作 + 同行评审的对抗
- 翻译 + 母语审校的对抗
11.4.5 黑板模式(Blackboard)
形态:所有 Sub-Agent 共享一个"黑板"(共享内存 / 共享文件 / 共享消息队列),每个 Agent 根据黑板上的当前状态决定是否行动,结果写回黑板。
┌─────────────────────────┐
│ 共享黑板(黑板) │
│ ┌───────────────────┐ │
│ │ fact-1: ... │ │
│ │ fact-2: ... │ │
│ │ hypothesis-1: ... │ │
│ │ open-questions: . │ │
│ └───────────────────┘ │
└─┬──────┬──────┬──────┬──┘
│ │ │ │
▼ ▼ ▼ ▼
[A-1] [A-2] [A-3] [A-4]
(各自订阅黑板变化,按需行动)
适用场景:
- 任务没有固定的执行顺序
- 多个 Agent 需要异步协作
- 信息是逐步积累的(不是一次性输入)
优点:
- 极度灵活(Agent 可以随时加入、退出)
- 异步协作,不阻塞
- 适合"探索性"任务
缺点:
- 收敛不可控(可能永远不结束)
- 黑板状态管理复杂(并发写、冲突解决)
- 调试困难(谁在什么时候改了什么)
典型例子:
- 复杂故障诊断(多个 Agent 各贡献一条线索)
- 多源情报融合(每个 Agent 提供一种情报)
- 创意头脑风暴(多个 Agent 提想法、互评、迭代)
11.4.6 编排模式对比表
| 维度 | 串行 | 并行 | 层级 | 对抗 | 黑板 |
|---|---|---|---|---|---|
| 复杂度 | 低 | 中 | 高 | 中 | 高 |
| 延迟 | 高(求和) | 低(取最大) | 中 | 高(多轮) | 不可控 |
| 吞吐量 | 低 | 高 | 中 | 低 | 中 |
| 容错性 | 低 | 高 | 中 | 中 | 高 |
| 实现难度 | 简单 | 中 | 复杂 | 中 | 复杂 |
| 适用规模 | 2-5 Agent | 3-10 Agent | 10+ Agent | 2 Agent | N Agent |
| 收敛性 | 必收敛 | 必收敛 | 必收敛 | 需条件 | 不保证 |
| 典型场景 | 流水线 | 多源调研 | 大项目 | 高质量 | 探索性 |
| 调试难度 | 易 | 中 | 难 | 中 | 极难 |
11.4.7 编排模式谱系图
┌────────────────────────────────────────────────────────────────────────┐
│ Sub-Agent 编排模式谱系 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 控制力强 控制力弱 │
│ ←──────────────────────────────────────────────────────────→ │
│ │
│ [串行] ──> [并行] ──> [层级] ──> [对抗] ──> [黑板] │
│ Pipeline Fan-out Tree Maker- Black- │
│ /Fan-in Checker board │
│ │
│ ───────── ───────── ───────── ───────── ───────── │
│ 阶段顺序 任务独立 层级嵌套 角色对立 异步协作 │
│ 失败阻塞 短板效应 过度设计 死循环 收敛难 │
│ 易调试 中等 难调试 中等 极难 │
│ │
│ 现实系统通常是多种模式的混合: │
│ - 顶层用层级,中层用并行,底层用串行 │
│ - 关键质量环节嵌入对抗 │
│ - 探索性环节用黑板 │
└────────────────────────────────────────────────────────────────────────┘
金句:编排模式不是"选一种",是"组合用"。真实的复杂系统,是层级嵌套着并行,并行里串着对抗,对抗中挂着黑板——就像人类组织既有部门树、又有项目组、又有评审委员会、又有意见箱。
11.5 通信机制
编排模式决定了"谁和谁说话",通信机制决定了"怎么说话"。Sub-Agent 系统的通信设计,本质上是分布式系统的通信设计——只不过节点不是进程,是 LLM 实例。
11.5.1 主 Agent → Sub-Agent:任务委派
主 Agent 向 Sub-Agent 发起的通信,核心是任务委派。一次完整的委派应包含:
| 字段 | 含义 | 示例 |
|---|---|---|
task_id |
任务唯一标识 | task-007 |
subagent_id |
目标 Sub-Agent | code-reviewer |
input |
任务输入(结构化) | { diff: "...", context: "..." } |
expected_output |
期望输出契约 | { verdict: "approve|reject", comments: [...] } |
deadline |
超时(毫秒) | 30000 |
priority |
优先级 | high |
context_ref |
共享上下文引用 | shared://task-007/context.md |
实际工程中,多数框架并没有把所有字段都显式化。但显式化是工程成熟度的标志——隐式的契约在 dev 时能跑,到了 prod 一定会爆。
委派的两种语义:
- 同步委派(blocking call):主 Agent 阻塞等待 Sub-Agent 返回。简单但失去并行机会。
- 异步委派(fire-and-track):主 Agent 发出后继续干别的活,Sub-Agent 完成后通过回调或黑板通知。复杂但能并行。
HappyClaw 的 Sub-Agent 走的是同步委派——通过 SDK 的 agents 选项注册,主 Agent query() 时由 SDK 内部决定何时调用 Sub-Agent。这种实现的优点是简单、可靠;缺点是并行度受限。
11.5.2 Sub-Agent → 主 Agent:结果返回
Sub-Agent 完成任务后,要把结果返回给主 Agent。返回的结果应该满足:
- 结构化:JSON 或明确的文本格式,主 Agent 可直接解析
- 可判定:明确包含"成功/失败"信号
- 可追溯:包含 Sub-Agent 的执行元信息(耗时、token 消耗、调用的工具)
一个理想的返回结构:
{
"task_id": "task-007",
"subagent_id": "code-reviewer",
"status": "completed",
"result": {
"verdict": "request_changes",
"comments": [
{"file": "src/auth.ts", "line": 42, "issue": "未处理 null 分支"},
{"file": "src/auth.ts", "line": 87, "issue": "SQL 注入风险"}
]
},
"metadata": {
"duration_ms": 12450,
"tokens_in": 3200,
"tokens_out": 850,
"tools_called": ["read_file", "grep"]
}
}
现实中,多数 LLM 框架的 Sub-Agent 返回是纯文本——这给主 Agent 的解析带来负担。改进方法:
- 在 Sub-Agent 系统提示里强制要求"以 JSON 输出"
- 主 Agent 拿到返回后做一次解析,失败则降级为纯文本处理
- 用 structured output / tool use 来强制结构化
11.5.3 Sub-Agent ↔ Sub-Agent:直接通信
默认禁止。原因:
- 直接通信导致拓扑复杂化(N 个 Agent 之间有 N² 条边)
- 责任分散(A 给 B 发了错误指令,谁负责?)
- 死锁风险(A 等 B,B 等 A)
- 可观测性差(侧信道通信不在主链路上)
但有些场景必须直接通信:
- 流式协作:coder 实时把代码流给 reviewer,reviewer 实时反馈
- 协商:两个 Agent 需要就某个共享资源达成共识
- 路由:一个 Agent 把任务转给另一个更合适的 Agent
允许直接通信时,要遵守:
- 通过显式的 message-passing 接口,不要共享内存
- 通信内容写入 trace,便于事后追溯
- 设置通信预算(如每个 Agent 最多发 5 条消息),防止无限对话
11.5.4 共享黑板:异步通信
黑板模式下的通信是异步的。Agent A 把信息写到黑板,Agent B 不知道什么时候会读,也不关心。这种解耦带来了灵活性,也带来了不确定性。
黑板的实现形式:
| 形式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 共享文件 | 简单、持久、可审计 | 并发写有冲突 | 跨进程 Agent |
| 共享内存 | 快 | 进程内才行 | 单进程多 Agent |
| 消息队列 | 解耦、可扩展 | 引入中间件 | 分布式 Agent |
| 数据库 | 强一致、可查询 | 重 | 需要查询的场景 |
| Vector Store | 支持语义检索 | 最终一致 | 知识积累型黑板 |
HappyClaw 的"记忆"机制(memory/CLAUDE.md + data/groups/.../CLAUDE.md)本质上就是一种持久化的黑板——主 Agent 和 Sub-Agent 都能读写,通过文件系统异步通信。
11.5.5 Sub-Agent 通信时序图
下面用一个典型场景展示通信时序:主 Agent 委派 code-reviewer 审查一段代码,reviewer 给出意见,主 Agent 再让 coder 修复。
主 Agent code-reviewer coder
│ │ │
│ 1.委派审查 │ │
├─────────────────>│ │
│ │ │
│ │ 2.读代码、查规范 │
│ │ (调用工具) │
│ │ │
│ 3.返回审查意见 │ │
│<─────────────────│ │
│ │ │
│ 4.委派修复 │ │
│ (含审查意见) │ │
├──────────────────────────────────-->│
│ │
│ │ 5.读代码、改代码
│ │ (调用工具)
│ │
│ 6.返回修复结果 │
│<────────────────────────────────────│
│ │
│ 7.主 Agent 整合,输出最终结果 │
▼ ▼
注意几个关键点:
- 主 Agent 是唯一的协调者,reviewer 和 coder 不直接对话
- 每次委派都是同步阻塞(主 Agent 等待返回)
- 每次返回都是结构化的(审查意见 + 修复 diff)
- 主 Agent 在第 7 步做整合,不是简单拼接,是基于两份结果的综合判断
金句:通信设计的第一原则是"显式"。隐式契约是 bug 的温床——你以为 Sub-Agent 会返回 JSON,它偏偏返回了 markdown;你以为它会处理 null,它偏偏没处理。显式契约 + 强制校验 = 工程化。
11.6 Sub-Agent 的上下文隔离
通信解决了"怎么说话",隔离解决"各自在什么房间里说话"。上下文隔离是 Sub-Agent 工程的结构保证——没有隔离,Sub-Agent 就是个伪概念。
11.6.1 独立 session
每个 Sub-Agent 应该有独立的 session id,不复用主 Agent 的对话历史。为什么?
反例:主 Agent 的对话历史里有用户的各种问题、上下文、错误信息。如果 Sub-Agent 复用这段历史,相当于让一个新员工"看完公司所有的会议纪要再开始干活"——既有用不上的噪声,也有干扰判断的偏见。
正例:Sub-Agent 拿到的是一个全新的、干净的 session,只包含"本次任务的输入 + 系统提示"。它不知道主 Agent 跟用户聊过什么,也不需要知道——它只需要把眼前的事干好。
独立 session 的工程含义:
- session id 需要持久化映射:主 Agent 调用 Sub-Agent 时,要为 Sub-Agent 分配并记住一个 session id
- 同一 Sub-Agent 多次调用可复用 session:让 Sub-Agent 保持跨调用的记忆(比如同一个 coder 修同一个文件,可以记住上次改了什么)
- 不同 Sub-Agent 的 session 互不可见:coder 的 session 不能被 reviewer 看到,反之亦然
HappyClaw 在 sessions 表里以 (group_folder, agent_id) 为主键持久化 session 映射,每个 Sub-Agent 拥有独立的 session 文件,互不干扰。
11.6.2 独立工作目录
涉及文件操作的 Sub-Agent,应该有独立的工作目录或文件命名空间。否则:
- coder-A 和 coder-B 同时改
src/auth.ts,互相覆盖 - researcher 把下载的资料塞在工作目录根,污染其他 Agent 的视图
- Sub-Agent 的中间产物和主 Agent 的产物混淆
解决方案:
| 方案 | 适用 | 缺点 |
|---|---|---|
| 子目录隔离 | 同一项目内多个 Agent | 路径管理复杂 |
| Worktree 隔离 | 多个 Agent 改同一仓库 | Git 操作开销 |
| 完全独立工作目录 | 多个不相关任务 | 资源浪费 |
| 文件锁 | 共享文件场景 | 死锁风险 |
HappyClaw 的"会话工作目录"(data/groups/{folder}/)就是会话级隔离——每个会话有独立的工作目录,不同会话的 Sub-Agent 不互相干扰。
11.6.3 独立工具权限
最小权限原则在 Sub-Agent 系统里同样适用。一个 Sub-Agent 应该只拥有完成本职工作所必需的工具,不多不少。
| Sub-Agent | 应有工具 | 不应有 |
|---|---|---|
| code-reviewer | read_file, grep, lint | write_file, bash, web_search |
| coder | read_file, write_file, bash | web_search, send_message |
| web-researcher | web_search, fetch | write_file, bash |
| tester | bash, read_file | write_file |
| doc-writer | read_file, write_file | bash, web_search |
为什么不给所有 Sub-Agent 所有工具?因为:
- 降低误用概率:reviewer 不小心执行了 bash 命令可能破坏环境
- 降低 prompt 注入风险:攻击面减少
- 减少 token 消耗:每个工具的 schema 都占 token
- 强制单一职责:工具集本身就是职责的边界
11.6.4 防止"心态污染"
这是上下文隔离最微妙的一点。LLM 的"心态"(reasoning style、temperature、attention pattern)会被上下文塑造。一个 Agent 在做创意发散时,如果上下文里塞满了"严格审查"的指令,它的发散就会被压抑。
心态污染的典型场景:
- 主 Agent 跟用户聊了很多"严格遵循规范"的话题,然后委派 coder 写代码——coder 受上下文影响,写得过于保守
- Sub-Agent A 输出了"挑刺"风格的审查意见,主 Agent 把它原样转给 Sub-Agent B,B 进入防御模式
- 多个 Sub-Agent 的输出在主 Agent 上下文里混合,主 Agent 的判断风格被"平均化",失去锐度
对策:
- 每个 Sub-Agent 独立 session(前面已说)
- 主 Agent 转述时重写语气:把 reviewer 的"挑刺"语言,改写成中性的"任务"语言给 coder
- 不同角色的 Sub-Agent 用不同温度:发散型 0.7+,收敛型 0.2
- 系统提示强化角色:在 Sub-Agent 系统提示里明确"你是 X,只关心 Y,不被其他话题影响"
11.6.5 上下文隔离架构图
┌────────────────────────────────────────────────────────────────────────┐
│ Sub-Agent 上下文隔离架构 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ │
│ │ 主 Agent 上下文 │ ← 用户对话 + 任务规划 + Sub-Agent 结果汇总 │
│ │ session: main │ │
│ │ tools: 全部 │ │
│ │ workdir: /group │ │
│ └──────┬──────┬──────┬─┘ │
│ │ │ │ │
│ 委派│ 委派│ 委派│ (各自独立 session / 独立工作目录 / 独立工具) │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Agent-A │ │ Agent-B │ │ Agent-C │ │
│ │session:A│ │session:B│ │session:C│ │
│ │tools: t1│ │tools: t2│ │tools: t3│ │
│ │wd: /a │ │wd: /b │ │wd: /c │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 隔离边界: │
│ - session 互不可见(A 看不到 B 的对话历史) │
│ - 工作目录互不可写(A 不能改 /b 下的文件) │
│ - 工具集互不重叠(reviewer 没有 write_file) │
│ - 心态互不污染(A 的发散不影响 B 的收敛) │
│ │
│ 通信边界: │
│ - 只能通过主 Agent 中转 │
│ - 或通过显式的共享黑板 │
│ - 不能直接读对方的 session / 工作目录 │
└────────────────────────────────────────────────────────────────────────┘
金句:隔离不是"防着 Sub-Agent",是"保护 Sub-Agent"。一个干净的、不被打扰的 Sub-Agent,比一个被全局上下文污染的 Sub-Agent,输出质量高得多。
11.7 HappyClaw 的 Sub-Agent 实现
理论讲完,来看一个真实实现。HappyClaw 在 container/agent-runner/src/agent-definitions.ts 中定义了两个内置 Sub-Agent:code-reviewer 和 web-researcher。这一节深入源码,讲清楚实现细节。
11.7.1 整体架构
HappyClaw 的 Sub-Agent 通过 Claude Agent SDK 的 agents 选项注册到 query() 会话。整体架构:
┌──────────────────────────────────────────────────────────────────────┐
│ HappyClaw Sub-Agent 注册与调用流程 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 启动阶段(agent-runner 进程启动) │
│ ┌────────────────────────────┐ │
│ │ agent-definitions.ts │ │
│ │ - code-reviewer 定义 │ │
│ │ - web-researcher 定义 │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ▼ │
│ 2. query() 调用阶段(每轮对话) │
│ ┌────────────────────────────┐ │
│ │ index.ts query() │ │
│ │ agents: [codeReviewer, │ ← 注册到 SDK │
│ │ webResearcher] │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ▼ │
│ 3. SDK 内部决策(是否调用 Sub-Agent) │
│ ┌────────────────────────────┐ │
│ │ Claude Agent SDK │ │
│ │ - 主 Agent 推理 │ │
│ │ - 决定调用 Sub-Agent │ │
│ │ - 路由到对应 agent 定义 │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ▼ │
│ 4. Sub-Agent 执行(独立 session + 独立工具集) │
│ ┌────────────────────────────┐ │
│ │ code-reviewer / web-... │ │
│ │ - 独立 session id │ ← 从 sessions 表加载 │
│ │ - 独立 provider_id │ ← 避免 OAuth 签名失效 │
│ │ - 独立工具集 │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ▼ │
│ 5. 结果返回主 Agent,主 Agent 整合后输出 │
│ │
└──────────────────────────────────────────────────────────────────────┘
11.7.2 code-reviewer Sub-Agent 定义
code-reviewer 是 HappyClaw 内置的代码审查 Sub-Agent。它的职责是:对主 Agent 产出的代码进行独立审查,给出结构化的审查意见。
定义的核心要素:
| 要素 | 取值 | 设计理由 |
|---|---|---|
| 名称 | code-reviewer |
简洁明确,符合命名规范 |
| 描述 | “Code reviewer agent…” | SDK 根据描述决定何时调用 |
| 系统提示 | 严格、挑刺、引用规范 | 验证型角色心态 |
| 工具集 | 只读(read、grep、glob) | 最小权限 |
| 温度 | 低(默认 0.2) | 收敛型推理 |
| session | 独立 | 隔离主 Agent 上下文 |
| provider_id | 独立 sticky | 避免跨 OAuth 账号签名失效 |
设计要点解析:
1. 系统提示的角色注入。系统提示要明确告诉 Sub-Agent “你是谁、你做什么、你不做什么”。例如:
You are a senior code reviewer with 10 years of experience.
Your ONLY job is to review code and provide structured feedback.
You DO NOT:
- Modify code yourself
- Suggest vague improvements ("could be cleaner")
- Approve without giving specific reasons
You DO:
- Read the relevant code thoroughly
- Check against common pitfalls (null handling, error paths, security)
- Provide line-level comments with file path and line number
- Give a final verdict: approve / request_changes / reject
2. 工具集的"只读"约束。code-reviewer 拿到的工具是 read_file、grep、glob——没有 write_file、没有 bash。这是结构性的安全保证:即便 Sub-Agent 被恶意指令污染,它也改不了代码。
3. 输出契约的强制。系统提示里要求"final verdict: approve / request_changes / reject",这是强制结构化输出。主 Agent 拿到返回后,能直接解析 verdict 字段做后续决策。
11.7.3 web-researcher Sub-Agent 定义
web-researcher 是 HappyClaw 内置的网页调研 Sub-Agent。它的职责是:对给定的调研问题,进行多轮 web 搜索,输出结构化调研报告。
| 要素 | 取值 | 设计理由 |
|---|---|---|
| 名称 | web-researcher |
简洁明确 |
| 描述 | “Web researcher agent…” | SDK 路由依据 |
| 系统提示 | 务实、结构化、引用来源 | 执行型 + 专项型 |
| 工具集 | web_search、fetch、read_file | 调研专用 |
| 温度 | 中(0.4) | 调研需要一定发散 |
| session | 独立 | 隔离 |
| 输出契约 | markdown 报告 + 引用列表 | 主 Agent 可直接整合 |
为什么 web-researcher 必须独立 Sub-Agent?因为 web 搜索的结果原文极其庞大。一次 web_search 返回的 10 条结果,原文可能 20-50K token。如果主 Agent 自己做搜索,几次下来上下文就爆了。让 web-researcher 在自己的窗口里消化搜索结果,输出"摘要 + 引用",主 Agent 只需要看摘要——这就是隔离的价值。
11.7.4 通过 SDK agents 选项注册
HappyClaw 使用 Claude Agent SDK 的 agents 选项注册 Sub-Agent。注册的代码结构(伪代码):
import { query } from '@anthropic-ai/claude-agent-sdk';
import { codeReviewerAgent } from './agent-definitions';
import { webResearcherAgent } from './agent-definitions';
const result = query({
prompt: userInput,
options: {
agents: [codeReviewerAgent, webResearcherAgent],
// ...其他选项
}
});
SDK 内部的决策逻辑:
- 主 Agent 接收到 prompt
- 主 Agent 推理:这个任务需要 Sub-Agent 吗?
- 如果需要,主 Agent 选择合适的 Sub-Agent(基于 description)
- SDK 把任务委派给 Sub-Agent,等待返回
- Sub-Agent 在独立 session 中执行
- Sub-Agent 返回结果给主 Agent
- 主 Agent 整合后继续推理
关键点:SDK 提供的是"机制",不是"策略"。什么时候调用哪个 Sub-Agent,是主 Agent 自己推理决定的。这意味着 Sub-Agent 的 description 字段极其重要——它就是主 Agent 的"路由依据"。
11.7.5 独立会话 ID 映射
HappyClaw 在 sessions 表中以 (group_folder, agent_id) 为主键持久化每个 Sub-Agent 的 session id:
CREATE TABLE sessions (
group_folder TEXT NOT NULL,
agent_id TEXT NOT NULL,
session_id TEXT,
provider_id TEXT,
updated_at INTEGER,
PRIMARY KEY (group_folder, agent_id)
);
设计要点:
- 主键是
(group_folder, agent_id):同一会话的同一 Sub-Agent 复用 session;不同会话或不同 Sub-Agent 独立 session session_id持久化:Sub-Agent 的对话历史跨进程重启可恢复provider_id持久化:见下一节
主 Agent 的 agent_id 通常是 default 或主 Agent 的标识;Sub-Agent 的 agent_id 是 code-reviewer、web-researcher 等明确标识。
11.7.6 独立 provider_id:避免 OAuth 签名失效
这是一个深刻而微妙的工程细节。
背景:HappyClaw 支持多个 OAuth 账号(“provider pool”),主 Agent 和 Sub-Agent 都可能被路由到任意一个 OAuth 账号。OAuth 账号之间是隔离的——每个账号有自己的 thinking block 签名。
问题:如果 Sub-Agent 第一次调用用账号 A,第二次调用用账号 B,会出现什么?
- 账号 A 的 session 里可能有 thinking blocks(扩展思考过程),这些 blocks 用账号 A 的密钥签名
- 账号 B 拿到这个 session,无法验证账号 A 签的 thinking blocks
- SDK 报错"thinking block 签名失效",Sub-Agent 无法继续之前的对话
解决方案:Sub-Agent 的 provider_id 必须持久化,后续调用 sticky 到同一个 provider。
┌──────────────────────────────────────────────────────────────────┐
│ provider_id sticky 的必要性与实现 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ 场景:Sub-Agent 跨调用需保持 session 连续性 │
│ │
│ 第一次调用: │
│ Sub-Agent (session=S1) ──> Provider Pool ──> 账号 A │
│ (sticky 选 A) │
│ │
│ sessions 表记录: │
│ (group=main, agent=code-reviewer) -> session=S1, provider=A │
│ │
│ 第二次调用: │
│ Sub-Agent (session=S1) ──> Provider Pool │
│ │ │
│ │ 查 sessions 表:provider=A │
│ │ sticky 到 A │
│ └──> 账号 A(同一个) │
│ │
│ 这样 thinking block 签名一致,session 可连续。 │
│ │
│ 如果不 sticky: │
│ Sub-Agent ──> Provider Pool ──> 账号 B │
│ 账号 B 收到 S1(含账号 A 签名的 thinking block) │
│ → 签名验证失败 → 报错 → Sub-Agent 退化为新 session │
│ → 上下文丢失 → 多轮对话能力丧失 │
└──────────────────────────────────────────────────────────────────┘
这个细节是 HappyClaw 在生产环境踩坑后总结出来的。它体现了一个核心理念:Sub-Agent 的"独立"不是"每次都从零开始",是"有控制的连续性"——独立的边界要清晰,边界内的连续性要保证。
11.7.7 Sub-Agent 注册流程图
┌──────────────────────────────────────────────────────────────────────┐
│ HappyClaw Sub-Agent 注册流程 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ [启动] │
│ │ │
│ ▼ │
│ agent-runner 进程启动 │
│ │ │
│ ▼ │
│ import { codeReviewerAgent, webResearcherAgent } │
│ │ │
│ ▼ │
│ 收到 stdin 输入(ContainerInput) │
│ │ │
│ ▼ │
│ 从 sessions 表加载 │
│ (group_folder, agent_id=default) -> 主 Agent session │
│ (group_folder, agent_id=code-reviewer) -> reviewer session │
│ (group_folder, agent_id=web-researcher) -> researcher session │
│ │ │
│ ▼ │
│ query({ │
│ prompt, │
│ options: { │
│ agents: [codeReviewerAgent, webResearcherAgent], │
│ // SDK 自动处理: │
│ // - 何时调用 Sub-Agent(主 Agent 推理决定) │
│ // - Sub-Agent 用哪个 session(从 sessions 表取) │
│ // - Sub-Agent 用哪个 provider(sticky 到持久化的 provider_id) │
│ } │
│ }) │
│ │ │
│ ▼ │
│ 流式输出 → stdout → OUTPUT_MARKER → container-runner → WebSocket │
│ │ │
│ ▼ │
│ query() 返回 │
│ │ │
│ ▼ │
│ 更新 sessions 表: │
│ - 主 Agent new session_id │
│ - 各 Sub-Agent new session_id │
│ - 各 Sub-Agent provider_id(sticky) │
│ │ │
│ ▼ │
│ [结束] │
│ │
└──────────────────────────────────────────────────────────────────────┘
金句:HappyClaw 的 Sub-Agent 实现体现了一个工程信条——“机制在 SDK,策略在主 Agent,状态在数据库”。三者各司其职,系统才稳。
11.8 典型 Sub-Agent 工作流
理论、设计、实现都讲完了,这一节通过一个完整的端到端案例,把所有概念串起来。
11.8.1 场景:用户请求"重构 auth 模块并审查"
用户在 HappyClaw 的 Web 聊天里输入:
“请帮我重构 src/auth.ts,提取密码哈希逻辑到独立模块,并让 code-reviewer 审一下。”
这是一个复合任务,包含:
- 理解需求:提取密码哈希逻辑
- 代码修改:重构 src/auth.ts
- 代码审查:调用 code-reviewer
- 整合输出:把修改和审查意见综合呈现给用户
11.8.2 工作流时序
用户 主 Agent code-reviewer 工具
│ │ │ │
│ 1. 输入请求 │ │ │
├─────────────────>│ │ │
│ │ │ │
│ │ 2. 读 src/auth.ts │
│ ├──────────────────────────────────────> │
│ │ 3. 文件内容返回 │
│ │<────────────────────────────────────── │
│ │ │
│ │ 4. 规划重构方案 │
│ │ (内部推理) │
│ │ │
│ │ 5. 写新模块 src/password.ts │
│ ├──────────────────────────────────────> │
│ │ │
│ │ 6. 修改 src/auth.ts (调用旧逻辑) │
│ ├──────────────────────────────────────> │
│ │ │
│ │ 7. 决定调用 code-reviewer │
│ │ (SDK 路由) │
│ ├──┐ │
│ │ │ 委派:审 src/auth.ts 和 src/password.ts │
│ │ ▼ │
│ │ ┌─────────────┐ │
│ │ │ code-reviewer│ │
│ │ │ 独立 session │ │
│ │ │ 独立 provider│ │
│ │ │ 只读工具 │ │
│ │ └──────┬──────┘ │
│ │ │ │
│ │ │ 8. 读相关文件、查规范 │
│ │ ├────────────────────────────> │
│ │ │ 9. 返回审查意见 │
│ │ │ (verdict + 行级 comments) │
│ │<────────┘ │
│ │ │
│ │ 10. 整合:把审查意见转成用户友好的输出 │
│ │ (主 Agent 推理) │
│ │ │
│ 11. 最终回复 │ │
│<─────────────────│ │
│
11.8.3 关键节点解析
节点 2-3:主 Agent 读文件。主 Agent 自己用 read_file 工具读取 src/auth.ts,不委派。这是合理的——读文件是轻量操作,没必要 Sub-Agent。
节点 4:主 Agent 规划重构方案。这一步是主 Agent 的"独立思考",不调用任何 Sub-Agent。主 Agent 在自己的上下文里推理:哪些代码是密码哈希、要提取什么函数、新模块叫什么。
节点 5-6:主 Agent 写代码。主 Agent 用 write_file 创建新模块,用 edit_file 修改原文件。这一步也不委派——代码生成是主 Agent 的核心能力,委派给 coder 反而增加通信开销。
节点 7:主 Agent 决定调用 code-reviewer。这是关键路由决策。主 Agent 在系统提示里有 code-reviewer 的 description,知道"代码审查"是该 Sub-Agent 的职责。SDK 根据这一决策,把审查任务委派给 code-reviewer。
节点 8-9:code-reviewer 独立执行。code-reviewer 在自己的 session 里,用只读工具读相关文件,对照规范做审查,返回结构化意见。它的 session 隔离,不被主 Agent 的"重构上下文"污染——它就是一个独立的、严格挑刺的审查员。
节点 10:主 Agent 整合。主 Agent 拿到审查意见,不是简单转贴,而是做综合判断:
- 哪些意见必须修(严重 bug)
- 哪些意见可以忽略(风格偏好)
- 是否需要再委派 coder 修复
最终输出给用户的是"修改 + 审查 + 整合判断"的合集。
11.8.4 时序图体现的几个原则
回看时序图,能提炼几条原则:
- 不是所有事都要委派。读文件、写代码这类主 Agent 能轻松搞定的,不要委派。委派有通信开销,过度委派是反模式。
- 委派时机由主 Agent 推理决定。SDK 不强制委派,主 Agent 根据任务性质和 Sub-Agent description 自己判断。
- Sub-Agent 的输出必须回到主 Agent。code-reviewer 的意见不直接发给用户,必须经过主 Agent 整合——这是"单一协调者"原则。
- 整合不是拼接,是判断。主 Agent 要对 Sub-Agent 的输出做"二次推理",决定如何使用。
金句:Sub-Agent 工作流的精髓在"何时委派"和"如何整合"。前者考验路由能力,后者考验综合判断能力。这两者,才是主 Agent 真正的硬功夫。
11.9 并行 Sub-Agent 的设计
并行编排能带来数量级的加速,但也带来复杂的工程问题。这一节专门讲并行。
11.9.1 任务可分性判断
不是所有任务都能并行。判断一个任务能否并行,要看四个条件:
| 条件 | 说明 | 例子 |
|---|---|---|
| 输入独立 | 各子任务的输入互不依赖 | 5 个框架调研:每个的输入是独立的框架名 |
| 输出独立 | 各子任务的输出互不覆盖 | 5 份调研报告:每份独立 |
| 无共享状态 | 子任务不读写同一资源 | 各自搜索各自的,不共享工作目录 |
| 结果可合并 | 子任务输出有合并策略 | 5 份报告可以拼成一份综合报告 |
四个条件全满足 → 可并行;任一不满足 → 不可并行或需改造。
改造例子:把"修改一个文件里的 10 个函数"改造成并行任务?看起来输入输出都依赖同一文件,不可并行。但可以用 worktree 隔离:每个 Sub-Agent 在自己的 git worktree 里改自己的函数,最后由主 Agent 合并 commit。这就是把"不可并行"改造成"可并行"的工程手段。
11.9.2 结果合并策略
并行执行完,要合并结果。合并策略分几类:
| 策略 | 适用 | 实现难度 | 例子 |
|---|---|---|---|
| 拼接 | 输出互不重叠 | 低 | 5 章拼接成书 |
| 去重合并 | 输出有重叠 | 中 | 多源调研去重 |
| 优先级选择 | 输出有优劣 | 中 | 多模型回答选最好的 |
| 投票 | 输出是判断 | 中 | 多 reviewer 投票决定是否合并 |
| 综合 | 输出需要推理整合 | 高 | 多份方案综合成最终方案 |
| 矛盾标记 | 输出有冲突 | 高 | 多源数据冲突时标记给人工 |
合并的难度不在"拼",在"消歧"。5 份调研报告都说"AutoGen 是微软开源的多 Agent 框架",但其中一份说"由 Microsoft Research 发布",另一份说"由 Microsoft 发布"——这种细微差异要不要统一?怎么统一?这是合并的真正难点。
实践建议:
- 让 Sub-Agent 输出结构化:JSON 比 markdown 容易合并
- 主 Agent 做二次推理:不要简单拼接,让主 Agent 读所有结果后输出综合
- 保留溯源:合并后的每一项都标注来自哪个 Sub-Agent,便于事后核查
11.9.3 失败处理
并行执行时,部分 Sub-Agent 失败是常态。处理策略:
| 策略 | 适用场景 | 风险 |
|---|---|---|
| 全部回滚 | 强一致任务 | 一个失败全盘皆输 |
| 部分成功 | 容忍缺失的任务 | 用户看到不完整结果 |
| 重试失败 | 偶发失败 | 拖延总时长 |
| 降级 | 有 fallback 方案 | 质量下降 |
| 标记失败 | 用户可自行处理 | 体验差 |
默认推荐:部分成功 + 明确标记。理由:
- 全部回滚在长程任务里代价过大(10 个并行任务里 1 个失败,重跑全部 10 个?)
- 部分成功让用户看到"已完成的 9 个 + 失败的 1 个",可以决定是否重试
- 明确标记让用户知道哪里缺失,不会误以为全部成功
11.9.4 部分成功 vs 全部回滚:决策表
| 维度 | 部分成功 | 全部回滚 |
|---|---|---|
| 任务性质 | 弱一致 | 强一致 |
| 用户期望 | 看到部分结果 | 要么全有要么全无 |
| 重试成本 | 低 | 高 |
| 典型场景 | 多源调研 | 数据库事务 |
| 实现复杂度 | 中 | 高(需要补偿) |
| 失败传播 | 局部 | 全局 |
11.9.5 并行 Sub-Agent 工作流图
┌──────────────────────────────────────────────────────────────────────┐
│ 并行 Sub-Agent 工作流(Fan-out/Fan-in) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ T0: 主 Agent 拆解任务 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ "调研 5 个 AI 框架" -> │ │
│ │ 子任务 1: 调研 AutoGen │ │
│ │ 子任务 2: 调研 LangGraph │ │
│ │ 子任务 3: 调研 CrewAI │ │
│ │ 子任务 4: 调研 Swarm │ │
│ │ 子任务 5: 调研 HappyClaw │ │
│ └─────────────────┬───────────────────────────────┘ │
│ │ │
│ T1: Fan-out(同时分派) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ ┌──[r-A]──┐ ┌──[r-B]──┐ ┌──[r-C]──┐ │ │
│ │ │ 调研 A │ │ 调研 B │ │ 调研 C │ (各自独立 │ │
│ │ │ session │ │ session │ │ session │ session)│ │
│ │ │ provider│ │ provider│ │ provider│ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ └────────┼───────────┼───────────┼────────────────┘ │
│ │ │ │ │
│ T2: 各自执行(搜索、读文档、整理) │
│ ... │
│ │ │ │ │
│ T3: Fan-in(结果汇总) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 主 Agent 收集 5 份调研报告 │ │
│ │ 做消歧、去重、综合 │ │
│ │ 输出最终综合报告 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 失败处理: │
│ - r-C 失败?标记缺失,综合时注明"框架 C 调研失败" │
│ - 重试 r-C 一次,仍失败则降级 │
│ - 不影响 r-A、r-B 的结果 │
│ │
└──────────────────────────────────────────────────────────────────────┘
金句:并行的真正难点不是"同时跑",是"跑完之后怎么合"。前者是机制,后者是智慧。
11.10 多 Agent 协作的反模式
讲完正例,必须讲反例。这一节列出多 Agent 系统常见的"工程坑",每一个都是真实踩出来的。
11.10.1 反模式 1:Agent 数量膨胀
症状:开发者一时兴起,给每个小职责都建一个 Sub-Agent。从"web 调研"到"web 调研-中文"到"web 调研-技术文档",Sub-Agent 数量从 3 个膨胀到 30 个。
危害:
- 系统提示维护成本爆炸:30 个 Sub-Agent 的系统提示都要调
- 路由决策变难:主 Agent 要在 30 个里选,选错率高
- 工具 schema 总量过大:每个 Sub-Agent 工具描述在 SDK 注册时都占 token
- 测试覆盖不了:30 个 Sub-Agent 的组合路径无法穷举
根因:把 Sub-Agent 当成"代码函数"来切,没意识到每个 Sub-Agent 都是一个完整的、有上下文成本的 Agent 实例。
对策:
- 一个新 Sub-Agent 上线前,问自己:“这个职责能不能让现有 Sub-Agent 兼任?”
- 如果不能兼任,再问:“这个职责出现频率高吗?值得维护一个独立 Agent 吗?”
- 两个问题都通过,才建新的
经验阈值:一个系统的 Sub-Agent 数量,3-7 个为佳,10 个为限。超过 10 个,就该考虑用 Sub-Agent 的 Sub-Agent(层级编排),而不是平铺。
11.10.2 反模式 2:通信开销 >> 计算开销
症状:主 Agent 把一个简单任务委派给 Sub-Agent,Sub-Agent 又委派给另一个 Sub-Agent,三层下来,每个 Sub-Agent 只干了 1 秒的活,但通信花了 10 秒。
危害:
- 延迟激增:用户等一个简单回答等了好几秒
- token 浪费:每次委派都要重新构造上下文
- 可靠性下降:每多一层委派,就多一个失败点
判断公式:
通信开销 = 委派次数 × (序列化成本 + 路由成本 + 等待成本)
计算开销 = Sub-Agent 实际推理时间
若 通信开销 >> 计算开销 → 反模式
对策:
- 能在主 Agent 一轮推理里做完的,绝不委派
- 委派的粒度要"够重"——至少让 Sub-Agent 干的活是通信开销的 5 倍以上
- 减少层级,能用并行就不用串行层级
11.10.3 反模式 3:责任分散
症状:多个 Sub-Agent 都"参与"了一个决策,但出问题时没人负责。
经典场景:
- coder 写了有 bug 的代码
- reviewer 没审出来
- tester 没测出来
- 上线后爆雷
每个 Sub-Agent 都说"我做了我该做的",但系统整体失败了。这就是社会心理学里的"旁观者效应"在 Agent 系统的重演。
对策:
- 每个决策有明确的责任 Agent:在系统提示里写明"你是 X 的最终责任人"
- 责任链可追溯:每次决策记录由哪个 Agent 做出、基于什么信息
- 责任倒查机制:出问题时能定位到具体 Agent 的具体决策
11.10.4 反模式 4:协调死锁
症状:Agent A 等 Agent B 的结果,Agent B 等 Agent C 的结果,Agent C 等 Agent A 的结果——三方互相等待,系统卡死。
典型触发条件:
- 黑板模式下,每个 Agent 都"等其他 Agent 先贡献"
- 对抗模式下,maker 和 checker 互相不接受对方的输出
- 层级模式下,子 Agent 等父 Agent 给输入,父 Agent 等子 Agent 给输出
对策:
- 设置超时:每个委派必须有 deadline,超时即降级
- 避免循环依赖:依赖图必须是 DAG(有向无环图)
- 默认行为:Agent 在等待时必须有默认 fallback(“如果 N 秒内没收到,就基于现有信息决策”)
11.10.5 反模式 5:过度编排
症状:开发者把"编排"当成炫技,简单的任务也搞个三层编排 + 黑板 + 对抗。代码量激增,可维护性暴跌。
危害:
- 实现复杂度 >> 任务复杂度
- 调试困难
- 后期维护成本高
对策:
- 编排复杂度应匹配任务复杂度,不超过 1.5 倍
- 简单任务用单 Agent + 工具调用就够了
- 编排层级 ≤ log2(子任务数) + 1
11.10.6 多 Agent 反模式树
┌────────────────────────────────────────────────────────────────────────┐
│ 多 Agent 协作反模式树 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 多 Agent 反模式 │
│ ├── 数量类 │
│ │ ├── Agent 数量膨胀(>10 个) │
│ │ └── 工具数量膨胀(单 Agent >30 工具) │
│ │ │
│ ├── 通信类 │
│ │ ├── 通信开销 >> 计算开销 │
│ │ ├── 侧信道通信(绕过主链路) │
│ │ └── 消息风暴(Agent 间高频对话) │
│ │ │
│ ├── 责任类 │
│ │ ├── 责任分散(多个 Agent 都参与,无人负责) │
│ │ ├── 责任倒置(Sub-Agent 凌驾主 Agent) │
│ │ └── 责任链断裂(出问题查不到谁) │
│ │ │
│ ├── 协调类 │
│ │ ├── 协调死锁(循环等待) │
│ │ ├── 协调活锁(一直退让不进展) │
│ │ └── 永不收敛(多轮对抗不收敛) │
│ │ │
│ ├── 隔离类 │
│ │ ├── 上下文污染(Sub-Agent 共用主上下文) │
│ │ ├── 工作目录冲突(多 Agent 改同一文件) │
│ │ └── 心态串扰(发散和收敛混杂) │
│ │ │
│ └── 架构类 │
│ ├── 过度编排(简单任务上重编排) │
│ ├── 编排不足(复杂任务用单 Agent) │
│ └── 模式错配(黑板场景用了串行) │
│ │
└────────────────────────────────────────────────────────────────────────┘
金句:反模式不是"做错了",是"做过头"。Sub-Agent 系统的失败,多数不是技术问题,是工程品味问题——知止,是一种美德。
11.11 Sub-Agent vs 单 Agent + 工具调用:决策树
并不是所有任务都需要 Sub-Agent。很多场景下,单 Agent + 工具调用就足够了。这一节给一个决策树,帮你判断"该不该拆"。
11.11.1 何时该拆(用 Sub-Agent)
满足以下任一条件,就该拆:
- 上下文消耗大:单次任务预计消耗 > 50% 上下文窗口
- 职责清晰可分:能明确画出"X 做 A、Y 做 B"的边界
- 并行机会:子任务之间无依赖,可并行
- 专业差异大:不同子任务需要截然不同的系统提示、工具、温度
- 质量需要对抗:需要 maker-checker 式的质量保证
- 复用价值:某个 Sub-Agent 能在多个任务里复用
11.11.2 何时不该拆(用单 Agent + 工具)
满足以下任一条件,就不该拆:
- 任务简单:单 Agent 一轮推理能搞定
- 职责边界模糊:拆出来的 Sub-Agent 不知道自己该干啥
- 强依赖:子任务之间必须顺序、紧密耦合
- 通信开销大:拆开后的通信成本超过节省的计算成本
- 频次低:任务很少出现,不值得维护 Sub-Agent
11.11.3 决策树图
┌─────────────────────┐
│ 任务复杂吗? │
│ (单 Agent 一轮能 │
│ 搞定吗?) │
└──────────┬──────────┘
│
┌────────────────┴────────────────┐
│ 否 │ 是
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ 任务有并行机会? │ │ 用单 Agent + 工具 │
│ 子任务独立? │ │ 调用即可 │
└────────┬────────┘ └─────────────────────┘
│
┌────────┴────────┐
│ 否 │ 是
▼ ▼
┌───────────┐ ┌─────────────────┐
│ 强依赖? │ │ 用并行编排 │
└─────┬─────┘ └─────────────────┘
│
┌────┴────┐
│ 是 │ 否
▼ ▼
┌────────┐ ┌─────────────┐
| 串行 │ │ 用层级编排 │
| 编排 │ └─────────────┘
└────────┘
更细的决策树:
┌───────────────────────┐
│ 1. 上下文消耗大吗? │
│ (>50% 窗口) │
└──────────┬────────────┘
│ 是
▼
┌───────────────────────┐
│ 2. 职责清晰可分吗? │
└──────────┬────────────┘
│ 是
▼
┌───────────────────────┐
│ 3. 子任务有专业差异? │
│ (不同 prompt/tool) │
└──────────┬────────────┘
│ 是
▼
┌───────────────────────┐
│ 4. 频次高吗? │
│ (值得维护 Sub-Agent) │
└──────────┬────────────┘
│ 是
▼
┌──────────────┐
│ 用 Sub-Agent │
└──────────────┘
11.11.4 决策对照表
| 维度 | 单 Agent + 工具 | Sub-Agent |
|---|---|---|
| 实现复杂度 | 低 | 中-高 |
| 上下文消耗 | 集中在主 Agent | 分散到各 Sub-Agent |
| 调试 | 简单 | 复杂 |
| 复用 | 工具级复用 | Agent 级复用 |
| 质量保证 | 主 Agent 自检 | 可引入对抗 |
| 并行 | 难 | 容易 |
| 适合任务 | 简单、单步骤 | 复杂、多步骤 |
金句:Sub-Agent 不是"高级",是"必要时的拆分"。能用单 Agent 解决的,就别上 Sub-Agent——简单性是工程美德,不是工程缺陷。
11.12 真实案例
理论讲完了,来看业界实践。这一节对比 5 个有代表性的多 Agent 系统,看它们各自的编排哲学。
11.12.1 Claude Code 的 Sub-Agent 系统
Claude Code(Anthropic 官方 CLI)内置了 Sub-Agent 机制,主要包含:
- code-reviewer:代码审查 Sub-Agent
- web-researcher:网页调研 Sub-Agent
- 自定义 Sub-Agent:用户可在
.claude/agents/定义自己的 Sub-Agent
设计哲学:主 Agent 主导,Sub-Agent 专精。主 Agent 推理决定何时调用 Sub-Agent,Sub-Agent 在独立 session 中执行专精任务。
技术细节:
- Sub-Agent 通过 SDK 的
agents选项注册 - 独立 session、独立工具集、独立系统提示
- 输出结构化返回给主 Agent
11.12.2 Cursor 的多 Agent 模式
Cursor(AI 编程 IDE)的多 Agent 模式体现在:
- Composer:主 Agent,负责代码生成
- Tab 补全:轻量 Sub-Agent,负责行内补全
- Cursor Chat:问答 Sub-Agent,负责侧栏对话
- Background Agents:后台 Sub-Agent,负责长任务
设计哲学:按场景拆分。不同交互场景对应不同 Sub-Agent,每个 Sub-Agent 有自己的 UI 入口和工具集。
11.12.3 AutoGen 的多 Agent 框架
AutoGen(微软开源)是早期的多 Agent 框架,特点是:
- 对话式编排:Agent 之间通过对话协调
- 角色可定制:用户定义每个 Agent 的角色
- 多种对话模式:sequential、group chat、nested
设计哲学:Agent 即角色。把人类组织里的角色抽象成 Agent,让它们对话解决任务。
典型反例(早期版本):两个 Agent 互相客套多轮不干活。后续版本引入了"终止条件"和"主持人 Agent"来收敛。
11.12.4 LangGraph 的图式编排
LangGraph(LangChain 出品)的核心抽象是有向图:
- 节点 = Agent / 工具
- 边 = 控制流
- 状态 = 图的共享内存
设计哲学:编排即图。把多 Agent 协作抽象成状态图,每条边都是显式的状态转移。
技术亮点:
- 显式的状态管理(vs AutoGen 的隐式对话)
- 可视化(图天然可画)
- 可分析(图论工具可分析死锁、活锁、可达性)
11.12.5 OpenAI Swarm
OpenAI Swarm(OpenAI 出品,2024)是轻量级多 Agent 框架,特点是:
- 极简抽象:Agent = (instructions, tools, handoff)
- handoff 机制:Agent A 可以把对话"交给"Agent B
- 无状态:框架本身不维护状态,状态在对话上下文里
设计哲学:轻量、显式、无状态。把多 Agent 协作简化为"Agent 之间互相 handoff",没有复杂的图、没有对话历史管理。
适用场景:原型、教学、轻量应用。不适合生产级长程任务。
11.12.6 五大框架对比表
| 维度 | Claude Code | Cursor | AutoGen | LangGraph | Swarm |
|---|---|---|---|---|---|
| 编排哲学 | 主+专 | 场景拆分 | 角色对话 | 状态图 | handoff |
| 抽象层级 | SDK agents | UI 入口 | Agent + 对话 | 图节点 | Agent + handoff |
| 状态管理 | 显式 session | 隐式 | 隐式 | 显式 | 无 |
| 并行支持 | 中 | 弱 | 中 | 强 | 弱 |
| 可观测性 | 中 | 中 | 中 | 强 | 弱 |
| 生产就绪 | 强 | 强 | 中 | 强 | 弱 |
| 学习曲线 | 中 | 低 | 中 | 高 | 极低 |
| 适合场景 | 编程 | 编程 IDE | 通用 | 复杂工作流 | 原型 |
金句:每个框架都在"抽象力"和"易用性"之间做了权衡。LangGraph 抽象力强但难学,Swarm 易用但弱。没有银弹,只有适合。
11.13 多 Agent 系统的可观测性
多 Agent 系统的调试比单 Agent 难一个数量级。单 Agent 出问题,看 trace 就行;多 Agent 出问题,要先把"谁在什么时候调用了谁、各自消耗了多少 token、谁失败了"梳理清楚。这一节讲可观测性的三大支柱。
11.13.1 调用链追踪
调用链(trace) 是多 Agent 系统的"案发现场重建"。一次完整的 trace 应包含:
| 字段 | 含义 |
|---|---|
trace_id |
整个用户请求的唯一 ID |
span_id |
每个 Agent 调用的 span ID |
parent_span_id |
父 span(主 Agent 是根) |
agent_id |
哪个 Agent |
input |
输入摘要 |
output |
输出摘要 |
start_time / end_time |
起止时间 |
status |
成功 / 失败 / 超时 |
tokens_in / tokens_out |
token 消耗 |
tools_called |
调用了哪些工具 |
一个典型 trace:
trace_id: abc-123
└─ span-1 [main Agent] (15.2s, 4500 in, 1200 out)
├─ span-2 [coder Sub-Agent] (8.1s, 2200 in, 600 out)
│ └─ tool: write_file (src/auth.ts)
├─ span-3 [code-reviewer Sub-Agent] (5.4s, 1800 in, 400 out)
│ ├─ tool: read_file (src/auth.ts)
│ └─ tool: read_file (src/password.ts)
└─ span-4 [main Agent 整合] (1.7s, 500 in, 200 out)
从 trace 能看出:
- 总耗时 15.2s,其中 coder 8.1s 占大头
- coder 和 reviewer 串行执行(reviewer 在 coder 之后开始)
- 各 Agent 的 token 消耗合理
- 没有失败
如果 reviewer 失败,trace 会变成:
└─ span-1 [main Agent]
├─ span-2 [coder] ✓
├─ span-3 [code-reviewer] ✗ (timeout 30s)
└─ span-4 [main Agent 整合,含失败处理]
trace 的可视化常用火焰图(flame graph),横向是时间,纵向是调用深度。
11.13.2 Token 用量归因
多 Agent 系统的成本控制,必须做到per-Agent 的 token 归因。否则你只知道"今天花了 100 万 token",但不知道哪个 Agent 是大头。
归因维度:
| 维度 | 例子 |
|---|---|
| 按 Agent | coder: 50万,reviewer: 20万,main: 30万 |
| 按任务类型 | 编程: 60万,调研: 30万,对话: 10万 |
| 按用户 | user-A: 70万,user-B: 30万 |
| 按模型 | GPT-4: 80万,GPT-3.5: 20万 |
| 按时间 | 早高峰: 40万,晚高峰: 50万 |
HappyClaw 在 usage_records 表里按 per-model per-Agent per-Message 拆行存储,可以做任意维度的归因聚合。
11.13.3 失败传播分析
多 Agent 系统的失败传播是级联的:一个 Sub-Agent 失败,会导致主 Agent 的整合失败,进而导致整个任务失败。
失败传播分析要回答:
- 哪个 Sub-Agent 是失败源头?(root cause)
- 失败传播到了哪些 Agent?(blast radius)
- 传播路径是什么?(impact chain)
- 如何阻断传播?(mitigation)
例子:
root cause: web-researcher 超时(30s 没返回)
↓ 主 Agent 收到 null 结果
↓ 主 Agent 试图基于 null 综合报告
↓ 主 Agent 输出"调研失败"
blast radius: 整个调研任务失败
mitigation: 给 web-researcher 设置更长超时 + 失败时降级为"基于已有知识回答"
11.13.4 火焰图示例
┌──────────────────────────────────────────────────────────────────────┐
│ 多 Agent 调用火焰图(横向=时间,纵向=深度) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 时间(s) 0 2 4 6 8 10 12 14 16 18 20 │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ 主Agt ████████████████████████████████████████████████████████ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ coder ─────█████████████████─────│ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ revw ──────────────────────────────████████████───│ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ resch ──────────────────────████████████████████████│ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ 整合 ───────────────────────────────────────────────██████ │
│ │
│ 解读: │
│ - 主 Agent 全程在线(顶层横条) │
│ - coder 在 2-8s 执行(5个 hash 块) │
│ - reviewer 在 8-14s 执行(在 coder 完成后开始,串行) │
│ - researcher 在 6-16s 执行(与 reviewer 部分重叠,并行) │
│ - 整合在 16-20s(所有 Sub-Agent 完成后) │
│ - 总耗时 20s,其中并行节省了约 6s │
│ │
└──────────────────────────────────────────────────────────────────────┘
金句:没有可观测性的多 Agent 系统,是黑盒里的黑盒。出问题时你只能"猜",而猜,是工程的大忌。
11.14 Agent 编排的未来
讲完当下,眺望未来。这一节是预测,不是断言——但趋势已经显现。
11.14.1 Agent 市场化
未来会出现Agent 市场:开发者把自己做的优质 Sub-Agent 上架,其他用户按需调用。
类比:
- App Store → iOS 应用市场
- Hugging Face → 模型市场
- Agent Store → Sub-Agent 市场(未来)
市场化的含义:
- 价值流转:优质 Sub-Agent 可获得收益
- 专业化分工:全职"Sub-Agent 工程师"出现
- 质量信号:评分、下载量、可靠性指标
- 组合创新:用户从多个作者那里组合 Sub-Agent
11.14.2 标准 protocol:MCP、ACP
标准化是市场化的前提。当前两个值得关注的 protocol:
MCP(Model Context Protocol):Anthropic 主推,专注"Agent 与工具/数据源"的标准化。已经广泛落地。
ACP(Agent Communication Protocol):聚焦"Agent 与 Agent"的通信标准化。还在早期。
未来预测:MCP + ACP 会成为多 Agent 系统的"TCP/IP"——底层通信标准。基于这个标准,会涌现大量跨厂商的 Agent 协作场景。
11.14.3 Agent 身份与信誉
当 Agent 跨组织协作时,"身份"和"信誉"成为核心问题:
- 身份:每个 Agent 有可验证的 DID(去中心化身份)
- 信誉:基于历史调用记录计算的信誉分
- 审计:每个 Agent 的关键决策可被追溯
- 授权:用户授权某个 Agent 访问哪些资源
这块目前还很早期,但方向清晰——Agent 也会有"职业信誉",就像人有信用分一样。
11.14.4 未来编排趋势图
┌──────────────────────────────────────────────────────────────────────┐
│ Agent 编排的未来趋势 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 当前 (2026) │
│ ├── 单厂商 SDK 内编排(Claude Code、Cursor) │
│ ├── 框架式编排(AutoGen、LangGraph、Swarm) │
│ └── MCP 标准化工具接入 │
│ │
│ 近期 (2027-2028) │
│ ├── ACP 跨厂商 Agent 通信标准化 │
│ ├── Agent 市场涌现 │
│ ├── 跨组织 Agent 协作(你的 Agent 调用我的 Agent) │
│ └── 可观测性标准化(trace、metrics 跨厂商) │
│ │
│ 远期 (2029+) │
│ ├── Agent 身份与信誉体系成熟 │
│ ├── Agent 自主交易(Agent-to-Agent 经济) │
│ ├── Agent 治理(合规、审计、问责) │
│ └── Agent 联邦(多 Agent 自组织成"Agent 公司") │
│ │
│ 终极愿景:Agent 网络成为人类社会的新型基础设施 │
│ │
└──────────────────────────────────────────────────────────────────────┘
金句:今天的 Agent 编排,相当于 1995 年的互联网——协议刚出,应用刚冒,没人知道 30 年后会变成什么。但有一点确定:协议、市场、信誉这三件事,会成为下一代 Agent 工程的基石。
11.15 最佳实践 Tips
经过前面十几节的论述,这里汇总 10 条最佳实践。每条都是踩坑后的提炼。
- 从单 Agent 起步,确认不够再拆 Sub-Agent。不要一上来就多 Agent,简单性是工程美德。
- Sub-Agent 数量控制在 3-7 个。超过 10 个就该考虑层级编排。
- 每个 Sub-Agent 有明确的 description。这是 SDK 路由的依据,模糊的 description 会导致路由错乱。
- 每个 Sub-Agent 独立 session。隔离是质量保证,不是性能优化。
- 验证型 Sub-Agent 只读。结构上禁止它修改产物,避免"自审自批"。
- provider_id 持久化。Sub-Agent 跨调用必须 sticky 到同一 OAuth 账号,否则 thinking block 签名失效。
- 委派必须有 deadline。没有超时的委派,迟早会陷入死锁。
- 失败要部分成功 + 明确标记。长程任务里"全部回滚"代价过大,部分成功是更现实的选择。
- 每个 Sub-Agent 都要可独立测试。给每个 Sub-Agent 写 golden case,回归时能快速定位。
- 可观测性是底线。trace、metrics、logs 三位一体,缺一不可。没有可观测性的多 Agent 系统,是给未来的自己挖坑。
金句:最佳实践的本质,是"不要重新发明轮子"。前人踩过的坑,没必要再踩一遍——除非你想交自己的学费。
11.16 番外篇:生物学中的细胞分化——从干细胞到专职细胞
讲完工程,讲点生物学。Sub-Agent 的"专业分工"思想,在生命系统里有极其精妙的对应——细胞分化。
11.16.1 干细胞与多能性
人体的起点是一个受精卵。它是全能干细胞——能分裂出人体的任何细胞。这就像一个"全能 Agent",理论上什么都能做。
但随着胚胎发育,细胞开始分化:
| 阶段 | 细胞类型 | 能力 |
|---|---|---|
| 受精卵 | 全能干细胞 | 能发育成完整个体 + 胎盘 |
| 囊胚期 | 多能干细胞 | 能发育成所有组织,但不能成胎盘 |
| 三胚层期 | 专能干细胞 | 只能发育成某一胚层的细胞 |
| 终末分化 | 成熟体细胞 | 只做一种职能(神经、肌肉、上皮) |
分化的本质是"放弃潜能换取专精"。神经元放弃了分裂能力,换取了极致的电信号传导;红细胞放弃了细胞核,换取了高效的氧气运输。
11.16.2 与 Sub-Agent 的对应
把这个模型映射到 Agent 系统:
| 生物学 | Agent 系统 |
|---|---|
| 受精卵(全能) | 单 Agent(理论全能) |
| 多能干细胞 | 通用 Sub-Agent(如 coder 通用编程) |
| 专能干细胞 | 专项 Sub-Agent(如 sql-agent 专精 SQL) |
| 终末分化细胞 | 高度定制的 Sub-Agent(如 K8s-yaml-validator) |
| 组织 | 多个同类 Sub-Agent 协作 |
| 器官 | 多个组织协作完成大功能 |
| 系统 | 多个器官协作维持生命 |
| 个体 | 整个 Agent 系统 |
11.16.3 分化的工程智慧
细胞分化给我们的工程启示:
- 不是越分化越好。干细胞太少,组织无法再生;分化细胞太多,组织失去灵活。Sub-Agent 同理——3-7 个为佳,10 个为限。
- 保留少量干细胞。人体保留少量成体干细胞用于修复。Agent 系统也应保留"通用 Agent"做兜底,专精 Agent 不擅长时 fallback。
- 分化要可逆(部分)。诱导多能干细胞(iPS)让分化细胞重编程为干细胞。Agent 系统里,Sub-Agent 的系统提示可改、工具可换,这就是"重编程"。
- 每个细胞都有全套 DNA。即便分化了,神经细胞里仍然有完整的基因组。Agent 系统里,每个 Sub-Agent 仍然可以访问全局知识库,只是默认不激活——这是一种"潜力保留"。
- 细胞间通信靠信号分子。激素、神经递质、细胞因子——本质是消息。Agent 间的通信也是消息,松耦合是关键。
金句:生命系统是亿万年试错的产物,它的工程智慧远超我们的代码。Sub-Agent 的"专业分化",本质是生命系统在代码世界的投影。
11.17 番外篇:企业组织架构——从个人贡献者到矩阵管理
第二个番外篇讲组织。Sub-Agent 协作,本质是"AI 版的组织管理"。看懂人类组织,就看懂了 Agent 编排的边界。
11.17.1 组织形态演进
| 时代 | 主流组织 | 特点 | 对应 Agent 编排 |
|---|---|---|---|
| 手工业 | 个人工匠 | 一人全干 | 单 Agent |
| 工厂制 | 流水线工人 | 串行分工 | Pipeline 串行编排 |
| 职能制 | 部门制 | 职能分组(市场、研发、销售) | 按职能拆 Sub-Agent |
| 事业部制 | BU | 按产品/地域分组 | 层级编排 |
| 矩阵制 | 双线汇报 | 职能 + 项目 | 黑板 + 层级混合 |
| 敏捷制 | 小队自治 | 跨职能小队 | 对抗 + 并行 |
| 自组织 | 去中心化 | 个体自治 | 黑板模式 |
11.17.2 经验对照
| 组织痛点 | Agent 痛点 |
|---|---|
| 部门墙(信息不流通) | Sub-Agent 上下文隔离过度 |
| 责任分散(没人负责) | 多 Agent 责任分散反模式 |
| 官僚主义(流程冗长) | 过度编排反模式 |
| 微观管理(不信任员工) | Sub-Agent 工具集过窄、不给决策权 |
| 山头主义(小团队利益) | Sub-Agent 各自为政,缺乏整合 |
11.17.3 治理启示
- 给 Sub-Agent 适度自主权。像管员工一样——给目标、给工具、给边界,至于怎么干让 Sub-Agent 自己决定。
- 建立"绩效考核"。每个 Sub-Agent 的输出质量、调用频次、失败率要持续监控,做得差的优化或下线。
- 建立"晋升通道"。高频被调用的 Sub-Agent 值得投入更多优化(更好的系统提示、更精的工具)。低频的可以合并或下线。
- 跨组织协作要 protocol。不同厂商的 Agent 协作,必须靠标准 protocol(MCP、ACP),不能靠"默契"。
- 保持组织敏捷。Sub-Agent 的职责、工具、系统提示应能快速调整,不要固化成"不可动的石头"。
金句:管 Agent 像管组织——管得太死,失去敏捷;管得太松,陷入混乱。中庸之道,是工程,也是艺术。
11.18 本章小结
让我们把全章的核心要点收束一下。
11.18.1 全章核心论点
- Sub-Agent 的必要性:单 Agent 的上下文窗口是物理边界,长程任务必须靠 Sub-Agent “扩容”。
- 设计哲学四原则:单一职责、松耦合、独立上下文、可独立验证。
- 角色分类四类:执行型、验证型、协调型、专项型,各有设计要点。
- 编排模式五谱系:串行、并行、层级、对抗、黑板,按控制力强弱排列,现实系统多为混合。
- 通信机制四要素:主→Sub 委派、Sub→主 返回、Sub↔Sub 默认禁止、共享黑板异步通信。
- 上下文隔离四层:独立 session、独立工作目录、独立工具权限、防止心态污染。
- HappyClaw 实现:通过 SDK
agents选项注册,独立 session + 独立 provider_id(sticky 避免 thinking block 签名失效)。 - 典型工作流:主 Agent 拆解→委派→Sub-Agent 执行→返回→主 Agent 整合。
- 并行设计三难点:任务可分性、结果合并、失败处理。
- 五大反模式:数量膨胀、通信开销过大、责任分散、协调死锁、过度编排。
- 决策树:能单 Agent 解决就单 Agent,必要时才拆。
- 业界实践:Claude Code、Cursor、AutoGen、LangGraph、Swarm 各有哲学。
- 可观测性三支柱:调用链追踪、token 归因、失败传播分析。
- 未来趋势:市场化、protocol 标准化、Agent 身份与信誉。
- 生物学隐喻:细胞分化启示"专业分化 + 保留干细胞"。
- 组织学隐喻:组织演进对应 Agent 编排演进,治理智慧可互鉴。
11.18.2 一句话总结
Sub-Agent 不是"把一个 Agent 拆成多个"那么简单,它是一套关于职责切分、上下文隔离、结果整合的完整工程哲学。其核心,是把人类几千年的组织智慧,迁移到 AI 系统中。
11.18.3 与其他章的联系
- 第 2 章讲的 Harness Engineering 是"单 Agent + 工具"的范式,本章是它的扩展与升级。
- 第 4 章的上下文管理,是 Sub-Agent 隔离设计的物理基础。
- 第 7 章的 Loop Engineering,是 Sub-Agent 在长程任务中持续协作的循环框架。
- 第 9 章的工具调用,是 Sub-Agent 工具集设计的基础。
- 第 12 章(如果有的话)会讲多 Agent 系统的安全与对齐,是本章的延伸。
11.19 思考题
-
场景题:你要构建一个"自动化数据分析 Agent",用户上传 CSV 后 Agent 自动清洗、分析、可视化、写报告。请设计这个系统的 Sub-Agent 架构:需要哪些 Sub-Agent?用什么编排模式?每个 Sub-Agent 的工具集是什么?
-
设计题:设计一个"maker-checker"对抗编排,用于"生成 SQL 查询 + 防注入审查"。给出 maker 和 checker 的系统提示大纲、工具集、收敛条件、失败处理策略。
-
分析题:分析 HappyClaw 的
code-reviewer和web-researcher设计,找出 3 处可以改进的地方,并说明改进方案与代价。 -
辩论题:有人说"未来 Agent 系统会越来越倾向单 Agent + 海量工具,Sub-Agent 是过渡形态"。请论述正反方观点,并给出你的判断。
-
工程题:你接手一个有 30 个 Sub-Agent 的系统,发现路由决策错误率高、维护成本大。请给出"瘦身"方案:保留哪些、合并哪些、下线哪些?判断依据是什么?
-
开放题:如果让你设计一个跨厂商的 Agent 协作 protocol(ACP),你会规定哪些必填字段?为什么?
-
反思题:本章用"细胞分化"和"组织管理"做隐喻。这种隐喻的边界在哪里?哪些地方隐喻成立,哪些地方隐喻失效?
本章结束。Sub-Agent 不是终点,是 Loop Engineering 的起点。当 Sub-Agent 学会协作,长程任务才真正成为可能。下一章见。
更多推荐
所有评论(0)