跳到主要内容

64 篇博文 含有标签「testing」

查看所有标签

确定性种子:为什么供应商将其视为“提示”而非“契约”

· 阅读需 12 分钟
Tian Pan
Software Engineer

CI 测试只有一个断言:相同的模型、相同的温度、相同的提示词、相同的种子(seed)、相同的输出字符串。它在每个开发者的笔记本电脑上都通过了,在前一百次 CI 运行中也通过了,但在三周内每五十次运行就会出现一次随机失败(flake),直到最后有人承认这种模式是真实存在的。第一个假设是显而易见的——测试工具中某处存在非确定性依赖——三天的调查却一无所获。实际原因隐藏在供应商 API 参考文档的一个脚注中:“seed 提供尽力而为的确定性。”团队读到了参数名称,并将其视为一种契约。而供应商记录的只是一个提示。

这是托管推理的一种特定失败模式,它困扰着那些围绕单一心智模型设计测试基础设施的团队:模型是其输入的纯函数,而 seed 是使函数具有可重现性的关键。在生产环境中,这个模型的这两个部分都是错误的。API 表面与底层物理原理之间的差距如此之大,以至于团队在供应商明确否认的假设之上,构建了整个评估和回归测试栈。

为什么你的智能体在开发中表现完美,在生产中却状况百出

· 阅读需 12 分钟
Tian Pan
Software Engineer

Agent 演示总是能成功。数据库里有三个客户,一个匹配记录,向量索引中有 12 篇文档,一个带有无限空档的空日历。Agent 选对行,检索到正确的文档,预订好正确的会议。上线吧。

接着,生产环境交给了同一个 Agent 一千万个客户,其中在同一个城市有三个 “John Smith”;一个返回了四千行的过滤器,因为 Agent 本想表达 status = 'active' 时却自信地写成了 status != 'closed';一个向量查询返回了七篇看似合理的文档,而 Agent 从未被要求在这几篇文档之间做选择;以及一个每个空档都需要协商的日历。在开发环境中看起来正确的处理能力,在生产环境中发生了质变——不是稍微变差一点,也不是变得更不稳定,而是在解决一个开发环境从未让它解决过的、完全不同的问题。

这就是“在本地运行正常”所掩盖的鸿沟。对于确定性代码,这句话在处理边缘案例时已经算是个谎言。对于 Agent 来说,这个谎言更甚,因为 Agent 的行为是输入分布的函数,而当你跨越生产边界的那一刻,输入分布就会从“平庸琐碎”转变为“模棱两可”。

你从未注入过的故障:给你的 Agent 提供一个说谎的工具

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开你的智能体(agent)韧性测试套件,看看它实际上在测试什么。你会发现超时。你会发现连接中断、500 错误、频率限制响应、格式错误的 JSON,也许还有一个在失败前卡死三十秒的工具。所有这些都是经典模式下的故障注入:工具坏了,问题在于你的智能体是否能优雅地降级。

现在找找看那个工具完全没坏的测试。那个工具在 80 毫秒内响应,返回了完全符合 schema 的有效 JSON,但里面的值纯粹是错的。一个过期了三天的余额。一个交换了两个字段的客户记录。一个两位数移位的订单数量。一个本应返回四十行却返回空的查询结果列表。

你找不到它。几乎没有人注入过这种故障。而这正是你的智能体最无法抵御的故障,因为所有其他故障都会自我宣告,而这种故障不会。

那些在你没留意时变简单的评估集

· 阅读需 10 分钟
Tian Pan
Software Engineer

你在 18 个月前编写了这套评估集(eval set)。那时它是一个非常有用的工具:低价模型的得分是 71%,更好的模型得分是 84%,而当出现回归(regression)时,分数会下降并被察觉。这套测试套件在 CI 中赢得了一席之地。于是你不再关注它了。

今天再运行它,每个候选模型的得分都是 96、97、98。新版本的得分与旧版本相同。你怀疑表现较差的模型与你认为更好的模型得分也一样。仪表盘上的数字依然显示为绿色,检查依然通过,但它实际上什么也没告诉你。你的评估集并没有坏。它只是变简单了——因为底层的模型变强了——而没人在意它失去区分度的那个瞬间。

这就是评估饱和(eval saturation),这不仅是你可能遇到的失效模式,更是任何静态测试套件在足够长的时间跨度下必然走向的终局。一个所有模型都能通过的测试,已经不再是测试了。

