> 把失败归因给模型之前,先审 verifier——41% 的"模型错误"其实是判分 bug
跑一个自动判分的 benchmark,拿到 81% 通过率之后, 第一件事不是分析模型为什么错,是逐条看那 19 个失败案例。
结论先行¶
跑一个自动判分的 benchmark,拿到 81% 通过率之后, 第一件事不是分析模型为什么错,是逐条看那 19 个失败案例。
一次实际的分类结果(IFEval,n=100,19 个失败):
| 类别 | 数量 | 占失败 | 真实根因 |
|---|---|---|---|
| JSON 格式检测 | 5 | 26.3% | verifier bug |
| 高亮段落检测 | 2+ | ~15% | verifier bug |
| 字数限制 | 2+ | ~15% | 模型生成 |
| 关键词频率 | 1+ | ~10% | 模型生成 |
| 标点(禁逗号) | 1 | 5.3% | 模型生成 |
超过 40% 的"失败"是判分器的问题,不是模型的问题。 不看就直接写"模型在指令遵循上有 19% 的失败率",这个数字是错的, 而且错在系统性高估模型缺陷的方向上。
为什么¶
两个 bug 都极其典型,值得当成模板记住:
1. json.loads(response) 直接解析原始输出。
LLM 几乎总是把 JSON 包在 markdown 代码块里:
```json
{ ... }
```
判分器看到反引号就解析失败,判为"没有按 JSON 格式输出"—— 而模型完全正确地按 JSON 输出了。5 个案例,全部同一原因。
2. 高亮检测只认 **bold** 和 # header。
模型用了 *italic* 或 `code` 就判为"没有高亮段落"。
指令说的是"highlighted sections",模型的理解合理,判分器的枚举不全。
共同结构:判分器把"一种正确的表达方式"当成了"唯一正确的表达方式"。 这在任何基于格式/正则的自动判分里都会发生,而且只会朝一个方向出错—— 误判为失败,从不误判为成功。所以它不是噪声,是偏差。
怎么用¶
每次拿到自动判分结果,先做失败案例审计。 流程:
- 把所有失败案例导出来,人工看一遍。 n=19 的时候这是十几分钟的事。 即使 n=200,抽 30 个也足以估计 verifier bug 的比例。
- 给每条标根因,只有三类:
verifier bug/模型生成/指令本身歧义。 第三类经常被忽略,但它决定了这一条该不该计入分母。 - 修完 verifier 重跑,报修复前后两个数,并说明差异来自判分器。 直接只报修复后的数,等于隐瞒了 benchmark 的一处缺陷。
- 把 verifier bug 的比例本身当作一个结果报出来—— 它是关于这个 benchmark 可信度的信息,对社区有价值。
预防性检查(写 verifier 时):
| 检查 | 问题 |
|---|---|
| 解析前是否剥离 markdown 代码块 | JSON / YAML / 代码类判分的第一大 bug |
| 格式枚举是否穷尽 | **b** *i* _i_ __u__ `c` 都算高亮吗 |
| 大小写、全角半角、多余空白 | 中英混排时尤其 |
| 失败时能否给出原始片段 | 只报 pass/fail 的 verifier 无法审计 |
最后一条是根本性的:verifier 必须记录它判失败时看到的原文。 不记录就没法做上面的审计,于是所有判分 bug 都会永久伪装成模型缺陷。
同源:指标的默认回退是静默的——而且 p 值不是效应量(指标含义错)、 区分"近似漂移"和"真 bug":用发散位置,不用最终指标(把 bug 当成方法的正常代价)。 三者都是"数字是对的,解释是错的"。
出处¶
~/Projects/SynthEval/results/FAILURE_ANALYSIS.md(IFEval 官方 benchmark, n=100,GPT-4o-mini)