AI/ML 详解:评估与基准

Day 15 · 2026-06-01
面向:有编程经验的非 AI 方向工程师
工程对应 → super-individual D6: Eval 工程(怎么搭自己的离线评估流水线)

一个绕不开的问题:「这个模型比那个好」凭什么说?软件工程里你有测试套件——红绿一目了然。但 LLM 的输出是开放文本,没有唯一正确答案。今天拆解四个核心评估机制,它们恰好对应你熟悉的测试金字塔:MMLU 是单元断言,HumanEval 是跑得过测试才算对,MT-Bench 是多轮集成测试,LLM-as-Judge 是自动化裁判——以及裁判自己的 bug。

大规模多任务语言理解MMLU

知识基准多选题
一句话类比

MMLU 就是给模型出的「标准化高考」——57 个学科(数学、法律、医学、历史…)的多选题题库。在你的世界里它对应回归测试套件(regression suite):一组固定不变的断言,每发一个新模型版本就跑一遍,看分数有没有退化。每道题相当于一条 assert

它解决什么问题 + 工作机制

Pain point:早期 NLP 每个任务一个 benchmark,碎片化得像一百个互不兼容的测试框架,没人能回答「这模型到底懂多少世界知识」。Hendrycks 等人 2021 年把 57 个领域的多选题汇成一个分数,覆盖从初等数学到专业法律。

机制的关键不是让模型「自由作答」(那没法自动判分),而是把开放生成问题降维成分类问题:给题干 + 4 个选项 A/B/C/D,看模型对哪个选项赋予的对数似然(log-likelihood,即模型认为这串字出现的可能性)最高。哪个选项概率最高就算选哪个,对了 +1。这一步「降维」是 benchmark 能规模化、零人工的根本原因。

诚实地说它有个致命软肋:污染(contamination)——题目原文泄漏进了训练数据,模型不是「会做」而是「背过」,分数虚高。这就像测试用例被偷偷写进了被测代码。

代码示例
# MMLU 的判分本质:比较每个选项的对数似然,不是让模型自由生成
from datasets import load_dataset

ds = load_dataset("cais/mmlu", "high_school_physics", split="test")
q = ds[0]
# q["question"], q["choices"] = ["A选项",...], q["answer"] = 正确索引

prompt = f"{q['question']}\nA. {q['choices'][0]}\nB. {q['choices'][1]}\n..."

# 对每个候选答案算 log P(选项 | prompt),取最大的作为模型的选择
def score_choice(prompt, letter):
    # 真实评估框架(lm-eval-harness)会取该 token 的 logprob
    return model.logprob(prompt + " " + letter)

pred = max("ABCD", key=lambda L: score_choice(prompt, L))
correct = ("ABCD"[q["answer"]] == pred)  # 自动判分,零人工
常见误区 + 实践场景
误区:「MMLU 高 = 模型真聪明」。错。MMLU 测的是知识检索 + 多选题应试技巧,不测推理深度、不测开放生成质量、更不测多轮对话。一个会背书的模型 MMLU 可以很高,写代码、做 agent 却很差。
📌 超级个体场景:选模型时把 MMLU 当「冒烟测试」——快速淘汰明显不行的,但绝不当最终判据。真正要选「帮我读论文/做决策」的模型,得看贴近你任务的评测(推理、长文本理解),而非一个综合分。
Takeaway + 思考题
💡 MMLU 的天才在于「把开放问题降维成可自动判分的多选题」;它的局限也正源于此——能自动判分的,往往不是你最想测的能力。
🤔 你的 CI 里哪些是「多选题式」的确定性断言,哪些是「需要人来判断好坏」的?后者你现在怎么测?

HumanEval 与 pass@kFunctional Correctness

代码评测概率估计
一句话类比

HumanEval 是给模型的「TDD 验收测试」——164 道 Python 题,每道带一组隐藏单元测试,生成的代码跑过测试才算对,长得漂不漂亮无所谓。而 pass@k 就是你最熟的那个东西:给不稳定的下游服务设重试,重试 k 次至少成功一次的概率

它解决什么问题 + 工作机制

Pain point:代码不能用字符串匹配判分。两段代码可以一字不差地不同却都对,也可以长得几乎一样一个对一个错。所以传统的 BLEU、编辑距离全失效。Chen 等人 2021 年(Codex 论文)的答案简单粗暴:functional correctness——跑单元测试,过了就对

