大模型评测
第 19 课:大模型评测
前一课我们把模型"发出去"服务了,也就能拿到一串跑分。这一课反过来问一件更要命的事:这些数字到底能不能信?一个分数背后藏着四层滤镜——它测的是不是你说的那个能力(构念效度)、答案有没有被背过(数据污染)、答案由谁打分(精确匹配还是 LLM 判官)、分数稳不稳(评测方差)。把四层看穿,你才能回答那个真正的问题:榜上的高分,为什么和我的真实体验对不上。这一课把评测的四个坑算清,最后给一套自建可信评测的流程。
② 用数字算出一分虚高里有多少来自污染、多少来自选项数、多少只是噪声
③ 给自己模型搭一套可信评测:定构念、防污染、校准判官、报置信区间、设发布门禁
上一课我们把模型「发出去」服务了,服务端会吐出一串跑分。这一张先回到跑分的源头:这些数字各自是从哪张考卷里来的、由谁来判。
因为「榜单上的分数」其实不是同一种东西——它是四张完全不同的考卷。就像学校里「语文 90 分、数学 60 分」,你不会直接说「语文比数学强」——两张卷子的题和判分方式都不一样。看榜要连问三件事:① 这张考卷喂给模型的是什么题(四选一 / 要写完整步骤 / 要跑代码 / 开放对话)?② 答案由谁来判(对选项 / 对数值 / 跑单元测试 / 真人投票)?③ 那它凭什么代表「能力」——换个问法还算数吗?这正是本课的主题构念效度。所以下面先把四张考卷摆在一起,再各算一笔账。
最常见的误读,是把「一次跑出的最高分」当成能力:同一个模型换个随机种子重跑,分数就会抖;而像 HumanEval 这种允许「生成 k 次、过一次算过」的指标,k 一大分数几乎必然逼近满分(单次通过率 p=0.3 时,pass@100 已 ≈ 100%)。所以看分必须先问:这是跑了几次的读数?
| 榜(基准) | 喂给模型的题 | 谁来判 | 测的是什么 | 一手来源 |
|---|---|---|---|---|
| MMLU | 57 个学科的四选一(约 1.4 万题) | 对选项字母 | 知识面 | arXiv:2009.03300 |
| GSM8K | 约 8.5K 道小学数学应用题 | 对最终数值 | 多步推理 | arXiv:2110.14168 |
| HumanEval | 164 道手写 Python 题 | 跑隐藏单元测试(pass@k) | 代码功能正确性 | arXiv:2107.03374 |
| Chatbot Arena | 真实用户随便问的题 | 真人两两盲投(BT 估计) | 人更喜欢哪个 | arXiv:2403.04132 |
| 项 | 数值 |
|---|---|
| 选项个数 | 4 |
| 纯随机猜的期望正确率 1 ÷ 4 | 25% |
| 设某模型 5-shot 得分(示例值) | 70% |
| 高出随机基线 | 70 − 25 = 45 个百分点 |
| 相对基线倍数 | 45 ÷ 25 = 1.8 倍 |
| 项 | 数值 / 定义 |
|---|---|
| 每题生成样本数 n(Codex 论文) | 200 |
| 论文用的无偏估计式 | pass@k = 1 − C(n−c, k) / C(n, k)(c = 通过的样本数) |
| 单题 c = 0(一次都没做对) | 任意 k 都 = 0 |
| Codex 的 pass@1 | 28.8% |
| Codex 的 pass@100 | 70.2% |
每张考卷都自带一个可被刷爆点,而它们都指向本课主题构念效度(这个测量,真的在测它声称的那件事吗?):
① MMLU:四选一有 25% 的猜测基线,分数里含「蒙对分」,考的是知识面,却掺了点排除法与运气。
② GSM8K / HumanEval:题目公开且发布于多年前,很可能已进训练语料——一旦靠记忆作答,分数就系统性虚高(数据污染,第 2 张卡片展开)。
③ Arena:分数来自真人投票,测的是「人更喜欢哪个」,会受投票人群(偏英语、技术用户)与「更长、排版更花哨」的风格偏好影响——它测的不是「谁更会做」(判官偏差在第 3 张卡片展开)。
所以看榜的顺序永远是:先认出是哪张考卷 → 再问它可能被什么刷高 → 最后才看分数。
上一张卡片拆开了分数里的"格式附加分"。这一张拆更隐蔽的一层:答案可能不是推出来的,是背出来的。
因为如果某道测试题(或它的改写版)出现在训练语料里,模型见到它时走的是"回忆"而不是"推理"——就像考前泄题:分数高不代表会,只代表见过。这类污染会系统性地把分数往上抬:那些看过的 token 序列已在训练里固化,模型不再需要现推;且不同模型被抬的幅度不同,于是"榜上谁高"就失去了可比性。所以下面先算"污染能让总分虚高多少",再看"怎么把它揪出来"。
更自然的做法是拿公开基准直接测、直接信总分——但题目公开且发布多年,很可能早已进了训练语料:靠记忆答对,卷面看着涨了几分,能力却一点没变(下一段的算例里,仅 20% 的题被见过就能白涨 5 分)。
| 组 | 占比 | 正确率 | 贡献 |
|---|---|---|---|
| 训练时见过(靠记忆) | 20% | 95% | 0.2 × 95 = 19.0 |
| 没见过(真实推理) | 80% | 70% | 0.8 × 70 = 56.0 |
| 卷面总分 | 100% | — | 75.0 |
| 污染的题占比 | 卷面总分 | 虚高(绝对分) |
|---|---|---|
| 20% | 0.2×95 + 0.8×70 = 75.0 | +5.0 |
| 40% | 0.4×95 + 0.6×70 = 80.0 | +10.0 |
| 污染层级 | 典型检测 | 能不能抓到 |
|---|---|---|
| 精确(题目原文照抄) | n-gram(连续 n 个词的片段)重合 / 字符串匹配 | 能 |
| 句法 / 语义(改写过) | 字符串匹配失效 | 抓不到 |
| 黑盒检测(如 CoDeC) | 加同分布上下文看置信度 | 可,论文自报 99.9% 数据集级 AUC(判别能力指标,1 为完美区分) |
污染不是"作弊被抓",而是评测的前提被悄悄破坏:你以为在测推理,其实在测记忆。防污染最稳的办法不是事后检测,而是事前隔离——用私有题集、动态生成题、或按时间切分(训练截止之后才出现的题)。检测是补救,隔离才是设计。
上一张卡片保证了题目干净。这一张处理下一个变量:同样的回答,由谁来判分。
因为开放生成没有唯一答案,打分器就成了评测的一部分。精确匹配最省事,但它只认逐字相同——就像判作文只数"和范文重复了几个字",写得更好但用词不同的反而被判错。所以工业界转向 LLM-as-a-judge(请强模型当裁判)。可裁判会偏心:它偏爱排在前面的答案(位置偏差)、偏爱更长的答案(冗长偏差)、还偏爱自己模型家族写的答案(自我偏好)——而 Semantic 相似度这类指标靠 embedding 比对,也各自有盲区。于是下面把这三种偏差各自量化一次。
更自然的做法是把「答对」定义成「和参考答案逐字相同」(精确匹配)——但这只认逐字一致:100 条回答里若有 30 条意思对、说法不同,它们会被全部判错,分数上限凭空少 30 个点。开放任务上,「判对错」本身就比「算对错」难。
| 项 | 数值 |
|---|---|
| 总题数 | 100 |
| 语义正确但表述不同的回答 | 30 条 |
| EM 只认逐字一致,判对的 | 70 条 |
| 被低估 | 30 个点(示意) |
| 项 | 数值 |
|---|---|
| MT-Bench 论文里 GPT-4 判官的换序一致性 | 约 65% |
| 即换序后判决改变的比例 1 − 0.65 | 约 35% |
| 每 100 对里会改判的 | 约 35 对 |
| 偏差 | 论文报告 |
|---|---|
| 冗长偏差(偏好更长的答案) | 判官与人类都偏好更长的回答(GPT-4 尤甚) |
| 自我偏好(偏向自己家族的答案) | GPT-4 约 10%、Claude-v1 约 25% |
打分器不是中立的尺子,而是评测的一部分。用 LLM 当判官前,必须做三件事:①换序取平均(消位置偏差)、②长度校正(消冗长偏差)、③避开自我评测(消自我偏好),并用一批人工金标校准它到底准不准(下一张卡片讲样本量,最后一张讲校准)。
上一张卡片解决了"判官偏心"。这一张处理最后一层随机性:就算判官完全公正,分数本身也不稳。
因为你不可能把所有可能的题都考一遍,只能抽一部分——抽到的题偏容易还是偏难,直接决定分数。就像只随机抽查 20 个客户的满意度去代表全公司:抽到谁,结果就差一截。所以"模型 A 比 B 高 2 分"很可能只是抽样运气。所以下面用标准误公式,把"差几个点才算真差异"算出来。
| 项 | 数值 |
|---|---|
| 题数 n | 1000 |
| 正确率 p(取最坏情况) | 0.5 |
| 标准误 SE = √(0.5×0.5/1000) | 1.58% |
| 95% 区间半宽 = 1.96 × 1.58% | ±3.1% |
| 题数 n | SE = √(0.25/n) | 95% 区间半宽 | 差 < 多少不可区分 |
|---|---|---|---|
| 1000 | 1.58% | ±3.1% | 约 6.2 点 |
| 100 | 5.0% | ±9.8% | 约 19.6 点 |
| 要分辨的差异 Δ | 所需题数 n ≈ 4×(1.96/Δ)²×p(1−p),p=0.5 → n ≈ (1.96/Δ)² |
|---|---|
| 5 个点 | (1.96/0.05)² ≈ 1,537 题 |
| 3 个点 | (1.96/0.03)² ≈ 4,268 题 |
"跑三遍差几个点"这个问题的答案不是一个数,而是一条公式:n 越小、p 越接近 0.5,噪声越大。凡是要下"谁更强"的结论,先问三件事——题数多少、区间多宽、两个区间有没有重叠。没有置信区间的排名,本质上是在比较两团噪声。
上一张卡片让"差几个点才算真差异"变得可算。这一张用它来解释那个最普遍的困惑:榜单选出来的模型,用起来却不如人意。
因为榜单做了一次"等权平均"的聚合,而你的业务从来不是等权的——就像按"全国平均气温"决定今天穿什么,你在哈尔滨就该棉袄、在三亚就该短袖。平均分掩盖了分布:你的流量分布、你喂给模型的 context、你的领域占比,恰恰是榜单看不见的那部分。所以下面用一个具体算例,演示"等权排序 A 更高、按你流量加权后 B 反超"。
更自然的做法是照榜单名次选模型——但榜单把各领域等权平均,你的流量却可能 70% 压在代码与客服上:等权下领先 5.5 分的模型,换一组权重后会以 0.8 分被反超。
| 领域 | 模型 A | 模型 B |
|---|---|---|
| 代码 | 70 | 82 |
| 客服 | 74 | 80 |
| 通用知识 | 90 | 72 |
| 数学 | 92 | 70 |
| 等权平均 | (70+74+90+92)/4 = 81.5 | (82+80+72+70)/4 = 76.0 |
| 领域 | 你的流量占比 | A 贡献 | B 贡献 |
|---|---|---|---|
| 代码 | 40% | 0.4×70 = 28.0 | 0.4×82 = 32.8 |
| 客服 | 30% | 0.3×74 = 22.2 | 0.3×80 = 24.0 |
| 通用知识 | 20% | 0.2×90 = 18.0 | 0.2×72 = 14.4 |
| 数学 | 10% | 0.1×92 = 9.2 | 0.1×70 = 7.0 |
| 加权总分 | 100% | 77.4 | 78.2 |
| 项 | 数值 |
|---|---|
| 加权后 A / B 差 | 78.2 − 77.4 = 0.8 分 |
| 1000 题时的可分辨阈值(承上卡) | 约 6.2 分 |
| 结论 | 0.8 < 6.2 → 不可区分 |
榜单失配有三重原因:①等权聚合掩盖了分布(你的流量不是等权的)、②对齐税(榜测知识、不测有用性)、③污染与噪声叠加。结论:榜单只能当"初筛",不能当选型依据。选型的最后一步永远是你自己领域上的评测——这正是下一张卡片要给的流程。
上一张卡片说明榜单不能替代你的场景。这一张把前面所有结论收成一套你能立刻搭起来的流程。
因为可信评测的每一步都是在堵一个具体的坑:堵"测错东西"就写清构念、堵"背过答案"就用私有集(把评测题与训练 token 流彻底隔开)、堵"判官偏心"就人工金标校准、堵"噪声当提升"就报置信区间。就像上飞机前的检查清单——单看每一项都很小,但漏掉任何一项都可能让结论失效。所以下面把最关键的三步——样本量、判官校准、发布门禁——各算一个数。
| 要分辨的差异 | 所需题数 | 适用 |
|---|---|---|
| 5 个点 | ≈ 1,537 题 | 粗筛 |
| 3 个点 | ≈ 4,268 题 | 上线决策 |
| 项 | 数值 |
|---|---|
| 抽检比对条数 | 200 条 |
| 判官与人工一致条数 | 156 条 |
| 一致率 | 156 ÷ 200 = 78%(示意) |
| 门禁条款 | 要求 |
|---|---|
| 同一条件下比 | 同一私有集、同一提示模板、同一解码参数 |
| 提升要过噪声 | 相对基线 ≥3 个点 且 95% 区间不重叠(3 点阈值对应约 4,268 题,题数不足就改用 5 点门槛) |
| 报告口径 | 分数 ± 95%CI + 题数 + 提示版本 + 日期 |
到此,"训练与推理工程"这条线收口——从怎么训、怎么省、怎么调、怎么发,到怎么证明它真的变好了。评测不是训练结束后的一个动作,而是贯穿始终的一条门禁。下一部分我们进入 Agent 工程:从"一次问答"到"一次循环",那会带来全新的评测对象——不再是一个答案,而是一条轨迹(归第 25 课)。