测试金字塔是软件工程里最经典的心智模型之一:底层是又快又便宜的单元测试,中层是服务层测试,顶层是慢但覆盖完整链路的 UI 端到端测试。但当你开始给应用接入大模型(LLM,即通过海量数据训练出来的、能理解并生成自然语言的模型),这个金字塔就裂开了——因为 LLM 推理(模型根据输入生成输出的过程)既慢又贵,但它调用起来又像 API 一样,这导致一个诡异的现象:服务层测试可能比 UI 测试更慢、更烧钱。
作者用一家披萨店的例子把问题讲得很具体。Archibald's Pizzeria 刚花了几千美元引入企业级供应商,除了网站和 App 下单,顾客还能打电话给一个叫 Archie 的聊天机器人接待员来订餐。现在有三个测试用例:用 Playwright(一个自动化浏览器操作工具)打开网页填表下单;拨打电话说“我要一份加双份芝士的意大利辣香肠披萨”;直接调用 agent(智能体,能自主完成任务的程序)处理文本输入的内部 API,把同样的话作为字符串传进去。第一个是标准的 UI 端到端测试,放金字塔顶端没问题。第二个也应该放顶端——电话连接就是语音 agent 的“UI”,想端到端测它只能真打电话跟它聊。麻烦的是第三个。它是个 API 测试,绕开了 UI,按理该放金字塔中间,但因为它会打到 LLM,大多数情况下比第一个还慢还贵。
于是作者把金字塔改了一下:LLM 和 UI 一样慢,但你像调 API 一样调用它并断言输出,所以把它放在 UI 和服务层之间。这样中间层就被劈成两半:走 LLM 的测试和不走 LLM 的测试。不走 LLM 就得 mock(模拟,用假实现替换真实依赖)掉 LLM。好消息是 mock 技术上不难——推理模型存在的意义就是猜用户想要什么,而自动化测试想要什么我们早就知道了。还是披萨的例子,如果店里只卖两种披萨,mock LLM 就是用户意图到工具调用的简单映射:输入里含 pepperoni 就调 orderPepperoni,含 hawaiian 就调 orderHawaiian。坏消息是,这是纯技术债。菜单一变就得改,更别说 agent 的功能行为变了。而且真实 agent 的推理决策会引出分支决策,分支又引出更多推理决策,mock LLM 最后会变成传统 IVR(交互式语音应答,就是电话里那套按键菜单)对话脚本树——而这恰恰是 AI 本该取代的东西。
那怎么办?作者的答案很干脆:用 LLM 来编排测试调用并评判结果。推理的定义就是模型负责搞清用户想干什么,那么“用户想要什么”本身就是测试用例。用 LLM 测你的 LLM,就能写出这样的测试:callArchie("你是 John Smith,住 Main St 1234 号,想点一个意大利辣香肠披萨。验证 agent 确认了你的选择、告诉你价格、记得收销售税、并在挂断前感谢你。")。这个测试零技术债。换 IVA 供应商、换 LLM 模型、把整个技术栈从 Java 重写成 C# 再重写回 Java,这个测试都原样成立。要付出的代价是那个 callArchie 函数本身——它不简单但绝对做得出来。它需要编排你的 agent 和另一个模型(或同一个模型用不同 prompt)之间的多轮对话,然后把对话记录交给 LLM-as-judge(用 LLM 当裁判,让模型评判另一个模型输出好坏)来评估。脚本本身可能一次就能写出来,但 prompt 的调优得准备好花一下午。
回到金字塔。中间层被拆成“mock LLM”和“调用 LLM”两类后,怎么决定测试放哪?作者的建议是把每个测试看作维护成本和执行成本之间的权衡。对老派 SDET(软件测试开发工程师)来说,跑一次要花一美元的 API 测试套件听起来贵得离谱,但技术债也贵——如果 mock LLM 每月要花一小时跟应用功能行为保持同步,而测试一周才跑几次,那 mock 可能根本不值。
关于端到端测试还有个补充:如果你已经建好了 LLM-as-judge 服务层测试,那通过电话线跑完全相同的测试,就能得到真正的端到端测试。具体怎么做、多难,完全取决于你的语音平台暴露了什么。如果平台有走真实通话的测试路由,用就是了,但要确认它是真测试——搞清楚哪些场景下即使电话 agent 坏了测试也能通过。如果平台要求你建一个外呼 agent 来测呼入 agent,而你本来不用外呼 agent,那就要掂量一下这个 vendor lock-in(供应商锁定,被某家厂商的技术绑住难以迁移)值不值。如果必须自己搭,先仔细评估范围——如果编码 agent 让你把语音转文字和文字转语音模型接到 LLM 上,想想测试 harness(测试框架)要跑多少带宽。而且立刻开始走供应商审批流程,这步可能比写代码还慢,电信供应商要处理海量欺诈,得有人刷脸刷身份证,法务可能还不喜欢他们的条款。
作者最后给了个判断框架:LLM 算 UI 层还是服务层,完全取决于 mock 它的难易程度,以及不经过它能否测好服务层。如果你愿意付 mock LLM 的前期和持续成本,那就几乎所有测试都用它,之后可能根本不需要服务层 LLM 测试了,端到端测试已经覆盖了 LLM 路径。如果你不想维护 mock LLM,打算写调用 LLM 的 API 测试,那不如多调几次,把 LLM-as-judge 的好处全拿到——最大的好处就是测试用例写起来维护起来都极其轻松。这个思路对所有接入了 LLM 的应用都适用:与其费劲 mock 掉模型,不如把模型本身变成测试基础设施的一部分。真正的坑在于别把 mock 做成第二个 IVR 树,也别低估 LLM-as-judge 的 prompt 调优时间。最让我意外的是作者对技术债的判断——mock LLM 看似省了执行成本,但维护成本可能悄悄吃掉所有收益,这个权衡在项目初期特别容易被忽略。

内容与图片版权归原作者所有 · 原文: https://dev.to/ineptech/where-does-the-llm-go-in-the-testing-pyramid-1e4j