真正有数学含量的是 pass@k。它要回答:「采样 k 个解,至少一个正确的概率多少?」最朴素的写法是 1−(1−p)^k,但单题样本少时方差极大、估计不准。Codex 论文用了一个无偏估计器:每题先采样 n 个解(n 远大于 k),数出其中 c 个正确,然后:

pass@k = 1 − C(n−c, k) / C(n, k)

逐符号拆开看就很直觉:
· C(n, k):从 n 个解里随机抽 k 个,一共多少种抽法(组合数)。
· C(n−c, k):只从那 c 个错解……不对,是从 n−c 个错解里抽 k 个的抽法数——即「k 个全抽到错解」的情况数。
· 两者相除 = 抽 k 个全错的概率;1 减去它 = 至少抽到一个对的概率
用大 n 估出真实正确率,再算这个组合式,就比直接重试 k 次稳得多——本质是用更多采样换更低的估计方差

一题采样 n=8 个解,c=2 个正确:

pass@1 ≈ 25% pass@4 = 1 − C(6,4)/C(8,4) = 1 − 15/70 ≈ 79%
代码示例
# pass@k 无偏估计器(Codex 论文给出的标准实现)
import numpy as np

def pass_at_k(n, c, k):
    # n=总采样数, c=正确数, k=想评估的 k
    if n - c < k:                 # 错解不足 k 个 → 必然抽到对的
        return 1.0
    # 用连乘算 C(n-c,k)/C(n,k),避免大数阶乘溢出
    return 1.0 - np.prod(1.0 - k / np.arange(n - c + 1, n + 1))

# 评测一道题:采样 n 个解,各跑隐藏单元测试
samples = [model.generate(problem["prompt"]) for _ in range(8)]
c = sum(run_unit_tests(s, problem["test"]) for s in samples)

print(pass_at_k(n=8, c=c, k=1))   # 一次就对的概率
print(pass_at_k(n=8, c=c, k=4))   # 4 次内至少一次对
常见误区 + 实践场景
误区:「pass@1 低这模型就没用」。不一定。在有验证器的场景(能自动跑测试),pass@10 高就足够可用——让模型反复试错,验证器挑出对的那个。这正是 coding agent 的工作方式:生成→跑测试→失败就再来。能自动验证时,「采样多次」是被低估的策略。
📌 超级个体场景:评估 coding agent 时,别只看 pass@1。如果你的工作流允许 agent 自己跑测试再迭代,pass@k(k 较大)才是真实可用性指标——这直接决定你能不能放手让它自动改 bug。
Takeaway + 思考题
💡 代码评测的范式转变是「从『长得像』到『跑得对』」;pass@k 则告诉你:有验证器时,模型的价值不在「一次答对」,而在「多试几次能不能撞对」。
🤔 你手上哪些任务有廉价的自动验证器(测试、编译、schema 校验)?那些任务最适合让 AI「采样多次 + 自动筛选」。

MT-Bench 多轮对话基准MT-Bench

开放生成多轮
一句话类比

如果 MMLU/HumanEval 是单元测试,MT-Bench 就是集成测试——它测多轮(2 轮)对话里模型能不能保持上下文一致、follow-up 不掉链子。就像测一个有状态会话服务:第一个请求没问题不算赢,要看跨多个请求后会话状态还对不对。

它解决什么问题 + 工作机制

Pain point:多选题和代码题测不了「开放对话质量」——写作、角色扮演、解释推理、改写。这些没有唯一正确答案,没法 assert。MT-Bench(出自 Zheng 等人 2023 的 MT-Bench / Chatbot Arena 论文)用 80 道高质量两轮问题,覆盖写作、推理、数学、编码等 8 类,专门压力测试「第二轮还跟得上吗」。

核心难题随之而来:开放回答怎么自动判分?MT-Bench 的答案是把判分外包给一个强模型——LLM-as-Judge,给每个回答打 1–10 分(single-answer grading),或两个模型的回答两两对比(pairwise)。这就引出了今天最关键、也最危险的机制 → 下一张卡。

代码示例
# MT-Bench 风格的单答打分:让强模型按 rubric 打 1-10 分
import anthropic
client = anthropic.Anthropic(api_key="sk-ant-...")  # 占位

JUDGE = """你是公正的评审。请就【有用性、相关性、准确性、深度】
给下面的回答打 1-10 分。先简述理由,最后单独一行输出 "Rating: [[分数]]"。

[问题] {q}
[第一轮回答] {a1}
[追问] {q2}
[第二轮回答] {a2}"""

msg = client.messages.create(
    model="claude-opus-4-8", max_tokens=512,
    messages=[{"role":"user",
        "content": JUDGE.format(q=q, a1=a1, q2=q2, a2=a2)}])
