跳到主要内容

评估集拥挤问题:为什么更大的测试套件捕获的回归反而更少

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 AI 评估测试集(eval suite)有 800 个测试用例。你又增加了 200 个。现在你的模型在评估中得分 94%,你满怀信心地发布了。三天后,一名用户发现了一个回归(regression)问题,而你那 1000 个测试用例中没有一个捕获到它。

这不是运气不好 —— 而是结构性问题。回归问题的存在恰恰是因为你扩充测试集的方式,而不是尽管你扩充了测试集才存在。当出现故障时增加更多评估指标(evals)的本能在理论上是正确的,但在实践中却适得其反。更多的测试并不自动意味着对重要事项的覆盖率更高。它们意味着对那些易于测试的事项有了更好的覆盖,而这完全是两回事。

评估测试集如何偏离生产环境的现实

失效模式始于激励机制。当一个 AI 功能发布并出现 Bug 时,最直接的反应是增加一个覆盖该特定输入的测试用例。当增加新能力时,你会为常规路径(happy path)和少数边缘案例(edge cases)编写评估。六个月后,测试集增长到数百个案例 —— 每个案例的加入在局部看都是合理的,但整体上却偏离了生产环境中真正重要的失效分布。

三种力量驱动了这种偏离:

自动化引力 (Automation gravity)。 能够自动评分的测试 —— 如精确匹配比较、代码执行结果、Schema 验证 —— 运行和维护成本都很低。而需要人工判断质量、语气或有用性的测试则非常昂贵。随着时间的推移,团队会下意识地针对可自动化的内容进行优化。评估集里充满了容易评分的案例,而不是难以做对的案例。

边缘案例堆积 (Edge case accumulation)。 工程师受过的训练是进行对抗性思考。他们寻找极端情况、边界条件和失效模式,然后为其编写测试。这些案例虽然真实但很罕见。它们在评估集中堆积,而最常见的用户路径 —— 尽管更可预测、测试起来不那么令人兴奋 —— 在每个失效模式下分配到的案例反而较少。

覆盖率剧场 (Coverage theater)。 评估测试集通常以数量来汇报。一个拥有 2000 个评估用例的团队听起来比只有 200 个的团队更严谨。这产生了一种压力,使人们将扩大测试集规模作为严谨性的代名词,而不考虑新案例是否真正能预测生产环境中的失败。

结果是,当你增加用例时,评估测试集在每一项指标上都在提升,但它预测发布是否会导致用户可见的回归的能力却停滞不前甚至下降。

每个测试用例的预期缺陷检测价值

每个评估项都有一个隐含的预期缺陷检测价值 (EDDV) —— 粗略来说,就是运行此测试捕获到原本会流入生产环境的故障的概率。大多数团队从不计算这个数值,但当你询问以下问题时,结构就变得清晰了:在用户报告的最近十个 Bug 中,有多少能被你当前的评估集捕获?

对于大多数团队来说,答案是十个中有两三个。其余的都发生在测试之间的缝隙中 —— 不是因为测试本身错了,而是因为测试分布与生产环境的输入分布不匹配。

测试集规模与 EDDV 之间的关系遵循一条熟悉的曲线。前 50 个设计良好的测试用例提供了巨大的信号。每个用例都覆盖了一个真正独特的失效模式。接下来的 50 个增加的价值较少。当你增加到数百个测试用例时,每个新用例通常要么是重复覆盖了已经存在的失效模式,要么是覆盖了一个极少发生到无关紧要的边缘案例,或者是抓取了一个真实用户根本不会生成的对抗性输入。

综合效应是,测试集总体的 EDDV 呈次线性增长,而维护成本则呈线性增长。一个包含 1000 个案例的测试集其价值并不是 100 个案例测试集的十倍。它的价值可能只有两到三倍,但维护、运行和解释的成本却是五倍。

AI 基准测试(benchmarks)的饱和时间线说明了这一点。MNIST 和 Switchboard 花了数十年才达到饱和。GLUE 在发布后两年内就饱和了。专门设计用来抵抗饱和的基准测试 —— 由困难的专家级问题构建 —— 随着前沿模型的改进,在 15 个月内就会趋于饱和。每个基准测试都遵循同样的轨迹:早期信号强,随着测试集老化并成为优化目标,噪声和刷分(gaming)随之而来。

古德哈特定律不是隐喻,而是一种机制

当你的评估集成为发布的主要质量关卡时,它就变成了一个目标。当一个指标变成目标时,它就不再是衡量你所关心的底层质量的好指标了。

这在 AI 系统中通过四种截然不同的方式体现出来:

无能力提升的刷分行为 (Score gaming without capability gain)。 模型可以通过提示词格式化、少样本示例(few-shot examples)、温度调节和集成投票来提高基准测试得分 —— 而这些都不会改变底层能力。针对评估集优化模型配置的团队虽然获得了分数提升,但并不能转化为用户满意度。

