什么时候不该用 Agent?

Anthropic 的 Building effective agents 把 agentic 系统分成两类:workflow(代码定好路径)和 agent(模型自己决定下一步)。它的第一条建议是:先用最简单的方案,确实需要时再加复杂度。

对测开来说,选哪种模式,就决定了你要测哪几个点、端到端成功率怎么算、成本和延迟能不能提前估出来。

1先退一步看全局

这一周的其他章节会从零写 agent loop、做工具调用、写 MCP server、给 loop 加 trace。动手之前先回答一个更基础的问题:这个需求真的需要 agent 吗?

本章读的是 Anthropic 工程博客 2024 年 12 月 19 日发表的 Building effective agents(Erik Schluntz、Barry Zhang)。文章的结论来自他们和几十个客户团队一起做项目的经验:做得好的团队,用的都是简单、可组合的模式,而不是复杂的框架。

原文顶部后来加了编者按:文中提到的工具生态自 2024 年 12 月以来变化很大。编者按只说工具生态变了,并指向 Claude Managed Agents 的最新做法。我们的判断是:下面讲的模式和原则仍然适用。

2两个定义:workflow 和 agent

原文把所有这类系统统称为 agentic systems,再按"谁决定流程"分成两种:

WorkflowAgent
谁决定下一步代码模型
步数固定,或有明确上限不固定,靠停止条件兜底
成本和延迟可以提前算出来是一个分布,要看 P50 / P95
原文的适用场景定义清楚的任务,要可预测、结果一致需要灵活性、需要模型在规模化场景下自己做决策
测开怎么测每个节点单独测,再算端到端测端到端结果 + 看 trace + 测停止条件
原文的原话是:agentic 系统通常是拿延迟和成本换更好的任务表现。很多应用只要把单次 LLM 调用优化好(加检索、加 in-context 示例)就够了,根本不需要 agentic 系统。

3基本构件:增强型 LLM

所有模式都用同一块积木:增强型 LLM(augmented LLM),也就是加上了检索、工具、记忆的 LLM。现在的模型可以自己生成搜索词、自己选工具、自己决定记住什么。

原文给了两条要求:这些能力要按你的场景裁剪;给模型的接口要简单、文档写清楚。接第三方工具的一种方式是 Model Context Protocol(MCP),本周有单独一章。

测开视角:这一块就是一次调用。它能测的东西最多、最便宜:固定输入、跑 n 次、数成功次数,第 1 周的 rule of three、Wilson、pass^k 全都直接能用。

4Workflow 1:提示链(prompt chaining)

做法:把任务拆成固定的几步,每次调用处理上一步的输出。中间可以加程序化检查(原文叫 gate),确认流程还在正轨上。

适用:任务能干净地拆成固定子任务。用延迟换准确率:每次调用的任务更简单,更容易做对。原文例子:先写营销文案再翻译;先写大纲、检查大纲是否符合要求,再按大纲写正文。

测开视角:怎么测、哪里容易坏

5Workflow 2:路由(routing)

做法:先对输入分类,再交给对应的专用下游处理。关注点分开,每个下游的 prompt 可以写得更专门。

适用:输入有几类明显不同、分开处理更好的情况,并且分类能做准(用 LLM 或传统分类器都行)。原文例子:客服问题分成一般咨询、退款、技术支持;简单问题交给小模型,难题交给大模型,省钱。

测开视角:怎么测、哪里容易坏

6Workflow 3:并行(parallelization)

做法:几个 LLM 同时干活,输出由代码聚合。分两种:

注意:原文的投票不限于过半。漏洞审查的例子是几个 prompt 各自审查、发现问题就标记,相当于任一票即报警的或规则;内容审核的例子是用不同的票数阈值平衡误报和漏报。阈值越低越偏召回,越高越偏精确。下面的计算以多数投票为例。

适用:子任务能并行、要速度;或者需要多次尝试、多个视角来提高把握。

测开视角:怎么测、哪里容易坏

7Workflow 4:编排者-工人(orchestrator-workers)

做法:一个中心 LLM 动态拆解任务,分给若干工人 LLM,再汇总结果。

和并行的区别:拓扑看着像,但子任务不是预先定义的,而是编排者根据具体输入决定的。原文例子:每次要改多个文件的编程产品(改几个、改哪些取决于任务);要从多个来源收集、分析信息的搜索任务。

测开视角:怎么测、哪里容易坏

8Workflow 5:评估者-优化者(evaluator-optimizer)

做法:一个 LLM 生成,另一个 LLM 评估并给反馈,循环修改。