# 用正则从 "Rating: [[8]]" 抽出分数——结构化输出便于自动解析
常见误区 + 实践场景
误区:「MT-Bench 分数可以跨论文绝对比较」。不行。分数强依赖用的是哪个 judge 模型、哪个版本、什么 prompt。换个 judge,分数整体平移。它适合同一套设置下的相对比较(A 比 B 好多少),不适合当跨研究的绝对刻度。
📌 超级个体场景:评估你自己的 writing assistant 时,固定一个 judge + 一套 rubric,让它对「旧 prompt vs 新 prompt」的输出两两打分。你关心的是相对进步,不是绝对分。
Takeaway + 思考题
💡 一旦评测对象变成「开放质量」,就没有断言可用,只能引入裁判——而裁判本身需要被评估。
🤔 你怎么知道「第二轮回答好」?把你脑中那套隐性 rubric 写成显式 5 条标准,会发现它比想象中难。

LLM 当裁判LLM-as-Judge

自动评估偏差Elo
一句话类比

用一个强模型给另一个模型的输出打分,就像「用一个服务监控另一个服务」,或者自动化的 code review bot。但关键反转:裁判自己有系统性偏差——就像你的监控系统本身也可能有 bug,会谎报或漏报。不校准裁判,就等于信任一个没测过的探针。

它解决什么问题 + 工作机制

Pain point:人工标注又贵又慢,规模化不了。Zheng 等人 2023 的发现给了 LLM-as-Judge 合法性:GPT-4 当裁判与人类偏好的一致率超过 80%——和人类彼此之间的一致率是同一水平。换句话说,强裁判已逼近「人类天花板」。

但同一篇论文也点名了三大系统性偏差,必须知道:

  • 位置偏差(position bias):成对比较时,倾向于偏好先出现的那个答案,与内容无关。
  • 冗长偏差(verbosity bias):倾向于给更长的回答更高分,哪怕没更好。
  • 自我增强偏差(self-enhancement bias):倾向于偏好自己或同家族模型生成的回答。

最实用的缓解是治位置偏差:交换顺序(swap)跑两遍——A/B 各当一次先手,只有两次都赢才判赢,否则算平。这把「位置」这个干扰变量消掉了。

位置偏差与 swap 缓解:
第 1 轮 答案Avs答案B 裁判选 先手
第 2 轮 答案Bvs答案A 裁判仍选 先手
→ 两轮结论矛盾 = 裁判在看位置不看内容,判为平局

一致性怎么量化?用一致率(agreement rate),更严谨的用 Cohen's kappa——它扣掉了「瞎猜也会蒙对」的随机一致部分,只留下真实一致。另一条路是 Chatbot Arena:让真人对两个匿名模型的回答投票,再用 Elo / Bradley-Terry 模型把海量两两胜负转换成一个排名分(和象棋天梯分同一套数学)。

代码示例
# 成对评判 + 位置交换,消除 position bias
def judge_pair(q, ans_a, ans_b):
    def ask(first, second):
        p = f"问题:{q}\n回答1:{first}\n回答2:{second}\n" \
            "哪个更好?只回 '1' 或 '2'。"
        return client.messages.create(
            model="claude-opus-4-8", max_tokens=5,
            messages=[{"role":"user","content":p}]).content[0].text.strip()

    r1 = ask(ans_a, ans_b)   # A 先手
    r2 = ask(ans_b, ans_a)   # B 先手(交换)
    # 只有两轮都选 A 才算 A 赢,否则平局——抵消位置偏差
    if r1 == "1" and r2 == "2": return "A"
    if r1 == "2" and r2 == "1": return "B"
    return "tie"
常见误区 + 实践场景
误区:「LLM judge 的打分 = 客观真理」。不是。它放大的是训练分布里的偏好——更长、更礼貌、更像它自己的风格的回答得分更高,哪怕实质没更好。把 judge 分数当 KPI 直接优化,模型会学会「讨好裁判」而非「真的变好」(一种 reward hacking)。
📌 超级个体场景:用 LLM judge 自动评估你的 prompt 迭代是高效的,但必须配两道保险:(1) 成对比较 + swap 消位置偏差;(2) 定期人工抽检 一小批,校准裁判有没有跑偏。裁判要被裁判。
Takeaway + 思考题
💡 LLM-as-Judge 让评估规模化成为可能,但它不是真理探测器——它是一个有已知偏差、需要持续校准的探针
🤔 你的监控系统会监控自己吗?同理:当你用 AI 评估 AI,谁来评估那个评估者?这条链在哪里触底?

