跳到主要内容

Agent 测试金字塔:为什么 70/20/10 的分层对 Agentic AI 行不通

· 阅读需 14 分钟
Tian Pan
Software Engineer

每一个从"我们有个聊天机器人"升级到"我们有个 Agent"的工程团队,都会撞上同一堵墙:他们的测试套件开始失去意义。

经典测试金字塔——70% 单元测试、20% 集成测试、10% 端到端测试——建立在三个基本假设之上:单元测试运行成本低、与外部系统隔离、结果确定可重复。Agentic AI 系统同时打破了这三个假设。所谓的"单元"是一次消耗 token 且每次返回不同结果的模型调用。一次端到端运行可能耗时数分钟,消耗的 API 预算足以让一位初级工程师整个迭代周期的测试都无法证明其合理性。而隔离性几乎无从实现,因为 Agent 的智能恰恰来自于与外部工具和状态的交互。

结果是可以预见的:要么团队完全不写测试,靠直觉和感觉行事;要么写出一堆端到端测试,慢到无法在 CI 中运行,贵到无法对每个 PR 执行,不稳定到无法信任。两种选择都算不上真正的测试策略。

经典金字塔的正确之处(以及它为何适用于普通代码)

测试金字塔最初由 Mike Cohn 提出,后经 Martin Fowler 推广普及,它反映了一个真实的经济学洞察。单元测试之所以快,是因为没有 I/O——没有网络、没有数据库、没有外部服务。当单元测试失败时,你能精确知道哪个函数出了问题。在规模化场景下,一套包含 10,000 个测试的套件应该能在 90 秒内跑完。

集成测试因为涉及真实的子系统——数据库写入、服务调用——所以更慢,但你只需要足够的测试来确认各模块能够正确协同工作。端到端测试从用户视角运行整个系统,刻意保持稀疏,因为它们维护成本高且执行缓慢。

金字塔的形状本身就编码了成本信息:底部是大量廉价的测试,顶部是少量昂贵的测试。整个模型能够运转,是因为单元是确定性的纯函数。相同的输入永远产生相同的输出。

LLM 调用不是纯函数。它是在由模型权重、温度参数、系统提示词、历史对话记录,乃至时间(当模型提供商悄悄推出静默更新时)共同塑造的分布上进行的概率采样。Agentic 系统的"单元"本质上是非确定性的。你无法用 assertEqual(agent_output, expected) 来断言任何有意义的东西。

Agent 如何在每一层打破金字塔

单元层没有真正的"单元"

在传统服务中,你可以对 parse_json(response) 函数或 format_prompt(context) 辅助函数进行单元测试。这些代码在 Agent 代码库中仍然存在,也理应被测试。但 Agent 真正的智能——关于调用哪个工具、如何分解任务、何时寻求澄清的决策——都存在于模型内部。你无法注入一个模拟 LLM 并期待得到有意义的行为。模型本身就是逻辑。

部分团队尝试通过隔离测试提示词模板来绕过这个问题。这能发现明显的格式错误,但无法告诉你渲染后的提示词是否真的能产生预期的行为。"提示词编译无误"与"Agent 按我们的意图行事"之间的鸿沟,正是大多数 bug 的藏身之处。

集成测试变成了工具调用测试,而工具调用代价高昂

在普通服务中,集成测试因为要访问数据库而成本适中。对于 Agent 而言,每次集成测试都要调用模型(有时每轮次调用多次,跨越多个轮次),并调用真实或半真实的工具。单次集成测试运行可能消耗 0.100.10 到 1.00 的 API 费用,耗时 30 到 120 秒。一套 50 个集成测试的套件每次运行需要 55 到 50,并让 CI 阻塞 25 到 100 分钟。这样的经济账使得在每个 Pull Request 上运行成为不可能。

端到端测试耗时数分钟、花费数美元,但它们是唯一能捕获真实故障的测试

一个 Agent 完成一项真实任务——研究某个话题、执行多步骤编码工作流、或处理一个支持工单——可能需要发起 15 到 30 次模型调用、调用 5 到 10 个工具,并在每个阶段产生需要检查的中间产物。这不是一个 30 秒的测试。当它失败时,错误信息通常只是"Agent 未完成任务"——其原因可能是提示词有缺陷、工具接口发生变化、模型出现退化,或者是三步之前的某次提示词修改引发的微妙推理偏移。

关键在于,Agentic 系统的故障会复利叠加。一个 10 步任务的第 3 步出错,会污染此后的每一个步骤。等到最终断言触发时,根本原因已经深埋在一份可能长达数千 token 的记录中。