适用:有明确的评估标准,并且反复修改确实能带来可衡量的提升。两个信号:人给出反馈后,LLM 的回答明显变好;LLM 自己也能给出这种反馈。原文例子:文学翻译(译者模型可能漏掉细节,评估者能指出来);需要多轮搜索的复杂搜索任务,由评估者决定还要不要继续搜。

测开视角:怎么测、哪里容易坏

9自主 Agent

做法:从用户的指令或讨论开始,任务明确后 agent 自己规划、自己行动,必要时回来找人确认。每一步都从环境拿"真实情况"(工具调用结果、代码执行结果)来判断进展。常见的停止条件是最大迭代次数。

原文说,实现上它们通常就是一个 LLM 在循环里根据环境反馈调用工具,所以工具集和工具文档的设计至关重要。本周"从零写 agent loop"一章就是写这个循环。

适用:开放式问题,很难或无法预测需要多少步,也没法把路径写死;模型可能要跑很多轮,你得对它的决策有一定信任。原文例子:解决 SWE-bench 任务的编程 agent(一个任务改多个文件);让 Claude 操作电脑的 computer use 参考实现。

原文点明的代价:成本更高,以及错误会累积。建议在沙箱里充分测试,并加上合适的护栏。

测开视角:怎么测、哪里容易坏

10可靠性账:步骤越多,越要小心

把链路上每一步的成功率乘起来,就是端到端成功率:

$$P_{\text{端到端}} = p_1 \times p_2 \times \cdots \times p_n$$
每步成功率5 步10 步20 步
90%59.0%34.9%12.2%
95%77.4%59.9%35.8%
99%95.1%90.4%81.8%
  1. 这就是 pass^k 的公式,只是 k 从"同一请求跑 k 次"换成了"链路上的 k 步"。前提也一样:每步独立,且每步的成功率要在真实上游输出上测。如果各步错误正相关(难的输入每步都难),真实成功率反而会比乘积高,这和第 1 周 Agent B 的例子是同一个道理。真正会让成功率低于乘积的,是每步只用干净快照测出的 p:上游“做对了但质量偏差”的输出,会让下一步的实际成功率低于快照测出的值。
  2. 反推每步要多可靠:10 步想要端到端 90%,每步要 \(0.9^{1/10} \approx 98.95\%\)。
  3. 每步 99% 怎么证明:按 rule of three,零失败要跑约 300 次(精确法 299 次)。步数越多,要证明的东西越多。
  4. 乘积也可以被打破:gate 检出错误后重试、agent 从环境反馈里发现错误并纠正,都能把端到端成功率拉回来,代价是多出来的调用次数和延迟。
workflow 的步数固定,成本和延迟可以提前算。agent 的步数由模型决定,同一个任务这次 8 步、下次 14 步。所以评测 agent 时,成本和延迟要当成随机变量来报:给分布、给 P95,而不是一个平均值。

11原文的核心建议

原文 Summary 部分给出了三条核心原则:保持简单;让 agent 的规划步骤透明可见;认真设计 agent-computer interface(ACI)。另外,它对框架单独给了建议。

原则 1:保持简单,先用最简单的方案

从单次调用开始,只有当更复杂的方案可以证明效果更好时才加复杂度。"可以证明"就是评测的活:新方案和旧方案在同一批用例上比,数字说话。

原则 2:让规划步骤透明

agent 打算做什么、为什么这么做,要显式地展示出来。对测开来说,这就是可观测性:规划和每一步决策都进 trace,出错时才能定位(本周 trace 一章)。

原则 3:认真设计 ACI(把工具接口当成产品)

ACI 要像人机界面一样投入:工具要写好文档、充分测试。具体做法见下面的列表。

另外:谨慎使用框架

框架能帮你省掉调用 LLM、定义和解析工具、串联调用这些底层工作,但多出来的抽象层会遮住底层的 prompt 和响应,让调试更难,也容易让人加上本来不需要的复杂度。建议先直接用 LLM API,很多模式几行代码就能写出来。如果用框架,要搞懂它底层在做什么;原文说,对"底层到底在干什么"的错误假设,是客户出错的常见原因。

ACI 的具体做法

测开视角:ACI 就是被测系统和模型之间的"接口契约"。工具契约测试(参数校验、错误信息是否能让模型看懂并自我纠正)是这一章最直接能落地的测试工作。

▶模拟器:选模式,调参数,看成功率、成本和延迟

两个成功率要分开:p₀ 是一次调用做完整个任务的成功率(单次调用、投票、评估者-优化者的生成器用它);p 是拆小以后每一步的成功率(提示链、路由的下游、分段、编排者-工人、agent 的每一步用它)。模型都假设各步独立。

