子智能体该不该并回主循环:一份架构取舍清单

子智能体该不该并回主循环:一份架构取舍清单

原文:Anthropic Blog - 《Building agents: When to fold subagents into your main agent loop》(https://claude.com/blog/building-agents-when-to-fold-subagents-into-your-main-agent-loop)

一、先把三种架构摆在同一张桌上

Anthropic Applied AI 团队在 10 月 22 日发了这篇文章,作者是 Diane Sarkis。它比较的不是模型,而是三种把同一个业务装进 Agent 的方式:

架构 长什么样 典型症状
一提示全包 一个超长系统提示,把流程、规则、口径全写进去 规则互相打架,改一句话影响三处
orchestrator + 子智能体 一个路由器 + 规划器 + 若干领域子智能体 交接丢细节,链路变长,延迟上去了
单 Agent + skills 一个模型、一个上下文窗口,能力靠 skills 与工具渐进加载 需要管好系统提示与上下文,靠纪律

原文的结论很直接:在多个企业部署的横向对比里,单 Agent 带 skills 在质量上常常优于另外两种,而且往往每任务的成本与延迟都更低。有一个客户拿自己的多 Agent harness 和单循环做了对照,后者的运行时间大约快 2 倍。

也就是说,过去两年我们被教的那套"先分层、再拆专家"的做法,在这个模型代际上开始反向走了。有两个真实观察支撑这个转向:

一是某公司的面向客户 Agent 里塞了十几个专家子智能体,结果品牌口径难以保持一致,延迟也把体验拖坏了。二是不少企业按团队或问题类型一一切分子智能体,最后架构变成了组织架构图的复印件------这就是 Conway 定律在 Agent 上的复现。

二、什么情况下该保留子智能体

这篇文章没有走向"全合并"的极端。它给了三条明确的保留条件,我按可直接落地的说法重写一遍:

  1. 单循环因为上下文膨胀出现了可测量的性能下降。注意是"可测量",不是"感觉有点长"。
  2. 多个任务需要并行,并且各自需要一份用完即弃的干净上下文窗口。
  3. 单 Agent 已经选不准工具,或者系统提示里出现了互相冲突的指令。

这三条的共同点是:它们是症状,不是偏好。你如果只是因为"架构图上分专业更清楚"而拆,那属于组织需求,不是技术需求------而这类需求完全可以用 skills 承接,不必付出子智能体那层开销。

三、合并顺序:按共享上下文,不按问题类型

这是我认为全文最值得抄下来的一条工程法则。拆分维度选错了,后面怎么调都是徒劳。

按上下文切分是有效的:给每个子智能体一块几乎不需要系统其余部分的工作,让它交回一个紧凑结果。独立的调研路径、接口干净的独立组件、黑盒验证,都属于这一类。

按问题类型切分是有害的:因为问题类型之间天然共享上下文,一旦切开,信息就得靠交接来回传递。原文用的词是传话游戏(telephone game),每一次交接都掉一层保真度。

落到合并动作上,有四条可操作的判据:

  • 从使用最频繁的子智能体开始折,收益最快兑现。
  • 相互串联输出、访问同一份数据、经常被一起调用的专家,优先合并。
  • 如果生产流量里很大一部分是"A 专家紧接着 B 专家",那这就是一对紧耦合,应该并成一个领域 Agent。
  • 一次只折一个,折完用评测对比,分数变差就退回去。

最后那条是整篇文章的方法论核心,比任何架构图都重要。

四、单循环到底该长什么样

原文给了一份设计规格,可以直接照着改代码。它描述的是一个模型、一个上下文窗口,跑开放式工具循环,而所有硬约束都由外层 harness 承担:

  1. 每一轮,模型发一批工具调用;harness 并行执行,把原始结果回给同一个模型。
  2. 模型看着结果决定下一步:再发一批、向用户提问、或者给答案。
  3. 循环在模型给出答案或撞到预算时结束。答案之后可以再跑一次目标检查或验证器。
  4. 模型在第一轮就把计划写进上下文,随结果到达而修订计划。

第 4 条是和 orchestrator 架构最本质的差别:写计划的那个模型,同时也是执行计划的模型,所以它可以在轮次中途改计划。而 orchestrator 模式下,计划在路由器那里定死,子智能体只能在自己那格里执行。

配套的上下文策略有两条,都是为了把"拆出去的理由"直接消掉:

  • 上下文靠 skills 渐进披露。Agent 先看到 skill 的简短描述,需要时才完整加载。
  • 工具靠 tool search 渐进披露。同理,先看描述,用时再载入。

原文提了一个数字:为更先进的模型重写 Claude Code 的系统提示时,缩减幅度超过 80%,其中就包括与 skills、工具渐进披露相关的裁剪。它给的第三个理由是模型本身变强了------从 Opus 4.5 起,模型在单循环里能管的事情远超大多数团队的预期,而且会边做边播报进度、自己回头检查,这让一部分 harness 组件变得多余。

工具层面还有几个硬数字和硬规则:

项目 建议 原因
系统提示内工具定义数 超过 30 到 50 个后开始退化 工具选择准确率下降
起步规模 一个清晰系统提示 + 4 到 5 个瘦数据工具 + 硬输出护栏 覆盖多数用例
分组方式 按用户意图分组,不是一个 API 一个工具 减少工具数量与歧义
权限 每个工具自行校验调用者权限,返回模型能读懂的普通拒绝 一个循环即可服务不同权限的用户

最后一条很实用:它意味着你不需要为每个权限档位单独做一个 Agent。

至于什么时候仍然需要保留子智能体,原文的边界划得很窄------只有子智能体必须直接和用户对话时,才值得做完整交接。其余场景都可以拆成"skill + 工具"塞回主循环。

五、迁移时最容易漏的一步:验证

这部分是我最想单独拎出来讲的,因为它描述的失败太真实了。

原文举了一个支持类 Agent 的例子:把 A 子智能体折进 B 之后,延迟确实降了,但一条原本在跑的流程断了------主 Agent 自己握着订单查询工具,直接回答了问题,没有再去问发货专家要那个日期。也就是说,能力合并了,但"必须去问另一个角色"这个隐性流程约束消失了。

更麻烦的是频率:这种断裂在两次运行里只出现一次。你跑一遍全绿,就以为没事了。

所以评测要按这几条搭:

  • 结构上,中央团队维护一套端到端评测集,每个 skill 由所属团队带一套小评测一起发。
  • 规模上,10 个 golden example 就足够起步,不必等评测体系建完。
  • 指标上分阶段:还有 orchestrator 时看路由准确率(选对了子智能体没有);折进去之后改看是否加载了对的 skill、调了对的工具。
  • 每条生产上会一起跑的 Agent 链路、每条不许破的规则,都要有对应用例,并且每条用例至少跑多次。
  • 对比时不要只看最终分数,要看哪些任务发生了翻转。
  • 环境难复现时,给关键事件打时间戳,之后按时间戳重放成定向评测。

这里有个我自己踩过的坑值得补一句:只看总分时,"A 变好、B 变差、总分不变"这种情况是完全隐形的,而它恰恰是合并最典型的中间状态。

六、一段折叠前后的对比骨架

下面这段是我按文章的方法论自拟的示意代码,不是官方实现,也不依赖任何 SDK,目的是把"跑多次 + 看翻转"这两件事固化下来。

python 复制代码
# fold_compare.py ------ 折叠前后对比,重点不是平均分,是"跑多次"和"看翻转"
import statistics
import time


def run_suite(agent, cases, repeats=3):
    """agent 需要有 run(case) 方法,返回带 passed 字段的字典。
    返回 (runs, latencies):runs 是每次运行的 {case_id: bool},latencies 是每轮延迟中位数。"""
    runs, latencies = [], []
    for _ in range(repeats):
        one_run, lats = {}, []
        for case in cases:
            t0 = time.perf_counter()
            out = agent.run(case)
            lats.append(time.perf_counter() - t0)
            one_run[case["id"]] = bool(out.get("passed"))
        runs.append(one_run)
        latencies.append(statistics.median(lats))
    return runs, latencies


def unstable(runs):
    """同一用例在不同运行里结果不一致 → 说明评测本身还不稳,先别拿它下结论。"""
    ids = runs[0].keys()
    return {i for i in ids if len({r[i] for r in runs}) > 1}


def flipped(before, after):
    """只比通过/失败的反转,不看总分。before、after 各取一次运行的 {case_id: bool}。"""
    won = {i for i in before if not before[i] and after[i]}
    lost = {i for i in before if before[i] and not after[i]}
    return won, lost


if __name__ == "__main__":
    # 伪代码式调用:先 orchestrator 版,再折掉一个子智能体的单循环版
    base_runs, base_lat = run_suite(orchestrator_agent, CASES, repeats=3)
    fold_runs, fold_lat = run_suite(single_loop_agent, CASES, repeats=3)

    print("抖动用例:", unstable(base_runs) | unstable(fold_runs))
    won, lost = flipped(base_runs[0], fold_runs[0])
    print(f"折叠后变好 {len(won)} 条,变差 {len(lost)} 条")
    print(f"延迟中位数 {statistics.median(base_lat):.2f}s → {statistics.median(fold_lat):.2f}s")

参数与返回值:run_suite 收三个参数------被测 Agent、用例列表、重复次数,返回两个列表,runs 里存的是每轮每题的布尔结果,latencies 里存的是每轮延迟中位数。它的返回结构刻意做成"按轮存"而不是"直接给个总分",因为后面两步都要用到逐题逐轮的原始数据。

unstable 只吃 runs,返回在多次运行中结果不一致的用例集合。这个函数应该在比较之前先跑一遍:如果抖动集合很大,说明你的评测是噪声,此时看翻转毫无意义。

flipped 收两次运行的逐题结果,返回变好、变差两个集合。调用链是:准备用例 → 跑 baseline → 折叠一个子智能体 → 重跑 → 先排除抖动用例 → 比翻转 → 只有净收益为正才保留这次改动。

这段代码刻意没做的一件事是算总分。因为一旦它吐出总分,人就会只看总分。

收尾

这篇文章的价值不在于"子智能体过时了"这种断言------原文自己留了三条保留条件,也明说子智能体在研究前沿仍有位置。它真正的贡献是把架构争论变成了可执行的迁移流程:测量、一次只改一个、留下扛得住的那个。

如果你的 Agent 现在有路由器、规划器和一堆领域子智能体,我建议的下一步不是重构,而是先花半天写 10 条 golden example,跑三遍,看看有多少用例是抖动的。抖动大的话,先修评测,再谈架构。

文中数据与判断来自 Anthropic 10 月 22 日的这篇博客,涉及具体模型能力与工具阈值的部分,以官方文档为准。

相关推荐
Dawson Zhu3 小时前
【AI编译器入门④】编译中端:图优化Pass全解析——DCE、常量折叠、算子融合与布局变换
人工智能·语言模型·架构·aigc·agi
Decay__3 小时前
附-01 · MySQL 压测与容量规划 —— sysbench 基准测试、容量评估与参数基线
运维·数据库·sql·mysql·架构
这个DBA有点耶3 小时前
主从切换报成功,业务却写不进去——数据层脑裂与应用层连接残留的两类假成功
数据库·架构·dba
七牛开发者4 小时前
多 Agent 架构中的 Subagent 拆分与合并策略
架构·agent·multiagent·subagent·harness
超级架构师4 小时前
让 COBOL 长出 AI 大脑:原生 Agent 核心框架 praxo-core 深度剖析
c语言·开发语言·c++·人工智能·python·架构·ai编程
4SAPI4 小时前
企业级大模型工作流基础设施选型指南:4SAPI、硅基流动与 OpenRouter 的架构权衡
运维·人工智能·架构·自动化
vipxieliang4 小时前
软件架构的核心原则:从抽象到权衡
架构
元岳数字人小元5 小时前
告别云端依赖,数字人本地部署筑牢项目安全底座
人工智能·安全·架构·开源·人机交互·交互