深入资源Further Reading

深入思考Deep Questions

1. 为什么几乎所有公开 benchmark 最终都会「失效」?这和软件测试里的「测试过拟合」是同一回事吗?
本质相同,但更隐蔽。软件测试里你可能写出「只为通过某个测试」的实现;LLM 的失效有两层:(1) 污染——benchmark 题目流入训练数据,模型从「会做」退化成「背过」,分数虚高却不代表能力;(2) 过拟合到分布——整个行业盯着同一个排行榜优化,模型学会了「这类题的应试模式」而非底层能力,就像所有学校都教同一套高考技巧。结果是 benchmark 一旦广为人知,它的信息量随时间衰减——这也是为什么 MMLU(2021)之后不断有 MMLU-Pro、GPQA 等「更难、更新、更防污染」的基准出现。工程对策类比:定期轮换私有 holdout 测试集,就像安全团队不公开全部渗透用例。对 BigCat 的启示:看到某模型「刷爆某榜」时,第一反应该是「这榜还有多少信息量」,而不是「它真这么强」。
2. pass@k 里「采样 n 个解再估计」和「直接重试 k 次」,统计学上差在哪?为什么论文要多此一举?
差在估计方差。直接重试 k 次只给你一个 0/1 结果(这 k 次里成没成功),单题信息量极低,跨题平均后噪声很大——尤其当某题正确率是 5% 这种小概率时,你重试 5 次很可能全失败,于是把它误判成「pass@5 = 0」,但真实值并非 0。论文的做法是先用大 n(如 100 或 200)把该题的真实正确率 c/n 估准,再用组合公式 1 − C(n−c,k)/C(n,k) 解析地算出 pass@k 的期望。这等于「用更多采样买更稳的估计」。统计直觉:你不是在「模拟一次 k 重试」,而是在「估计这道题的难度参数,再算出任意 k 下的理论通过率」。类比你做压测:与其手动重放 5 次请求看成功率,不如先精确测出单请求成功率 p,再解析推导任意重试次数的可用性——后者样本利用率高得多,结论也稳得多。
3. 既然 LLM-as-Judge 有 80% 与人类一致率,剩下 20% 的分歧是「裁判错了」还是「人类错了」?这个问题为什么没有干净答案?
因为「正确答案」本身不存在——开放生成质量是偏好而非事实,人类标注者彼此都只有约 80% 一致率(即同样两份人工标注也会在 20% 的样本上互相打架)。所以那 20% 分歧里,三种情况混在一起且无法干净拆分:(a) 裁判受偏差影响(偏好长答案)判错;(b) 人类标注者注意力/偏好差异导致「人类标准答案」本身就不稳定;(c) 这道题本来就没有共识好坏(比如两种都合理的写作风格)。这意味着 80% 不是「裁判的准确率」,而是「裁判与一个同样有噪声的参照系的吻合度」——参照系本身就有 20% 内部噪声。深层含义:评估开放质量时,不该追求「逼近真理」,而该追求「与目标人群偏好对齐」。对 BigCat:当你用 judge 评估「哪个写作风格更好」,先想清楚对谁更好——裁判校准的方向应该是你的真实受众,而非某个抽象的「客观质量」。
4. 把今天四个机制串起来:为什么评估的难度是「越接近真实价值的能力,越难自动评估」?这对你设计 AI 工作流意味着什么?
四个机制恰好排成一条「可自动化程度 vs 贴近真实价值」的反向曲线。MMLU 完全可自动判分(多选),但离真实价值最远(只测知识检索);HumanEval 可自动判分(跑测试),贴近度提升(真能写对代码);MT-Bench 测开放质量、贴近真实使用,但已无法用断言判分,被迫引入裁判;LLM-as-Judge 试图自动化「质量判断」本身,却带来偏差和「谁评估评估者」的无穷回退。规律是:能写成 assert 的能力,往往不是你最在乎的;你最在乎的能力,往往写不成 assert。对工作流设计的意涵:(1) 在有廉价验证器的环节(代码、数据校验、格式)尽量自动化、放手让 AI 多采样自筛;(2) 在开放质量环节(写作、决策、跨学科洞察)保留人在环(human-in-the-loop),用 LLM judge 做初筛、人做终审;(3) 警惕「因为某能力好测就过度优化它」——这是评估驱动的局部最优陷阱,会让你在能量化的地方过度投入,在真正重要却难量化的地方失明。