跳到主要内容

Eval 差异分析作为分支保护:交付分数变化,而非分数下限

· 阅读需 11 分钟
Tian Pan
Software Engineer

我曾合作过的一个团队拥有一套看起来很清爽的评估门禁(eval gate):每个 prompt PR 都必须在黄金测试集(golden set)上获得 0.85 以上的评分,否则合并按钮就会保持灰色。他们为此感到自豪。但在六周后,平均质量已从 0.93 悄然滑落至 0.87 —— 每个 PR 都通过了门槛,每个 PR 都成功上线,而且没有任何一个改动需要为这种质量回退负责,因为它们都没有违反规则。这个门槛是根据上个季度的质量快照设定的,而不是根据上周的质量。

这就是绝对阈值评估门禁的失效模式:一个将评分从 0.92 降低到 0.86 的 PR 可以绿灯通过,而一个将评分从 0.80 提升到 0.84 的 PR 却会被挡在门外。团队学到的是“只要过线就能发布” —— 这是一个关于质量的故事。但你真正需要的信号是“如果这个改动在重要的切片(slices)上没有发生回退就发布” —— 这是一个关于回退检测的故事。

测试覆盖率工具在十年前就解决了这个问题。它们报告相对于父提交(parent commit)的差异,并将其细化到每个文件。评估门禁还没赶上这个进度。

得分底线是过时的门禁

得分底线通常在 AI 功能上线冲刺期间被写入 CI 流水线一次,然后大约在十分钟后就停止重新校准了。当模型处于 0.88 时合理的数字,在模型达到 0.94 时看起来依然合理 —— 但事实并非如此,因为 0.85 的底线现在允许 9 个点的质量回退在悄无声息中发生。

更深层的问题在于团队从门禁中学到了什么。底线教育的是“这个 PR 质量合格了吗”这样一个“是/否”问题。而差异(diff)教育的是“这个 PR 是否改变了质量,在哪个切片上,向哪个方向改变”。前者的框架是为“过线”而优化;后者的框架是为“不让情况变糟”而优化。这是不同的文化默认设置,并会体现在代码审查中。审查者不再询问“得分下降了吗?”,因为绿色的勾号已经替他们回答了 —— 即使这个勾号仅仅确认了“仍然高于 0.85”。

你有时可以通过在每次发布后提高底线、使其向当前得分靠拢来修补这个问题。但这比听起来更糟糕。现在,你已经将门槛与上周评估运行的噪声底线耦合在了一起。一旦某个 PR 触及样本量(N)较小且方差较高的切片,它就会产生误报性质的失败,团队为了解锁会降低阈值,于是你教会了所有人:评估门禁是可以讨价还价的筹码,而不是可以信任的准则。

差异是更小、更诚实的声明

你真正想要的契约更加狭窄:“除了噪声范围外,这个 PR 在重要的切片上没有发生回退。”而不是“这个 PR 是高质量的”。“高质量”是一个发布就绪性问题,而不是一个针对每个 PR 的问题。在一周内针对同一个黄金测试集询问 40 次这个问题是错误的。

具体来说,具备基准意识(baseline-aware)的评估所报告的信号,是相对于父提交(或主分支上一个绿灯提交)的每个切片的得分增量,并同时显示噪声范围。审查者在阅读 PR 时会看到:“意图分类:−0.03(在噪声范围内),引用准确率:−0.08(回退),拒答率:+0.02(改进)”。他们可以针对每一行独立采取行动。总分可能仍然高于旧的底线,但引用准确率切片已经崩盘,而门禁捕捉到了这一点。

这种框架还修复了底线处理改进时的不对称性。一个将处于困境的切片从 0.62 提升到 0.71 的 PR 是一次有意义的胜利,但全局底线看不见它 —— 总分几乎没有变化。而差异视图将其展示为急需帮助的切片上的明确增量,审查者可以据此给予相应的认可。

切片级的不回退胜过全局聚合

全局聚合的评估得分隐藏了你最想看到的回退。全局平均分下降 2 个点,可能掩盖了某个单一类别的 15 个点崩盘,尽管该类别的样本量较小,但其面向用户的严重程度却很高 —— 比如那些每天导致用户流失十次的失败长尾意图。

在你进行切片分析之前, PR 的得分差异看起来可能并无大碍。这里的纪律是像定义测试文件一样定义切片:显式定义、成员稳定,并且有明确的所有权归属。有用的切片轴包括:意图或任务类型、语言或区域、输入长度区间、客户分级,以及“这个问题之前是否是 Bug”。

应该放入门禁的规则不是“全局平均分下降不得超过 X”,而是“任何切片的得分回退不得超过其噪声范围”。这条规则会在回退影响最大的类别上快速报错,而且不会因为某个 PR 对其从未触及的切片保持中立而误罚。

切片所有权之所以重要,是因为切片会碎片化。一旦评估套件拥有 20 个切片,就会有人开始询问为什么切片 14 在每个 PR 上都失败,而答案通常是“切片 14 只有 9 个样本,任何噪声看起来都像回退”。这是一个切片设计问题,而不是门禁问题 —— 但团队会通过放宽门禁来解决它,这会破坏其他所有地方的信号。切片的所有者也应该负责其样本数量、标注质量和噪声预算。

抖动预算区分噪声与信号