Eval 测试集是滞后指标:你的绿色仪表盘只反映上季度的失败

· 阅读需 9 分钟
Tian Pan
Software Engineer

每一个成熟的 AI 团队构建其评估套件的方式都如出一辙,而且几乎没有人会公开说出那个潜台词。生产环境中出现了一个故障。有人写了一份复盘报告。一名工程师将该事故提炼为一个测试用例,将其添加到评估套件中,于是仪表盘再次变绿。重复这个循环一年,你就会拥有几百个案例、一个令人满意的通过率,以及一个足以让你在演示幻灯片上感到无比安心的数字。

潜台词是:那个评估套件其实是一个博物馆。每一件展品都是团队已经挺过来的故障类别。98% 的通过率证明了你的系统可以抵御过去 —— 抵御那些已经发生过的特定破坏方式 —— 而对于模型迁移、提示词编辑或用户行为转变即将引入的新型故障模式,它几乎给不出任何参考。评估集是一个披着先行指标外衣的滞后指标。

Happy Path 是你的 Agent 评估测试过的唯一路径

· 阅读需 11 分钟
Tian Pan
Software Engineer

看看大多数智能体(Agent)评测集是从哪里来的。有人构建了智能体,向团队演示,演示成功了,于是演示脚本就变成了评测套件。那些通过评审的案例,正是有人已经亲眼看到它们运行成功的案例。评测集在构建之初,几乎就是“快乐路径”(Happy path)的录音——即在截屏当天成功运行的那一段工具调用序列。

所以,当仪表盘显示智能体得分为 94% 时,它实际上是在说:它通过了我们能想象到的案例。它完全没有提及搜索 API 在多步计划中途返回 429 错误的情况,或者用户推翻了两轮前设定的约束的情况,亦或是检索结果为空,智能体必须在胡乱猜测和承认不知道之间做出选择的情况。这些情况并非没有通过你的评测。它们压根就没在评测里。

这就是黄金路径偏见(Golden-path bias),除非你刻意对抗,否则它就是智能体评测套件的默认形态。解决方法不是增加案例数量,而是增加不同种类的案例——这些案例应根据失败模式(Failure mode)来选择,从生产环境中收集,并针对刻意引入的故障进行压力测试。

那个由智能体编写的、实际上什么也没测的测试

· 阅读需 11 分钟
Tian Pan
Software Engineer

让一个编程智能体 (AI agent) “为这个模块添加测试”,你会得到测试。它们格式整齐,遵循你的项目规范,而且能够通过。覆盖率会上升。这个 PR 看起来非常尽职。然而,这些测试中很大一部分根本无法捕捉到你可能引入的任何 Bug。

这并不是一个关于模型太蠢的故事。智能体完全按照要求完成了任务。问题在于,“添加测试”和“添加能约束行为的测试”是不同的请求,而其中只有一个是能被一眼验证的。无论是真正的断言还是同义反复(tautology),绿色的对勾看起来都一模一样。

结果就是,测试套件的代码行数在增加,但效能却在萎缩。你最终得到了更多的文件、更多的 CI 耗时、更多的维护成本——而交付回归缺陷的概率却与开始前几乎无异。

悄然失效的评估:当你的测试套件在衡量一个已不存在的世界

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的评测套件通过了。240 个案例全是绿色,和上周一样。你发布了代码。两天后,支持工单激增。当你阅读对话记录时,你发现了一种你的套件完全没有立场的失败模式——不是某个案例从通过变成了失败,而是用户开始问一些你的套件从未想到过要去问的问题。

这就是评测(evals)的无声失败。我们将“全绿”视作对现状的肯定:“系统运行正常”。实际上,它只是对过去的一种陈述——即编写这些评测案例的那一刻。六个月前编写的评测编码了当时的三样东西:产品的范围、模型的失败模式,以及真实用户表达请求的方式。而这三者都在变化。功能增加了新的界面,模型升级了两次。随着用户了解产品的功能,输入分布也发生了漂移。套件没有随之移动,因此全绿的运行结果越来越只是在证明一个不再存在的世界。

没有人注意到,因为没有东西崩溃。过时的评测不会报错。它会继续自信地通过,但衡量的关键内容却越来越少。

删除评估用例是决策,而非清理

· 阅读需 11 分钟
Tian Pan
Software Engineer

