大模型评测体系详解

模型换了、prompt 改了、RAG 的 chunk 大小从 512 调到 1024——你怎么知道到底是变好了还是变差了?
大多数团队的回答是"跑个分看看"。但"跑个分"和"评测体系"之间,差的不是几个脚本,而是一整套方法论。
这篇文章把大模型评测拆成四层结构,讲清三类评测范式、六类指标怎么选,以及最容易被忽视的数据污染问题,最后给出一条能接进 CI、每次改动都能自动跑起来的评测流水线,附带可直接复用的代码。
一、先明确:评测到底在测什么
很多人一上来就问"用哪个榜单"。这个问题本身就错了——榜单是工具,不是目的。真正的评测要先回答:你要用它做什么决策?
不同决策需要不同层级的证据,这就是评测体系的四层结构:

| 层次 | 核心问题 | 典型手段 | 结论用于 |
|---|---|---|---|
| 场景与端到端 | 在我的业务里能不能跑通 | RAG 忠实度、Agent 任务成功率、工具调用准确率 | 上线决策 |
| 对齐与安全 | 输出是否可控、可信、可担责 | 指令遵循、安全基准、过度拒答、幻觉率 | 风险审批 |
| 核心能力 | 模型本身有多强 | MMLU-Pro、GPQA、MATH、HumanEval、LiveCodeBench | 选型 |
| 系统与成本 | 跑得起吗、快不快、贵不贵 | TTFT、吞吐、P99 延迟、每百万 token 成本 | 容量规划与报价 |
关键认知:这四层不可互相替代。
一个 MMLU 85 分的模型,可能在你的客服场景里因为不遵守"必须先核实订单号"的指令而完全不可用;一个 Agent 任务成功率 90% 的模型,可能每百万 token 贵 8 倍。反过来,只做业务端到端评测的团队,往往在换基座模型时完全失去方向感——因为不知道该往哪个能力维度上加数据。
一个成熟的评测报告,四层必须齐全。
二、核心能力层:MMLU 早就该退休了
2.1 知识类基准的"饱和"问题
MMLU 是过去三年被引用最多的基准:57 个学科、约 1.6 万道四选一,4-shot。但头部模型的分数已经普遍超过 88 分,区分度接近 0——85 分和 88 分之间更多反映的是题目噪声,而不是能力差异。
于是有了几个替代方案:
- MMLU-Pro:1.2 万题,选项从 4 个扩到 10 个,去掉了"靠排除法也能蒙对"的水分,并要求 CoT 作答。头部模型分数普遍掉到 70 分上下,重新有了区分度。
- GPQA Diamond:198 道博士级物理/化学/生物题,设计目标就是"Google 不到答案"。人类专家(非本领域)正确率约 34%,是少数还没被刷爆的硬基准。
- HLE(Humanity's Last Exam):2500 道专家级跨学科题,用来测量"前沿到底还差多远"。
- 中文能力:C-Eval(52 个学科、约 1.4 万道)、CMMLU(67 个主题)。注意:中文基准的翻译腔题目较多,且同样存在污染,不要只看总分,要看学科分项。
2.2 数学与代码:正确性可验证,所以更可信
这两类任务的判分可以自动化到接近 100%,因此是评测里最"干净"的部分:
- 数学:GSM8K(8500 道小学应用题)已经饱和;MATH(1.25 万道竞赛题)仍有区分度;AIME 每年新题是当前最好的抗污染数学基准之一。
- 代码:HumanEval(164 题)太小,方差极大,一题之差就是 0.6 分;MBPP(974 题)稍好;真正有说服力的是:
- LiveCodeBench:按题目发布时间切分,只用模型训练截止日期之后的题,天然抗污染;
- SWE-bench / SWE-bench Verified:真实 GitHub issue,让模型改真实仓库,用测试用例判定。500 条 Verified 子集是目前最接近"真实工程能力"的基准。
2.3 一张基准选型表
| 能力维度 | 推荐基准 | 规模 | 指标 | 现状与注意点 |
|---|---|---|---|---|
| 通用知识 | MMLU-Pro | 12k | Accuracy | 已取代 MMLU 成为主基准 |
| 专家推理 | GPQA Diamond | 198 | Accuracy | 方差大,务必报置信区间 |
| 数学 | MATH-500 / AIME | 500 / 30 | Exact Match | AIME 每年换题,抗污染 |
| 代码(函数级) | HumanEval / MBPP | 164 / 974 | pass@1 | 规模太小,只做参考 |
| 代码(工程级) | SWE-bench Verified | 500 | resolve rate | 最贴近真实开发 |
| 指令遵循 | IFEval | ~500 | 约束满足率 | 客观可验证,强烈推荐 |
| 长文本 | RULER / NIAH | 可配置 | 各长度档准确率 | 必须测多个长度档,别只测 32k |
| 中文 | C-Eval / CMMLU | 14k / 11k | Accuracy | 分学科看,别只看总分 |
选型经验:能力维度上,宁可要 3 个"小而硬"的基准(GPQA、AIME、SWE-bench Verified),也不要 20 个"大而水"的排行榜分数。
三、对齐与安全层:只测"安全"会奖励"什么都不答"的模型
这一层最容易被做偏。常见的错误是只测"有害问题有没有拒绝",结果得到一个过度拒答的模型:安全分满分,但用户问"如何杀死一个进程"都会被拒绝。
正确的做法是三个维度同时测:
- 有用性(Helpfulness):指令遵循能力。IFEval 用"必须包含关键词""必须少于 200 字""必须用 JSON 输出"这类可程序验证的约束,直接算满足率,是最客观的对齐指标。
- 无害性(Harmlessness):SafetyBench、HarmBench、JailbreakBench,覆盖直接有害请求与越狱攻击。
- 诚实性(Honesty):TruthfulQA(817 题,考"常见误解")、SimpleQA(4326 题短答案事实性)、HaluEval(幻觉检测)。注意 SimpleQA 的绝对分数很低,前沿模型也常在 30 分以下——这是设计使然,它测的是"敢不敢说不知道"。
同时必须测过度拒答:XSTest 提供 250 条"看起来敏感但其实完全安全"的提示(如"怎么用刀切菜"),统计误拒率。
一条判断准则:如果你的安全评测只报告了"有害请求拒答率",那这个数字越高,模型可能越没用。必须同时报告"安全提示的误拒率",两者一起看才有意义。
四、场景与端到端层:唯一无法外包的一层
前三层都能用公开基准,这一层不能。因为它完全取决于你的业务分布。
4.1 RAG 系统
不要只测"最终回答对不对",要拆开测,否则你不知道是检索坏了还是生成坏了:
| 指标 | 含义 | 低了说明什么 |
|---|---|---|
| Context Recall | 参考答案里的信息,检索结果覆盖了多少 | 检索召回不足 |
| Context Precision | 检索结果里有多少是无关噪声 | 检索排序有问题 |
| Faithfulness | 回答是否完全由检索内容支撑 | 模型在编,幻觉 |
| Answer Relevancy | 回答是否切题 | 生成偏题 |
RAGAS 是这套指标最常见的开源实现。另外建议单独构造一组负样本(问知识库里根本没有的问题),专门测"模型会不会老实说不知道"——这是生产环境最常见的翻车点。
4.2 Agent / 工具调用
Agent 的评测和 Chat 完全不同,因为它是多步轨迹:
- 任务完成率:最终状态对不对(τ-bench、WebArena、OSWorld)。
- pass^k 一致性:同一任务跑 k 次,全部成功的概率。这个指标极其重要——一个"平均成功率 80% 但方差巨大"的 Agent,在生产上比"稳定 70%"的更难用。
- 函数调用准确率:BFCL 覆盖单轮、多轮、并行调用、拒答调用等场景。
4.3 多模态与长文本
MMMU(大学级多模态理解)、MathVista(视觉数学)、Video-MME(视频理解)是当前主力。长文本一定要做多长度梯度测试:8k / 32k / 128k 各测一遍,因为"支持 128k"和"128k 内还能用"完全是两件事。
五、系统与成本层:能力涨 2 分,价格翻 3 倍,算不算升级?
这一层经常被忽略,但它常常是真正的决策依据:
| 指标 | 定义 | 为什么重要 |
|---|---|---|
| TTFT | 首 token 延迟 | 决定"感觉快不快",交互类产品红线 |
| TPOT / ITL | 相邻 token 间隔 | 决定"读起来顺不顺" |
| 吞吐 | tokens/s(含并发) | 决定单卡能服务多少用户 |
| P99 延迟 | 99 分位延迟 | 平均值好看但长尾爆炸是常态 |
| 单位成本 | 每百万 token 成本(含缓存) | 决定商业模式是否成立 |
务必在真实并发下测,单请求压测出来的吞吐没有参考价值。还要测上下文长度对延迟的影响——很多模型在 8k 上下文时很快,到 100k 时 TTFT 会涨 10 倍。
六、方法论:三种评测范式,没有一种能单独成立
6.1 静态基准:给你"可比性"
优点是可复现、成本低、有社区共识,是版本回归的最佳基线。缺点是会被污染、会饱和、对 prompt 极其敏感——同一模型换个 few-shot 数量,分数能差 5 分以上。
6.2 动态与对抗评测:给你"真实性"
包括 LiveCodeBench 这类时间切分基准、Arena 这类实时对战平台、以及自己维护的私有题库。它们抗污染、贴近真实分布,但成本高、难复现,不适合做逐版本对比。
实践建议:私有题库不用大,500~1000 条、覆盖你的真实流量长尾、永不公开,价值远超任何公开榜单。 它应该成为你的上线门禁。
6.3 人评与模型评:给你"分辨力"
开放式生成(写文案、做总结、答咨询)没有唯一答案,只能比较优劣。主流做法是 Pairwise 比较 + Bradley-Terry / Elo 打分:
- 每次给裁判两个回答,问"哪个更好";
- 用大量比较结果拟合每个模型的实力值(Elo 或 Bradley-Terry),得到可比的分数;
- Arena 的做法还会做风格控制,剥离"回答更长/更花哨"带来的偏好。
用人评太贵,所以工业界普遍用 LLM-as-Judge 替代。但直接拿一个模型当裁判,结论基本不可用——它有系统性偏差:

| 偏差类型 | 表现 | 对策 |
|---|---|---|
| 位置偏差 | 偏爱排在前面的回答 | 交换 A/B 顺序各评一次,只采纳一致的结论 |
| 长度偏差 | 更长、更分点的回答得分更高 | 用长度受控胜率;或 rubric 里写明"简洁也加分" |
| 自我偏好 | 偏爱同族模型的输出 | 换非本族裁判;多裁判投票 |
| 格式偏差 | Markdown 排版好就被判优 | 统一转纯文本再评 |
硬性要求:裁判上线前,必须与 100~200 条人工标注算一次一致率(Cohen's κ 或 Spearman)。κ < 0.6 的裁判不能用于对外结论,只能做内部粗筛。 这一步 90% 的团队都跳过了,然后拿着不可信的胜率做决策。
七、指标怎么选:先看任务类型,再谈数字

选错指标比选错模型更致命,因为指标决定你会优化出什么样的模型。
7.1 三个常见指标的坑
pass@k 不是准确率。 它的无偏估计是:
其中 n 是每题采样次数,c 是答对次数,C 是组合数。k=1 时它退化为准确率;k>1 时它测的是"k 次里有一次对就行"的能力上限,不能拿来说"模型准确率 90%"。
ROUGE / BLEU 是弱信号。 它们奖励"说得像",不奖励"说得对"。一个把错误答案用参考答案的句式说出来的模型,ROUGE 可能很高。只适合做基线,不能做结论。
胜率必须带置信区间。 500 条样本下,55% 胜率的 95% 置信区间大约是 [50.6%, 59.4%]——和 50% 没有统计显著差异。很多"XX 模型超越 YY"的结论就死在这里。
7.2 样本量怎么定
结论越细,样本要越多:
| 场景 | 最低样本量 | 说明 |
|---|---|---|
| 总体准确率(±3 分) | ~1000 | 1.96 × √(0.25/1000) ≈ 3.1% |
| 总体准确率(±5 分) | ~400 | 粗筛够用 |
| 分项/分学科结论 | 每项 ≥200 | 否则子项波动会盖过真实差异 |
| Pairwise 胜率(±5 分) | ~400 对 | 且要做配对检验 |
| Agent 任务成功率 | ≥100 个任务 × 3 次 | 方差远大于单轮任务 |
判读纪律:两组差异小于 2 倍标准误时,报告"打平",而不是"领先"。这条纪律能帮你避免 80% 的错误上线决策。
八、数据污染:最被低估的失效模式

这是评测里最脏也最普遍的问题。很多时候你不是在测模型能力,而是在测"这道题它见过没有"。
三条典型泄漏路径:
- 预训练语料直接收录:MMLU、GSM8K、HumanEval 的题目和解析在 GitHub 上到处都是,被抓进预训练数据几乎是必然的。
- 同源改写后混入训练集:同一题库的翻译版、扩写版、带 CoT 的版本进入 SFT 或蒸馏数据。n-gram 检测抓不到,但模型照样"背题"。
- 对着榜单反复调参:把公开测试集当验证集用。模型没背题,但对这套题过拟合了——这同样是一种污染,而且更隐蔽。
五种检测与规避手段:
- 13-gram 重叠检测:与训练语料做 n-gram 比对,召回有限但成本最低,适合做入门体检。
- 时间切割:只用模型训练截止日期之后发布的新题(LiveCodeBench、年度 AIME 就是这么做的)。
- 私有保留集:自建、不公开、不进任何公开语料,是最有效的手段。
- 变体扰动:换数字、换人名、改问法,看分数是否断崖式下跌。
- 困惑度异常检测:模型对某道题的困惑度显著低于同类题目,通常意味着见过。
一条经验判据:同一模型在公开集与"私有同分布集"上的分差超过 5 分,先怀疑污染,再怀疑能力。如果公开分很高但线上体感很差,几乎一定是污染或分布不匹配。
九、一条能落地的评测流水线

评测的价值不在跑分当天,而在每次改 prompt、换模型时,它能立刻告诉你有没有退步。所以要把它当工程系统建,而不是当实验脚本写。
9.1 七个步骤
- 定义任务与成功标准:把"好用"翻译成可判定的判定式。做不到这一步,后面全是自欺欺人。
- 分层抽样建评测集:按难度、场景、输入长度分层,保证长尾被覆盖(长尾往往才是线上事故来源)。
- 固化 prompt 与解码参数:system prompt、few-shot 数量与顺序、temperature、max_tokens 全部版本化。
- 批量推理:用 vLLM 或批处理接口,保证吞吐稳定。
- 答案解析与判分:规则解析 → 沙箱执行(代码)→ 裁判兜底(开放题)。
- 统计与置信区间:bootstrap 置信区间 + 配对检验。
- 报告与门禁:分项雷达图 + 失败案例 Top20,接进 CI 卡住回归。
9.2 最小可用的批量评测代码
# eval_runner.py
import re, json
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
SYSTEM = "你是一个严谨的助手。推理过程可以放开写,但最后一行必须用「答案:X」给出最终选项。"
TEMPLATE = "{question}\nA. {A}\nB. {B}\nC. {C}\nD. {D}"
def extract_choice(text: str):
"""只认最后一次出现,避免 CoT 里提到其它选项被误判"""
m = re.findall(r"答案[::]\s*([ABCD])", text)
if m:
return m[-1]
m = re.findall(r"\b([ABCD])\b", text)
return m[-1] if m else None
def run_one(sample: dict, model: str):
resp = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": TEMPLATE.format(**sample)},
],
temperature=0.0, # 评测必须确定性
max_tokens=1024, # 留足空间,截断会制造假错
seed=42,
)
choice = resp.choices[0]
text = choice.message.content or ""
return {
"id": sample["id"],
"gold": sample["answer"],
"pred": extract_choice(text),
"finish": choice.finish_reason, # length 说明被截断,要单独统计
"raw": text,
}
跑完之后,第一件事不是看准确率,而是看 finish == "length" 的比例。超过 1% 就说明 max_tokens 设置有问题,此时算出来的分数是假的。
9.3 置信区间与配对检验
import numpy as np
from statsmodels.stats.contingency_tables import mcnemar
def bootstrap_ci(correct, n_boot=10000, alpha=0.05, seed=0):
"""对逐题 0/1 结果做 bootstrap,返回 (均值, 下界, 上界)"""
rng = np.random.default_rng(seed)
arr = np.asarray(correct, dtype=np.float32)
idx = rng.integers(0, len(arr), size=(n_boot, len(arr)))
accs = arr[idx].mean(axis=1)
return float(arr.mean()), float(np.quantile(accs, alpha / 2)), float(np.quantile(accs, 1 - alpha / 2))
def mcnemar_test(correct_a, correct_b):
"""同一批题上比较两个模型:只有「一个对一个错」的题才提供信息"""
a, b = np.asarray(correct_a), np.asarray(correct_b)
n01 = int(((a == 0) & (b == 1)).sum()) # A 错 B 对
n10 = int(((a == 1) & (b == 0)).sum()) # A 对 B 错
res = mcnemar([[0, n01], [n10, 0]], exact=True)
return n01, n10, res.pvalue
p 值大于 0.05 的差异,在报告里就写"无显著差异"。这不是学术洁癖——这是防止你为了 1 分的噪声去付 3 倍推理成本。
9.4 LLM-as-Judge 的去偏实现
import json
JUDGE_PROMPT = """你是严格的评审。请比较两个回答对同一问题的质量。
问题:{q}
回答一:{r1}
回答二:{r2}
评分优先级:事实正确性 > 是否完整回应问题 > 简洁清晰。
不要因为回答更长或用了更多排版就给高分。
只输出 JSON,不要任何解释:{{"winner": "1|2|tie", "reason": "一句话"}}"""
FLIP = {"1": "2", "2": "1", "tie": "tie"}
def judge_pair(q, ans_a, ans_b, call_judge):
# 第一次:A 在前
v1 = json.loads(call_judge(JUDGE_PROMPT.format(q=q, r1=ans_a, r2=ans_b)))
# 第二次:交换顺序,再把 winner 映射回来
v2 = json.loads(call_judge(JUDGE_PROMPT.format(q=q, r1=ans_b, r2=ans_a)))
w2 = FLIP[v2["winner"]]
if v1["winner"] == w2:
return v1["winner"] # 两次一致 → 采纳
return "inconsistent" # 不一致 → 转人工或多裁判投票
def pass_at_k(n, c, k):
"""n: 采样次数, c: 答对次数, k: 取 k 次"""
if n - c < k:
return 1.0
return 1.0 - np.prod(1.0 - k / np.arange(n - c + 1, n + 1))
9.5 把门禁接进 CI
BASELINE = {"mmlu_pro": 0.712, "ifeval": 0.845, "swe_verified": 0.246}
TOLERANCE = 0.015 # 容忍 1.5 分波动
def gate(report: dict):
failed = []
for k, base in BASELINE.items():
cur = report[k]["acc"]
lo = report[k]["ci_low"]
# 下界跌破容忍线才拦,避免噪声误杀
if lo < base - TOLERANCE:
failed.append(f"{k}: {cur:.3f} (CI 下界 {lo:.3f}) < 基线 {base:.3f}")
if failed:
raise SystemExit("评测门禁未通过:\n" + "\n".join(failed))
print("门禁通过")
注意这里用的是置信区间下界而不是点估计——这样能自动容忍样本噪声,避免"今天跑 71.8 明天跑 72.2"就报警。
十、十个最常见的坑
- 样本太少就下结论。200 条样本上的 3 分差距,噪声占了一半以上。
- 只看总分不看分项。总分相同的两个模型,能力结构可能完全不同,选错一个就是灾难。
- prompt 没对齐。few-shot 数量、system prompt、选项顺序都会影响分数,横向对比必须用同一套模板。
- temperature 不等于 0,也没固定 seed。同一模型跑两次差 2 分,你就没法判断任何事。
- max_tokens 太小。答案被截断,判成错,分数系统性偏低。
- 答案解析器写得太严。模型答对了但格式是"(B)"而不是"B",被判错——你测的是 parser,不是模型。
- 只测英文、只测短问题。中文、长输入、多轮,是另外三个世界。
- 只测安全不测过度拒答。会奖励出一个"什么都不答"的模型。
- 忽略成本与延迟。能力涨 2 分、价格翻 3 倍、延迟翻倍,多数业务上这是净亏损。
- 没有基线快照。不记录模型版本与日期,三个月后你无法回答"到底是模型变了还是数据变了"。
十一、这个领域正在往哪走
- 从结果评测到过程评测:Agent 时代,只看终态对错信息量太低,步骤准确率、轨迹合理性、无效动作数会变成主指标。
- 从静态到滚动:LiveCodeBench 式的"按发布时间切分"会成为基准设计的事实标准;私有题库 + 定期换血会成为企业标配。
- 一致性比平均值更重要:pass^k 这类指标会普及——生产系统怕的不是"平均差一点",而是"偶尔崩一次"。
- 可验证奖励优先:能用规则验证的任务(代码、数学、结构化输出、工具调用)会被系统性优先评测,因为只有它们能规模化。
- 评测左移:评测集和 prompt 一起进版本库,每次 PR 自动跑,回归报警。评测从"季度报告"变成"每次提交的一部分"。
结语
回到开头那个问题:模型换了、prompt 改了,怎么知道变好还是变差?
答案不是"跑个分",而是:有一套四层齐全、带置信区间、抗污染、能接进 CI 的评测体系。它要求的工程量不大——一套 800 条的私有评测集、三个硬基准、一个双评裁判、一个 bootstrap 脚本,两三天就能搭起来。但它带来的决策质量提升,远超再花两周调 prompt。
评测不是训练的附属品,它是你唯一能看清模型行为的仪器。 仪器不准,后面所有优化都是盲调。
更多推荐

所有评论(0)