本节摘要:6.1 的 0/1/2 判分有一个隐含前提——每道题存在可写死的对错口径。当任务是开放的(文案、安抚话术、摘要风格),"好坏"变成偏好,绝对判分就会标准分裂(2.1 讲过的锚点漂移与评分者分歧)。本节把 2.1 的机制搬到家里:成对比较——评审只回答"左边的回答好还是右边的好",这个判断人类做得又快又稳;战果积累成内部竞技场,用简易 Elo 排名(K=32 在线更新,起点 1500),配对战矩阵防 Elo 失真。脚本纯标准库可直接运行,输出排名、对战矩阵与"分差 → 预期胜率"换算——直接复用 2.1 的公式与 2.2 的小样本警告(20 场战事只当候选排序)。组织纪律四条:匿名、乱序、禁止弃权、评审三人成局;风格偏置(2.3)在内部竞技场原样存在,治理靠乱序与多人而非"相信评审"。要不要用模型当裁判省人力:给出选择者的三条纪律,深入做法详见《Evals 实战》第 5 章的裁判设计。
阅读完本节,你应当能够:
三个信号,出现任意一个就该考虑成对比较:
| 信号 | 表现 | 根因 |
|---|---|---|
| 口径写不死 | 同一份回答,A 判 2、B 判 1,双人一致率上不去 | 判分标准本质是偏好 |
| 分数挤在一起 | 所有模型都拿 1 分,总分没区分度 | 尺度太粗,差异在维度之间而非对错之间 |
| 评审自己打架 | 判分人反馈"说不清为什么,就是左边好" | 判断是整体的,拆不成 checklist |
2.1 的结论在这里直接兑现:成对比较的偏好稳定性显著高于绝对量表(社区通行经验)——"哪个好"比"打几分"容易得多。代价是信息量变稀:一场投票只贡献一比特,所以成对比较需要更多评审人次,且只回答排序问题、不回答"离合格还差多远"——绝对水平仍要靠 6.1 的可判分子集兜底。
把 2.3 的投票噪声治理提前到设计里,四条纪律:
配对方案:3 个模型 3 组对局(C(3,2)=3),每组 7 场起步(示意量级,正式用建议 15+);题从 6.1 的题集里抽,开放维度优先。
# arena_elo.py(纯标准库,可直接运行) """内部竞技场:成对战果 -> 简易 Elo 排名与对战矩阵(K=32,起点 1500)。""" BATTLES = [ # 示意:团队评审对匿名 A/B/C 投票的战果(20 场) ("A", "B", "A"), ("A", "B", "B"), ("A", "B", "A"), ("A", "B", "A"), ("A", "C", "A"), ("A", "C", "C"), ("A", "C", "A"), ("A", "C", "A"), ("B", "C", "B"), ("B", "C", "B"), ("B", "C", "C"), ("B", "C", "B"), ("A", "B", "A"), ("A", "C", "A"), ("B", "C", "B"), ("A", "B", "B"), ("A", "C", "A"), ("B", "C", "B"), ("A", "B", "A"), ("B", "C", "C"), ] def expected(ra, rb): return 1 / (1 + 10 ** ((rb - ra) / 400)) # 2.1 的"分差 -> 胜率"公式 def update(ratings, a, b, winner, k=32): ea = expected(ratings[a], ratings[b]) sa = 1.0 if winner == a else 0.0 # 平票记 0.5(本例未出现) ratings[a] += k * (sa - ea) ratings[b] += k * ((1 - sa) - (1 - ea)) if __name__ == "__main__": ratings = {m: 1500.0 for m in ("A", "B", "C")} h2h = {} for a, b, w in BATTLES: update(ratings, a, b, w) h2h.setdefault((a, b), [0, 0])[0 if w == a else 1] += 1 print("内部竞技场排名(Elo,K=32,起点 1500):") for m, r in sorted(ratings.items(), key=lambda x: -x[1]): print(f" {m}: {r:.0f}") print("对战矩阵(胜-负):") for (a, b), (wa, wb) in h2h.items(): print(f" {a} vs {b}: {wa}-{wb}") top = sorted(ratings.items(), key=lambda x: -x[1]) gap = top[0][1] - top[1][1] print(f"读法:头名领先 {gap:.0f} 分 ≈ 预期胜率 {expected(top[0][1], top[1][1]) * 100:.0f}%" f"(2.1 换算);20 场的小样本,结论只当候选排序,别当定论(2.2)")
一次运行的真实输出(实测,示意输入):
内部竞技场排名(Elo,K=32,起点 1500): A: 1583 B: 1494 C: 1423 对战矩阵(胜-负): A vs B: 5-2 A vs C: 5-1 B vs C: 5-2 读法:头名领先 89 分 ≈ 预期胜率 62%(2.1 换算);20 场的小样本,结论只当候选排序,别当定论(2.2)
三个读数纪律:对战矩阵先于 Elo——5-2、5-1、5-2 的传导关系与排名一致,Elo 才可信;若出现"A 胜 B、B 胜 C、C 胜 A"的环,说明三者实力在噪声内,Elo 的微小分差没有含义(2.2 的"统计并列"内化);头名分差要换算——89 分 ≈ 62% 预期胜率,听着领先,其实在"前两名接近、第三名落后"的档位里;战次决定上限——20 场只是演示,正式结论至少 3 组 × 15 场 × 3 人。
💡 在线 Elo(本脚本)对战序敏感,Bradley-Terry 整体拟合更稳——这正是 LMArena 2023-12 切换到 BT 的原因(官方口径,2.1 讲过)。内部竞技场规模小,两者的差异通常小于评审噪声,不必过度工程化。
评审人次是内部竞技场的瓶颈,用模型当裁判(LLM-as-judge)是自然的选择——MT-Bench 系列研究(Zheng et al.)已把这条路线走通(与人类偏好的一致性见其论文口径)。选择者视角的三条纪律:
裁判的深入做法——rubric 设计、偏见清单、多裁判仲裁、成本控制——详见《Evals 实战》第 5 章(裁判设计是那一章的主业);本书只管"你作为选择者外包判分时怎么不翻车"。
6.1 的 0/1/2 与本节的成对比较不是二选一,是分工:可判分子集(格式、边界、事实正确)走盲测拿绝对分,开放子集(话术、风格、可读性)走竞技场拿排序;两份证据在第 7 章的需求矩阵里按维度权重合成。合并时一个常见坑:Elo 分与 0/1/2 分不可直接平均——一个是相对量表一个是绝对量表,先各自归一到"该维度谁占优",再进矩阵。
至此,你手里有了两类自己的证据:绝对分(6.1)与偏好排序(6.2)。但证据不会自己变成决定——预算约束、延迟门槛、切换风险都还没进方程。第 7 章把这些收进需求矩阵、成本延迟质量三角和一页选型报告,产出本书的最终交付物。