数据污染 (Data contamination)。 评估数据集与预训练数据的重合率,团队很少去测量。当模型在训练期间遇到过与评估类似的示例时,它在这些评估上的表现反映的是记忆而非泛化。这是一个程度问题,而不是非黑即白 —— 即使是部分污染也会系统性地夸大相对于生产环境表现的基准测试得分。

结构性过拟合 (Structural overfitting)。 当模型根据在评估集中得分较高的输出进行微调时,它会针对你的评估分布进行优化,而这只是实际用户输入分布的一个子集。微调后的模型在评估中表现更好,但在评估未覆盖的长尾真实查询中表现可能更差。

评审者锚定 (Reviewer anchoring)。 审查模型输出的人类评估员会随着时间的推移根据他们见过的输出进行校准。几个月后,他们变得更擅长识别那些在他们看来“不错”的输出,而这又与现有测试集中得分较高的输出相关。不符合过去失效模式的新失效模式得到的评价往往比应有的评价更宽容。

实际后果是:实验室基准测试分数与实际部署表现之间通常存在 37% 的平均差距,这已普遍到足以被视为基线预期。评估集的提升是必要的,但不足以证明生产环境的质量也得到了提升。

剪裁评估集的强制排序法

解决方法不是停止增加测试,而是要将你的评估集视为一个容量有限的投资组合,并强迫每一个用例都必须凭实力赢得自己的席位。

从生产环境故障开始,而不是从覆盖率开始。 在构建或审计评估集时,第一个问题不应该是“我们应该测试哪些输入?”,而是“生产环境中到底发生了什么故障?”真实的用户报告、监控告警和 A/B 测试的性能退化是关于故障模式最真实(ground-truth)的信号。从结构上看,源自真实生产环境故障的评估用例比人工构建的合成边缘用例具有更高的 EDDV。

在规模化之前,验证指标与结果的相关性。 对于你用来给评估打分的每一个指标,都要验证该指标的提升是否与生产环境 KPI 的提升(如用户满意度、任务完成率、单次推理成本)相关。这种相关性检查是大多数团队都会跳过的步骤。一个与生产结果不相关的指标,无论有多少用例在使用它,都无法捕捉到生产环境的回归。校准的目标是使评估得分与真实生产质量信号之间的误报率和漏报率保持在较低水平。

按辨别力排序,而不是按新旧程度排序。 根据评估用例在不同模型版本之间的辨别频率进行排序——如果一个用例每个版本都能通过,那么它就无法提供任何有效信号。根据该用例是否能捕捉到最近的生产故障进行排序。不符合这两个标准的用例都应该被淘汰。这可能会让人感到不安,因为这意味着要删除测试,感觉像是在降低覆盖率。其实不然:这是在用“预测力”取代“覆盖率剧场”。

限制并强制执行评估集规模。 设定一个明确的上限——比如 200 个用例——并规定增加一个新用例就必须淘汰一个旧用例。这会迫使团队在哪些用例最具预测性上做出明确的权衡,而不是将评估集视为一个不断增长、仅供追加的日志。当评估集规模不受限制时,用例的平均 EDDV 会单调递减。而当规模受限时,新增用例必须证明自己比现有用例更有价值。

区分“饱和”与“通过”。 模型总是能通过某个测试用例,并不代表模型已经掌握了这项能力。这可能意味着该用例已经“饱和”——它不再能区分模型版本的优劣。定期阅读智能体对话记录(transcripts)。当一个用例不再产生有意义的差异时,请将其淘汰,或用更高难度的同类能力测试取而代之。

评估集是一个生命系统,而非账本

更深层的问题在于,大多数团队将评估集视为一个不断累积测试用例的账本。每增加一个测试用例都是一种承诺,而移除一个用例感觉就像是在削弱严谨性。这种想法是本末倒置的。

一个不加剪裁而任其增长的评估集,是一个缺乏负反馈的系统。其信噪比会随着时间的推移而降低。曾经具有辨别力的用例会变得饱和,新用例的增加速度超过了旧用例的淘汰速度。最终,维护这套评估集所需的工作量将超出小团队的承受能力,但移除用例的负担——即必须解释为什么要“降低安全性”——又阻碍了必要的剪裁。

强制性的准则是:如果你无法针对某个评估用例回答“这个测试能捕捉到哪种生产环境故障?”,那么该用例就应该待在暂存池(staging pool)中,而不是活跃评估集里。如果发生了一个该用例能够检测到的生产故障,它可以被晋升。在此之前,它只是对故障模式的推测,而非证据。

将评估设计视为一种持续的审计——而非“构建后即焚”的资产——会改变其经济效益。活跃评估集保持精简、运行迅速且具备预测校准能力。暂存池则存放等待验证的实验性用例。当用例证明了其辨别力时,它们从暂存池晋升到活跃集;当它们饱和时,则从活跃集退休。

这确实比单纯地追加用例要费工,但比起去调试那些由 1,000 个用例组成的评估集信誓旦旦保证没问题、结果却在生产环境发生回归的故障,这点工作量显然要小得多。

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