非确定性污染每一层

Anthropic 自己的评估研究发现,Agent 的单次运行成功率集中在 68% 到 74% 之间,而要求 Agent 连续成功 8 次,成功率则降至 52% 到 73%。这种差异代表了一个你没有做错任何事的系统中的自然方差——这正是概率系统的行为方式。一个 70% 概率通过的测试不是可靠的质量门禁,它只是披着 CI 徽章的噪声。

另一种思路:为 Agent 量身打造的三层体系

真正有效的方案是三层方法,用适合概率系统的成本/保真度层级替代原有的速度/隔离层级。

第一层:Prompt 契约测试(快速、廉价、确定性)

这一层测试 Agent 中具有确定性的部分:提示词组合、工具 Schema 定义、响应解析器、输入清洗器。"Prompt 快照"模式借鉴自视觉回归测试,将渲染后的提示词捕获为 JSON 产物,并与已提交的基准版本进行比对。如果一次代码变更改变了系统提示词的文本,快照差异会在任何模型被调用之前就将其捕获。

针对工具定义的 Prompt 契约测试可能会断言:search_web 工具的 JSON Schema 包含必填的 query 参数,其类型为 string,且没有未经文档记录的新参数被添加进来。这类测试在毫秒级别完成,在每次提交时运行,模型调用成本为零。

Prompt 快照测试专门用于捕获最常见的静默破坏模式:有人重构了提示词模板辅助函数,意外改变了指令措辞,进而改变了 Agent 的行为,而这一切直到两周后用户投诉时才被发现。

第二层:基于录制 Fixture 的工具交互测试(中等成本,受控保真度)

这一层大致对应集成测试,但关键的适配是工具录音带(tool tapes)——工具响应的录制 Fixture,类似于 VCR 风格测试中的 HTTP cassette。在 CI 中,Agent 不再调用真实的 web_search API 或 execute_code 沙箱,而是针对上一次会话的工具响应回放来运行。

工具交互测试要验证的是:给定这个初始状态和这些录制好的工具响应,Agent 是否以正确的顺序、用正确的参数调用了正确的工具?同时也验证错误处理分支:当 database_query 返回超时错误时,Agent 是进行指数退避重试,还是优雅地告知用户无法完成任务?

由于工具调用被模拟了,一套 30 到 50 个场景的测试套件在 10 分钟内即可完成,成本仅为生成 Agent 决策所需的模型推理费用。它们每晚运行一次,或在涉及 Agent 逻辑的 PR 时运行,而非每次提交都运行。工具录音带模式还解决了一个真实的调试问题:当测试失败时,你拥有 Agent 行为的完整录制记录——它错误调用了哪个工具、收到了什么响应——这比实时运行的混乱状态提供了清晰得多的失败信号。

第三层:目标完成测试(高成本,完整保真度)

这一层刻意保持规模较小:10 到 20 个场景,代表你最关键的工作流。它们在预发布环境中针对真实模型和真实工具运行,衡量任务完成率——Agent 是否真正完成了既定目标?——结合环境检查(文件是否被创建?数据库记录是否被更新?)以及针对无法通过编程验证的结果使用 LLM 作为评判者的评分标准。

与经典端到端测试相比,关键转变在于评分方式。目标完成测试不采用二元通过/失败的判断,而是跨多次运行产生统计信号。不再断言"这个测试通过了",而是断言"这个测试在 5 次运行中至少有 80% 的通过率"——即 Anthropic 评估框架所称的 pass@k 标准。这将内在的非确定性从测试负担转化为可管理的质量指标。

目标完成测试每晚运行一次,或在发布候选版本时运行,绝不在每个 PR 上运行。

各层级的 CI 基础设施模式

三层模型对应一套具体的 CI 流水线结构:

每次提交:Prompt 契约测试在 2 分钟内完成,无需模型调用,CI 环境中无需 API 密钥。这些测试是每次合并的门禁。

每个涉及 Agent 逻辑的 PR:工具交互测试针对录制 Fixture 运行,目标总时长在 10 分钟以内。这类测试需要模型 API 访问权限,但不需要真实工具。破坏工具交互测试的 PR 将被阻止合并。

每晚:目标完成测试针对真实基础设施运行,生成统计通过率报告,并在出现退化时发出告警。单次失败的运行不阻塞任何流程;通过率持续下降的趋势则触发评审。

