跳到主要内容

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 是进行指数退避重试,还是优雅地告知用户无法完成任务?

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates