模型评测涨分,如何排除随机波动
文章指出,评测集采样、LLM 裁判和任务执行中的噪声,都可能让分数上涨掩盖真实回归。提出用配对比较和统计功效检验建立 CI 门禁,避免仅凭平均分批准模型或提示词变更。
AI 深度解读
把 prompt 调一遍,评测均分从 0.81 涨到 0.83,就能批准上线吗?作者见过三次类似事故:总分看着进步,两周后却发现某类意图在生产环境退化。文章的主张是,LLM 发布门禁需要配对比较、样本量估算和置信区间,不能只盯均分。
这套方法适合正在给 AI 应用接 CI 的团队。但原文的统计公式有简化,代码也被截断,值得借鉴思路,不能直接照搬结论。
为什么涨了两分,仍然不能证明变好了
作者把评测波动分成三类。
第一类是样本抽样噪声。黄金集只有 200 条时,每条占 0.5 个百分点;所谓提升 3 个百分点,可能只是六条样本翻转,其中还有边界案例。
第二类是裁判噪声。用 LLM 打分且 temperature 大于 0,同一个输出可能今天通过、明天失败。即便只是把比较顺序从「A、B」改成「B、A」,裁判也可能给出不同判断。
第三类是任务噪声。生成时的采样温度、工具超时、检索索引漂移,都可能在业务代码没有变化时改变输出。
作者建议,让 baseline 和 candidate 跑同一批样本,再逐条相减。一条修好了记 +1,一条弄坏了记 -1,避免两组样本难度不同干扰比较。
配对能减少比较中的噪声,但不能保证评测结果没有随机性。
尤其要区分:固定同一批题目,能控制两组题目不一致的问题,却不能消除这 200 条样本代表不了真实流量的问题。
200 条样本,究竟能看见多大的变化
文章强调,配对通过率比较要关注「分歧率」,即两个配置在同一条样本上给出不同通过结果的比例。
原文假设分歧率为 15%,样本量为 200,给出:
SE = sqrt(0.15 × 0.85 / 200) ≈ 2.5 个百分点
在统计功效为 80%、α=0.05 时,原文估算最小可检测效应(MDE)约为 2.8 × SE ≈ 7 个百分点。统计功效可以理解为:变化确实达到指定幅度时,检验有多大概率发现它。
按同一套估算,检测 5 个百分点需要约 400 对样本,检测 3 个百分点需要约 1,100 对。它们是公式推算,不是实测基准。
不过,这里的公式需要打个问号。对取值为 -1、0、+1 的配对差值,若分歧率为 q、平均差值为 δ,方差应为 q - δ²,不能普遍写成 q × (1-q)。原文的 required_n(disagreement_rate, mde, z_alpha=1.96, z_power=0.84) 沿用了后一种写法,因此这些样本量只能作为原文的粗略估算,正式设门槛前需要重新计算。
方向仍然有用:样本越少,越难可靠识别小幅变化。均分多出两个百分点,证据可能远远不够。
CI 应该看区间,而不是只看 delta
作者给出的核心实现,是对配对差值做 bootstrap:反复有放回抽样,观察平均差值的分布。
def paired_bootstrap(baseline, candidate, iters=5000, seed=7):
"""Scores aligned on the SAME example ids, 0/1 or 0..1.
Returns (mean delta, 2.5th pct, 97.5th pct)."""
diffs = [c - b for b, c in zip(baseline, candidate)]
n = len(diffs)
rng = random.Random(seed) # fixed seed: the gate must be reproducible
means = sorted(
sum(diffs[rng.randrange(n)] for _ in range(n)) / n
for _ in range(iters)
)
return sum(diffs) / n, means[int(0.025 * iters)], means[int(0.975 * iters)]
最该检查的是 zip(baseline, candidate):两列分数必须按相同 example id 对齐,长度也要一致,否则代码仍可能返回一个看似正常的结果。运行这个函数还需要原文中的 import random。
它默认抽样 5000 次,使用 seed=7 固定重采样随机数,返回均值及第 2.5、97.5 百分位数。固定种子只能让这一步可复现,不能固定模型生成、裁判和工具调用。
如果要求「证明提升」,作者建议区间下界高于零才放行。如果黄金集无法扩充,则建议改成「退化不超过 X」。两者不是同一道门槛:后者需要先确定可接受的退化幅度,再围绕这个阈值判断。
原文标注了 python paired_gate.py、仅依赖 Python 标准库,但示例在 print(f"delta 处截断,没有完整的 CI 接入和退出码逻辑。
我的判断
我赞成把发布判断从单个均分推进到逐条差值和区间。相比「涨分就合并」或「重跑几次看着稳定就上线」,它能把证据不足暴露出来。
但作者没有提供三次事故的详细记录,也没有给出采用门禁后的对照数据。「半天统计加一个 CI job 就能解决」属于经验判断,所需时间取决于团队有没有对齐的样本、可靠的评分和可控的运行环境。
还有一个缺口:总体区间通过,仍然可能掩盖某类意图退化。文章开头的事故恰好属于这种情况。配对统计能改善总体判断,却不能自动替你发现被平均值淹没的业务问题。
能拿来做什么
- 给现有 AI 应用评测保留 example id、baseline 分数和 candidate 分数;在 CI 里先校验一一对齐,再计算配对差值。
- 改 prompt 或替换模型之前,先确定要检测多大的变化,再估算样本量;不要让固定的 200 条样本承担识别任意小提升的任务。
- 把「证明提升」和「允许有限退化」写成两种明确规则,并为后一种规则预先确定 X,避免看到结果后再改标准。
- 除了总分,也检查关键意图的失败明细;同时记录生成温度、裁判设置和检索环境,方便判断波动来自哪里。