模式
端到端成功率
期望调用次数(成本)
期望延迟

所有模式对比(各模式用各自的当前参数)

▶场景判断:给需求,选模式

按原文的判断标准选最合适、最简单的一种。选完看解析,再点"下一题"。

✎练习

题 1(算):提示链 6 步,每步成功率 95%,没有 gate,各步独立。端到端成功率是多少?
%
0.956 ≈ 0.7351 = 73.5%。每步看着都挺好,6 步乘下来只剩七成多。和 pass^6 是同一个公式。
题 2(算):路由分类准确率 90%,分对以后专用处理器成功率 96%,分错按失败算。端到端成功率是多少?
%
0.90 × 0.96 = 86.4%。分类准确率是整条链路的天花板,所以路由要先单独测分类,看混淆矩阵。
题 3(算):5 票多数投票,每票独立、正确率 80%。多数投票结果正确的概率是多少?
%
至少 3 票对:C(5,3)·0.8³·0.2² + C(5,4)·0.8⁴·0.2 + 0.8⁵ = 0.2048 + 0.4096 + 0.32768 = 94.2%。同样 5 次,pass@5 = 1 − 0.2⁵ = 99.97%,但那需要一个能挑出正确那次的检查器。
题 4(概念):一个判断任务单票正确率只有 40%。把多数投票从 3 票加到 9 票,会怎样?
3 票时 35.2%,9 票时 26.7%。多数投票只在单票正确率高于 50% 且票与票相互独立时才有帮助。可以在模拟器里把 p₀ 拖到 40% 验证。
题 5(排查):评估者-优化者把最大轮数从 3 轮(83%)调到 10 轮,成功率只涨到 87% 左右就上不去了,成本却涨了。最可能的原因是?
成功率上限是 p(1−f) / [p(1−f) + (1−p)m],m 是漏判率。p = 60%、f = 10%、m = 20% 时上限 87.1%。坏稿子一旦被放行,流程就结束了。评估者就是一个 Judge,要按第 5 周的方法校准。

12面试要点与代码

一句话讲清楚

Workflow 是代码定路径,agent 是模型定路径。Anthropic 的建议是先用最简单的方案,单次调用够就不上 workflow,workflow 够就不上 agent。从评测角度看,链路上每一步的成功率要相乘,步数越多越难做到可靠;agent 的步数不固定,成本和延迟要按分布报 P95。每种模式有自己的薄弱点:路由看分类准确率,投票看独立性,评估者-优化者看评估者的漏判率。

常见错误说法

❌ "用 agent 肯定比 workflow 强":agent 拿成本、延迟和可预测性换灵活性,任务路径固定时是亏的。
❌ "每一步都 95%,整体应该也差不多":10 步乘下来只有 59.9%。
❌ "投票次数越多越准":单票低于 50% 时越投越差;同源的票相关,提升也比独立时小。
❌ "加一个评估者自动把关就行了":评估者自己会漏判,只要漏判率 m > 0,成功率的上限就到不了 100%。
❌ "agent 平均一次花 8 步":只报平均值,看不到长尾。门禁要看 P95。
❌ "先上一个框架再说":原文建议先直接用 LLM API,搞懂底层再决定要不要框架。
from math import comb

def chain(p: float, n: int) -> float:
    """提示链:n 步各自成功率 p,各步独立时的端到端成功率。"""
    return p ** n

def majority_vote(p: float, m: int) -> float:
    """m 票(奇数)多数投票,每票独立、正确率 p。"""
    if m % 2 == 0:
        raise ValueError(f"票数要是奇数,收到 m={m}")
    return sum(comb(m, k) * p**k * (1 - p)**(m - k) for k in range(m // 2 + 1, m + 1))

def evaluator_optimizer(p: float, rounds: int, miss: float, false_reject: float) -> float:
    """每轮生成器成功率 p;评估者漏判率 miss、误杀率 false_reject;
    最多 rounds 轮,最后一轮被打回也照样输出。"""
    accept_good = p * (1 - false_reject)
    accept_bad = (1 - p) * miss
    reject = 1 - accept_good - accept_bad
    ok = sum(reject**i * accept_good for i in range(rounds))
    return ok + reject**(rounds - 1) * p * false_reject

print(chain(0.95, 10))                          # 0.5987
print(majority_vote(0.8, 5))                    # 0.9421
print(evaluator_optimizer(0.6, 3, 0.2, 0.1))    # 0.8318

公式显示依赖 KaTeX(CDN),断网时公式会显示成原始 LaTeX 源码,交互部分不受影响。