评测分数里的三处泄漏:判定器、协议与推理栈
同一模型换一套同样合理的评测配置,35.3% 的站点会选出不同赢家;同一条提示换 BF16/FP16,49%–100% 会分叉。三份新证据指向同一件事:分数里混进了不属于模型的东西。
一个分数里,有多少是模型挣来的
9 月 22 日 arXiv 上挂出两篇论文。一篇说同一个模型、同一条提示、同一个 greedy 解码算法,在 BF16 和 FP16 下会给出不同答案;另一篇说一个便宜判定器只要肯承认自己没把握,就能用比较器 0.36% 的费用留住它 99% 的准确率。再往前一个月,还有一篇把矛头对准了评测协议本身:换一套同样合理的评测配置,35.3% 的监测站会选出不同的冠军模型。
三篇论文讲的都不是模型变强,而是分数里混进了不属于模型的东西。做评测流水线的人得把这三处泄漏分别堵上——它们的排查顺序,正好是从上往下。
泄漏一:判定器把分数吃在低置信区
JEV-as-a-Judge(卡内基梅隆,9 月 22 日提交)拿一个只输出判定和标签概率的判定器,跟 16 个生成式判定器和奖励模型对打, disagreement 交盲审人工裁决。在普通偏好和证据接地的事实性上,它与最强比较器相差 3 个百分点以内,费用是对方的 0.36%。
便宜不是重点。重点是它的置信度能把错误排出来:按最大标签概率 q 分箱,q<0.6 的 65 项上准确率 47.7%,[0.7,0.8) 的 85 项上 76.5%,[0.95,0.99) 的 147 项上 93.9%,q=1 的 322 项上 99.1%。同一批题上最强比较器只从 78.5% 走到 99.1%——强模型的优势全堆在弱判定器没把握的那一头。
这就给出了一条能落地的门。判定器先过一遍,有把握的直接收下,没把握的升级给强模型:
def two_order_confidence(first_pos_prob, a, b):
"""双向打分后对齐平均,抵消位置偏好;平局记半分。"""
p_ab = first_pos_prob(a, b) # A 在第一位时 A 的概率
p_ba = first_pos_prob(b, a) # B 在第一位时 A 的概率
return 0.5 * (p_ab + 1.0 - p_ba)
def gate(item, tau, fallback):
q = two_order_confidence(jev_first_pos_prob, item.a, item.b)
if q >= tau:
return {"verdict": item.jev_verdict, "src": "jev", "q": q}
return {"verdict": fallback(item), "src": "fallback", "q": q}
阈值不能拍脑袋。论文的做法是在独立的 selection set 上扫格子:在「覆盖率最大化」的前提下,要求 selection set 准确率与 fallback 的差距不超过 2 个百分点。冻结后的 τ=0.9 策略(fallback 为 GPT-6 Astra)在 510 条留出偏好对上接受 53.7%,准确率 92.5% 对 fallback 的 93.1%,费用 56.8%(保守口径 62.2%)。单序版本更直观:升级 34% 的题目,准确率 91.3% 对 GPT-6 的 91.7%——保留 99.6%——花掉 47% 的钱,约 $6.3 每一千次判定;同样升级 34% 但随机挑题只能到 88.1%,按标签挑的最优上限是 94.4%——置信度信号吃掉了一半可得增益。
⚠️ 原稿把单序版本写成「拿到 fallback 99.6% 的准确率」,方向读反了。论文原文是 “scores 91.3% against GPT-6’s 91.7%(99.6% retained)“:91.3% 是级联的绝对准确率,99.6% 是它相对 fallback 的保留率(91.3/91.7)。级联并没有追平 GPT-6,它省下的 53% 费用换来的是 0.4 个百分点的绝对损失。这个区别决定了这条路的定位——它是省钱工具,不是提分工具:凡指望级联把评测质量提到强模型之上的场景,从一开始就不成立。
两个坑必须提前说清。阈值不跨模型迁移:给 GPT-5.6 Sol 配的 τ=0.7 策略接受了 81.0% 的题目,代价是掉 2.35 个点,超出 2 个百分点的容忍线;另有三个策略干脆退化成「只做双向平均、不升级」——论文的冻结策略表显示这三条的阈值恰好都是 τ=0.5(接受率 100%,即永不升级),涉及 GPT-OSS 120B、Qwen3.6 27B、Qwen3.8 27B 三个 fallback。同一个 τ=0.9 换成 GPT-5.4 当 fallback,接受率同样是 53.7%,但保守费用口径变成 1.096(超过 1,比全用 fallback 还贵),原因是缺失用量按预留计费。换 fallback 就要重扫阈值,这是这条路上最容易被忽略的一步。信号有失效区:RM-Bench 的 hard 子集上 q 对正确性的 AUROC 从 easy/normal 的 0.918/0.902 掉到 0.770,[0.9,0.95) 区间错掉三分之一;无参考答案的自由文本上 AUROC 是 0.518,任何阈值都不起作用。上线前拿「它将来会遇到的题型」扫一遍 AUROC,低于 0.7 就别开级联。
泄漏二:换一套同样合理的协议,赢家就换了
Quantifying Protocol-Induced Uncertainty(Eastern University,8 月 26 日)把「评测协议的选择」当成一种不确定性来源来量化。425 个欧洲背景监测站、365 个美国 EPA 监测点,static split 与 rolling-origin 两种协议,7 个预测 horizon。
换协议的平均 PSS 是 0.801 和 0.772,35.3% 和 31.5% 的站点选出的冠军模型变了;而协议内部那些惯例性扰动(同样打分的靶标)只给出 0.072 和 0.230 的 PSS,冠军更换率 0.8% 和 4.9%。两者差三到七倍。候选模型从 3 个扩到 9 个,跨协议换冠军的比例升到 60.2%——候选集越大,结论越脆。
PSS 的定义可以直接抄进自己的流水线:
from scipy.stats import kendalltau
def pss(rank_p, rank_q, weights):
"""rank_p/rank_q: 各 coordinate 下按损失升序的模型排序。值域 [0,2]。
论文式 (1):分子是加权位移和,分母必须除以权重总和,否则量纲随 coordinate
个数漂移,跨实验不可比。"""
num = sum(w * (1 - kendalltau(rank_p[c], rank_q[c]).statistic)
for c, w in weights.items())
return num / sum(weights.values())
def winner_swap(loss_p, loss_q, weights):
swapped = sum(w for c, w in weights.items()
if argmin(loss_p[c]) != argmin(loss_q[c]))
return swapped > 0.5
这里有个容易被忽略的分辨率陷阱:完整且无并列时,一次相邻对换改变 4/[M(M−1)],H 个等权 coordinate 下最小非零位移 δ_min = 4/[M(M−1)H]。M=3、H=7 时是 0.095,M=9 时只有 0.0079。
更反直觉的是扩到 9 个候选后两个指标朝相反方向走:换冠军率从 35.3% 升到 60.2%,而平均 PSS 从 0.801 降到 0.540。两者并不矛盾——Kendall 对所有候选对一视同仁,新增的 6 个候选大多稳定地待在底部或顶部(persistence 恒在末位、灵活方法恒在前列),这些不变的成对关系把平均位移摊薄了;而真正激烈的竞争发生在榜首附近,恰恰是最终要选模型的那一段。所以只看 PSS 会得出「候选多了排名反而更稳」的错误结论,只看换冠军率又会低估整体排名的扰动。两个指标必须一起报,且要注明候选集大小。
论文的落地建议很克制:凡声称某模型更优,就附上一小组事先声明的、协议内合法扰动下的排名稳定性。
泄漏三:greedy 解码也不是确定的
Greedy Decoding Is Not Precision-Invariant(TMLR 2026,9 月 22 日)测了 6 个 1.1B–7B 模型(4 个家族,另在 12B 上做了表征)和 3 个基准:同一硬件上 BF16 与 FP16 的输出分歧覆盖 49%–100% 的提示,单个 token 翻转经常级联成整条轨迹的分叉。
机制上有个反直觉的结论:22 层累积的 body 误差区分不了「翻转步」和「非翻转步」,结果主要取决于 LM head 处 top-2 logit 的间隔,相对于两个候选之间方向性扰动的大小。由此推出的五条可检验预测全部命中,其中一条是把更多计算放进 FP32 反而让一致率变差。作者给出的最佳低开销干预是选择性 FP32 LM head 重计算——只在间隔低于阈值时触发——在 A10G 上拿到 +22–36 个百分点的完全一致率提升(L4 与 A100 上 +12–21),batch≤4 的单流推理延迟开销低于 4%。边界也很清楚:body 误差主导时收益消失,在 batch≥8 和端到端 FP8 下无效。(摘要与正文概览都只说「间隔低于某个阈值时触发」,未给该阈值的数值,别照着猜,在自己模型上扫。)
对评测流水线来说,可操作的不是去改精度,是把推理栈钉死并留证:
run:
commit: 9f3c1ab
framework: vllm 0.11.2
dtype: bf16 # 与 fp16 之间会分叉
kernels: flash-attn 2.7.4
batch_size: 4 # ≥8 时上述干预收益消失
gpu: A10G
decoding: greedy
seed: 0
每次评测产出都带一份 manifest,「分数对不上」时先比 manifest 再比模型。跨团队对齐数字前,把 dtype、batch、kernel 版本三项先对齐——这是三处泄漏里成本最低、最常被漏掉的一处。
出问题时,按什么顺序查
三处泄漏的排查成本差着一个量级。分数对不上,先比 manifest:dtype、batch、kernel 版本三项是否一致,几分钟就能判定,且不必重跑。manifest 一致而排名照样变,去查协议——换一组事先声明的合法配置重算 PSS,看冠军更换率本来就在不在那个量级。前两步都排除了,才轮到判定器:把争议样本按 q 分箱,看错误是不是堆在低置信区;堆在低区就调阈值,没有堆在低区说明级联已经开在了失效区,加钱也救不回来。
发布前的最小清单
三处泄漏对应三条门禁:判定器要报 q 分箱准确率和 AUROC,级联阈值在独立 selection set 上拟合并按题型复验;评测报告要带 PSS 与冠军更换率,候选集扩容时重新算一遍;产物要带推理栈 manifest,复现以 manifest 一致为前提。
三件事都不需要新模型,只需要承认一件事:分数是流水线的产物,不是模型的属性。
参考来源
- JEV-as-a-Judge: Accept When Confident, Escalate When Unsure(arXiv:2609.26550,2026-09-22)
- Quantifying Protocol-Induced Uncertainty in Comparative Predictive-Model Evaluation(arXiv:2609.26288,2026-08-26)
- Greedy Decoding Is Not Precision-Invariant(arXiv:2609.26621,TMLR 2026)