发布前:针对所有支持场景运行完整的目标完成测试套件,以统计阈值(例如每个场景 5 次运行中 80% 的通过率)作为发布到生产环境前的硬性门禁。

这一结构确保了昂贵、缓慢、不稳定的测试能够存在,但不会阻碍日常工程效率。廉价、快速的测试为日常开发提供信心,而昂贵的测试则为发布提供信心。

传统测试无法发现的故障模式

有几类 Agent 故障对传统金字塔测试完全不可见:

轨迹漂移:Agent 通过错误的工具调用顺序得到了正确的最终答案——浪费了时间和金钱,或触发了意外的副作用。对最终输出的断言无法说明 Agent 是否调用了 12 次 read_file 而一次就够了,或者它是否在得出正确答案之前发出了一个具有意外副作用的 API 请求。只有轨迹评估才能捕获这类问题。

通过工具输出注入的 Prompt:网络搜索或代码执行返回的恶意字符串可以重定向 Agent 的行为。对提示词模板的传统单元测试永远无法发现这个问题,因为注入来自运行时数据,而非静态提示词。

复利推理错误:一个 10 步任务的第 3 步产生了微妙的错误中间结果。基于这个错误输入,第 4 到第 10 步都成功执行了。最终输出看起来合理,但实际上是错误的。单步评估永远不会触发警报;如果最终状态检查不够细粒度,端到端评估也可能无法发现它。

静默模型漂移:模型提供商悄悄更新了模型版本。Agent 的行为逐渐发生偏移。你的确定性测试无法捕获到这一点,因为它们不调用模型。只有生产监控或定期的完整套件运行才能检测到退化,而且往往是在它已经影响到用户之后。

工具 Schema 演进:你的 Agent 依赖的第三方工具改变了其参数名称或响应格式。你的 Prompt 契约测试通过了。你的工具交互测试也通过了(因为它们使用录制 Fixture)。故障只在目标完成测试或生产环境中才会浮现。这说明有必要定期加入至少几个使用真实外部依赖的实时工具集成测试。

成熟团队的实际做法

最成熟的团队以对待生产服务同等严格的态度对待 Agent 评估:版本化的提示词(提示词与渲染它们的代码一起存储在版本控制中)、CI 中的自动化质量门禁、将 1% 到 5% 流量路由到新 Agent 版本的灰度发布,以及指标下降时明确的回滚程序。

LangChain 自己的评估就绪框架建议,60% 到 80% 的评估精力应在自动化之前专注于错误分析——这是对传统方法的刻意颠覆。团队不应从自动化入手再调试失败,而应先手动审查 20 到 50 个真实的生产记录,建立故障类型分类体系,然后再构建针对这些具体故障模式的自动化测试。这使测试套件建立在已观测到的真实故障之上,而非假设性的故障。

OpenAI 在 2025 年初收购 promptfoo(价格为 8600 万美元,项目保留其开源 MIT 许可证)标志着这类工具已变得多么核心:Prompt 评估和回归测试现在是基础设施级别的需求,而非一个小众关注点。

Notion 工程团队报告称,在实施系统化的 Agent 评估后,其 AI 辅助问题解决率从每天 3 个修复增加到 30 个——10 倍的提升,归因不是更好的模型,而是测试与开发之间更好的反馈循环。

新的思维模型

经典测试金字塔是一种为优化两个属性而选择的形状:速度与信心。底部的廉价测试提供快速反馈,顶部的昂贵测试以可承受的成本提供系统信心。金字塔形状之所以有效,是因为成本与范围正相关。

对于 Agent 而言,成本与范围是解耦的。单步评估既不快也不便宜,因为它要调用模型。但对 10 步的轨迹评估并不比 2 步的评估贵出一个数量级——一旦你支付了模型调用的开销,成本曲线是次线性的。

正确的思维模型不是金字塔,而是成本-保真度坐标系。将测试沿两个轴分布:运行成本有多高,以及它们对真实 Agent 行为的还原程度有多高?你希望尽可能多地覆盖高保真区域,并尽量降低运行最频繁的低保真检查的成本。

Prompt 契约测试成本低、保真度低。基于 Fixture 的工具交互测试成本适中、保真度适中。目标完成测试成本高、保真度高。廉价的测试持续运行,适中的测试频繁运行,昂贵的测试有计划地运行。

目标不是颠覆金字塔,而是停止将一个概率性、多步骤、外部耦合的系统强行塞入一个为确定性、隔离函数所构建的框架中——转而构建真正契合问题本质的测试体系。

References:Let's stay in touch and Follow me for more thoughts and updates