每个评测套件(eval suite)最终都会被精简。有人注意到套件运行需要 9 分钟,每次运行成本 40 美元,而且里面充满了没人记得为什么要写的用例。他们提交了一个名为 “清理陈旧评测用例” 的 PR,删除了 40 条 “看起来不再相关” 的条目,CI 运行时间降到了 4 分钟。PR 获得了点赞。没人反对,因为删除测试看起来就像是在做维护。

这不是维护。每一个评测用例都是团队对自己做出的承诺:这种失败模式不会再静默地发生。 删除用例就意味着撤销了这项保证。通过率没有变化,仪表板依然是绿色的,唯一消失的是团队对这项保证曾经存在过的记忆。六个月后,一次模型迁移重新引入了被删除用例所防范的回归,复盘(postmortem)重新发现了团队已经支付过代价的教训,然后有人写道 “我们应该为此添加一个测试” —— 而这个测试正是之前在清理 PR 中被删除的那个。

Eval 回填税:为什么每一次模型能力发布成本都超出了你的预算

· 阅读需 11 分钟
Tian Pan
Software Engineer

一名高管发了一封只有一行字的邮件:“好消息——我们在下个冲刺周增加视觉能力。”产品经理将其解读为一星期的工作量:更换模型、开放图像参数、发布。评估(Eval)团队读了同样的邮件,脑子里已经开始起草一份尚未获批的四周计划。到了周五,这种认知脱节在站会上表现为一句含糊的“我们需要做一些评估工作”,然后大家一致同意以后再解决。

这种在“我们添加了视觉能力”与“我们可以安全发布视觉能力”之间的鸿沟,就是评估补填税(Eval Backfill Tax)。每当新的模型能力落地时——多模态输入、工具使用、更长上下文、推理轨迹、电脑使用——这项工作就会悄无声息地落在评估团队身上。因为历史测试案例是在一个模型不会以这些新方式失败的体系下构建的。测试套件依然显示绿色,头条基准测试分数在上升,但生产环境的发布却暴露出了没人写过测试的失效模式。

快照评估衰减:当绿色的 CI 不再意味着你的产品仍然可用

· 阅读需 12 分钟
Tian Pan
Software Engineer

六个月的绿色 CI 掩盖了一个事实:大约 40% 的评估集(eval set)已不再代表用户在产品中的实际行为。测试套件仍在运行,裁判(judge)仍在打分,仪表盘依然闪烁着绿光。但这些案例是针对查询分布、语料库、工具界面和监管文本编写的,而这些内容早已发生了变化——现在的绿色运行意味着“昨天的产品在昨天的现实中依然有效”,而这并不是你付费让 CI 回答的问题。

这就是“快照评估退化”(snapshot eval decay),它是 AI 评估中最缓慢、最昂贵的失败模式。说它缓慢,是因为套件从未失败——陈旧性表现为无法区分模型优劣,而不是构建变红。说它昂贵,是因为当有人意识到评估通过的模型切换导致了生产环境回归时,团队已经建立了一年之久的“评估通过即发布”的肌肉记忆,而这一记忆是建立在一个早已悄然失效的资产之上的。

Agent 分支覆盖率:你的评测仅命中了 Happy Path,而非 Planner 的 If-Else 逻辑

· 阅读需 9 分钟
Tian Pan
Software Engineer

我上季度合作的一个团队针对其支持智能体(support agent)运行了一套包含 240 个案例的评估集。连续六个月,测试结果全线飘绿。接着,他们更换了规划器提示词(planner prompt)中的一个句子——仅仅是一次语气调整——结果第二天生产环境的人工接管请求激增了 3 倍。而评估分数却纹丝不动。人工接管分支仅仅是开始在以往能在线解决的临界案例上触发,而评估集中没有一个案例属于这种临界类型。该分支存在于提示词中,存在于生产环境中,唯独不存在于评估集中。

这就是我想命名的失败模式:智能体分支覆盖率 (agent branch coverage)。代码覆盖率工具在过去的 40 年里一直是调试的基础,但智能体系统具有运行时控制流——规划器分支会选择工具、限定回复条件、升级到人工、拒绝执行、或尝试不同的策略重试——而评估集仅触及团队想到的那些案例。规划器 80% 的决策分支从未在测试下执行,于是,一份“全绿”的评估报告就成了一场披着回归测试外衣的冒烟测试。