评估套件不是确定性的。采样温度、裁判模型方差以及小样本 (small-N) 分片都会产生运行间的波动,这会误触发幼稚的非回归规则。针对噪声触发的门控会被禁用,因此噪声预算必须作为设计的核心组成部分。

最简洁的方法是在发布门控之前刻画每个分片的噪声区间。针对同一提示词运行评估套件 N 次,计算每个分片的标准差,并将 ±2σ(或你想要的任何置信水平)范围内的任何增量视为抖动而非信号。样本较多的分片区间更窄;样本较少的分片区间更宽,这正是正确的行为——一个小样本分片告诉你它可能发生了回归,这需要更大的波动才值得被相信。

这为你免费带来了一个额外的洞察:具有荒谬噪声区间的分片太小,不适合用于门控。将它们提升为“仅供参考”,直到样本数量增加。噪声区间会告诉你哪些分片在门控中起承重作用,哪些只是装饰性的。

抖动预算还澄清了 PR 失败时该怎么做。如果回归是在小样本分片的噪声区间内,正确的做法是重新运行,而不是调查。如果回归在区间之外,或者虽然在区间内但在多次运行中表现一致,正确的做法是调查。这两者都不是“降低阈值”。

PR 评论才是真正的产品

Diff、分片和噪声预算的存在都是为了产生一个产物:一条审阅者可以在 20 秒内读完并采取行动的 PR 评论。覆盖率工具完美地实现了这种用户体验——Codecov 评论会显示补丁覆盖率、文件级 Diff 以及与基准的对比,并将需要注意的事项置顶。

评估 Diff 的 PR 评论也应该做类似的工作。首先列出回归超出其噪声区间的分片。显示改进超出其噪声区间的分片。将剩下的归为“无显著变化”。将每个分片行链接到回归示例的样本中,因为在问过“它回归了吗”之后,问题总是“给我看哪里坏了”。如果评论需要审阅者点击三个仪表板才能找到答案,它就会输给“lgtm,平均值还可以”。

一些具体的细节使这种评论在实践中值得信赖。与同分支上的父提交对比,而不是与最新的 main 分支对比,可以防止无关合并产生的噪声渗入 Diff。在评论页眉中锁定评估套件版本、裁判模型版本和温度,可以使结果可复现——并在其中任何一项发生变化时引发显而易见的问题。包含一个小的“重新运行此分片”按钮(或其 CLI 等效项)为审阅者提供了一条处理疑似抖动的路径,而无需禁用门控。这些都不算高明;它们是测试运行器 UI 在多年前就已经趋同的便利功能。

一次不会搞砸团队的迁移

大多数团队已经拥有一个无法直接移除的绝对阈值门控,因为该门控已植入分支保护规则和几个月的肌肉记忆中。更安全的迁移是让两个门控并行运行。将底线作为软警报——一个不阻塞的红色状态检查——并引入 Diff 作为新的阻塞门控。经过几周的数据积累,你会看到 Diff 是否捕获了底线漏掉的东西(确实如此),以及底线是否捕获了 Diff 没发现的东西(主要是:你需要重新校准 Diff 噪声区间的情况)。

在此期间,配置评论显示但不强制执行。在任何检查变红之前,让审阅者观察两个冲刺的分片 Diff。这段配置期是你发现其中三个分片的噪声区间不可用、其中一个实际上是披着大衣的两个分片,以及在这一切奏效之前裁判模型需要锁定版本的时期。在阻塞门控下发现这些问题都不会太体面。

最终状态并非“到处都没有阈值”。一些绝对阈值仍然有其价值——拒绝率、高严重性分片的幻觉率、延迟 p95。这些是面向用户的契约,而不是质量得分,底线是适合它们的形式。其他所有内容——汇总质量得分、每个任务的准确率数字、评分标准平均值——都应该使用 Diff。

切换后的预期

一旦团队开始发布 Diff 而不是底线,三件事会发生变化。首先,PR 以正确的方式变得更加谨慎:原本会将五个提示词修改打包进一个 PR 的作者现在会拆分它们,因为 Diff 让哪次修改移动了哪个分片变得显而易见。其次,分片的所有权开始变得重要。必须有人负责那个不断触发噪声预算的 9 样本分片——要么增加样本,要么弃用它,要么将其接受为仅供参考。第三,关于质量的对话从发布准备评审转移到了每个 PR 的评审中,这正是它本该在的地方。

不变的是,评估套件仍然是需要投入的承重基础设施。Diff 无法修复糟糕的分片、缺失的标签或裁判模型的漂移。它们能更快地暴露这些问题,但不能替代维护套件的工作。一个团队在陈旧、嘈杂且不具代表性的黄金集之上构建了一个漂亮的 Diff 评论,他们只会更快、更诚实地收到其评估套件已损坏的信号——这是一个好信号,只是可能不是他们所希望的那个。

更深层次的认识是,提示词和模型 PR 应该像其他代码变更一样,享受测试套件般的回归检测待遇。评估套件不是质量标准;它是回归检测器。根据上季度的快照进行校准是错误所在。逐个分片地根据父提交进行校准,并配合尊重小样本现实的噪声预算,才是解决方案——它将评估门控从团队学会“通过”的东西变成了团队学会“信任”的东西。

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