
如果你已经花了几个月时间折腾数据集清洗、LoRA 微调、分布式训练结果模型一上线连你自己都说不清它到底比 base 强在哪那我建议你停下来认真读一读这篇。LLM 训练做到后期真正拉开差距的往往不是训练脚本写得多花哨而是评测体系稳不稳。这一节 Lab 15咱们不讲炼丹专门把“怎样评测模型好坏”这件事拆开聊透基准怎么选数据污染怎么防以及怎么让评测流程做到可复现、可追溯、经得起别人质疑。我先说一个可能不太好听的事实国内很多团队的评测其实是“表演型评测”。找一个榜单跑几个熟人指标挑最好看的结果写进汇报里剩下的日志删掉。这种玩法在模型规模小、内部试用的时候没有问题可一旦你要把模型推向真实业务、或者开源出去评测不严谨带来的反噬会非常快——别人复现不出你的分数数据污染被扒出来甚至只是评测集和微调集来自同一个源头都足以让整个模型的可信度归零。所以评测不是训练结束后的收尾动作它应该是和训练并行设计的一等公民。1. 为什么说评测是 LLM 训练中“最容易被低估”的环节1.1 评测决定你下一步改哪里先说最实际的一点评测的直接产出不是分数而是下一步的动作方向。比如你在做指令微调训练完发现 MMLU 涨了 2 个点但 GSM8K 掉了 4 个点这说明什么说明 SFT 数据里数学推理类样本比例不对或者 LoRA 的 rank 设置让模型在推理任务上发生了灾难性遗忘。如果你只跑一个综合榜单看一个总分这 2 和 -4 就被平均成 -1 了你会得出“模型差不多没变”的错误结论错过修正数据配比的机会。我自己习惯把评测当成一次“系统体检”不是抽血化验一个指标就完事而是分系统查知识储备查 MMLU、C-Eval推理能力查 GSM8K、MATH、BBH代码能力查 HumanEval、MBPP长文本理解查 LongBench指令跟随和真实性另建一组内部集。每个方向独立出报告改哪里一目了然。1.2 评测不严谨的代价是链式放大的评测体系不严谨坑的不止是当前版本。你的 checkpoint 选择、LoRA 超参、数据配比全部依赖评测分数做决策。如果评测集本身有偏差、评测脚本有 bug、或者温度参数没有固定你选出来的“最优 checkpoint”可能只是一个噪声尖峰。更麻烦的是这个不严谨的分数会被写进实验记录、项目周报、开源模型卡Model Card。等模型部署到线上用户反馈和你的评测结果对不上你再回头排查才发现是评测时 prompt 模板写错了——这种问题在真实项目里一点也不少见。所以我的原则是评测脚本的代码审查严格程度至少和训练脚本一样高。2. 基准怎么选理解每一个分数的“适用半径”2.1 主流基准各自在测什么很多人对基准的认知停留在“MMLU 测知识GSM8K 测数学”这话对但太粗了。我按实际使用经验把常用的公开基准重新梳理一遍MMLU / MMLU-Pro57 个学科的多选题覆盖人文、社科、理工等。它测的是“知识广度和基础理解”但注意它是 4 选 1存在约 25% 的猜测保底分数。MMLU-Pro 提高了选项数量和干扰项难度能更好拉开模型差距缺点是题目更少、更不稳定。C-Eval / CMMLU中文综合基准。C-Eval 包含 13948 道题覆盖 52 个学科是目前中文评测绕不开的基准。但它的 few-shot 设置敏感度很高我实测下来 0-shot 和 5-shot 的分数能差出 10 个点以上评测时必须在报告里写明 shot 数。GSM8K / MATH数学应用题与竞赛题。GSM8K 侧重多步算术推理MATH 难度高一个档次。这两个基准对 CoT 提示非常敏感评测时用 chain-of-thought 还是直接答案结果天差地别。HumanEval / MBPP代码生成。HumanEval 是 164 道函数补全题用 passk 评估。这里有个经典坑passk 是估算指标官方脚本用了截断正态概率估计并不是简单地在 k 个样本里有多少通过。很多人直接算 pass1忽略了采样温度对通过率的影响。BBHBIG-Bench Hard从 BIG-Bench 里挑的 23 个困难任务测的是组合推理、逻辑、多步处理。它比 MMLU 更能区分顶级模型的推理能力但同样对 few-shot 模板敏感。LongBench长文本理解基准包含单双文档问答、摘要、代码补全等 14 个任务。如果你的模型改了 RoPE 基频、扩了上下文窗口必须跑这个它测的是真实的长文本利用能力不是“能读多长”而是“长了之后还能不能答对”。2.2 一个基准组合的默认配方我开源过自己的内部评测配方给中小团队做参考不需要对所有公开基准都跑一遍优先跑一套“组合拳”通用知识MMLU5-shotMMLU-Pro5-shotC-Eval5-shot中文 推理GSM8K8-shot CoTMATH4-shot CoTBBH3-shot 代码HumanEvalpass1temperature0.2MBPPpass1 长文本LongBench0-shot按它官方设置 指令跟随内部 200 条集合后面讲怎么建 中文场景CMMLU5-shot 自己业务场景的评测集这套组合跑一轮大约耗时 2~6 小时看模型和 GPU信息量已经足够支撑绝大多数训练决策。千万别贪多评测集跑太多时间成本会严重挤占真正该用的“人工审查案例”环节。2.3 少样本设置、提示模板这些“看似琐碎”的参数必须写进评测报告为什么同一个模型同一个公开基准不同人跑出来的分数不一样除了随机种子最大的变量是评测时的 prompt 模板。比如 GSM8K有人直接给题目让模型答有人用官方的 CoT few-shot 模板还有人用自己写的“让我们一步步思考”模板——三者分数能差 5~8 个点。这不算作弊但说明评测分数无法脱离设置而存在。所以我在评测报告里强制固定这几项基准名称、数据版本、shot 数、是否有 CoT 提示、温度、top_p、最大生成长度、并发数因为并发会影响显存分配导致的推理波动。没有这些信息的分数一律视为无效。3. 数据污染你以为在测知识其实在测“记忆”3.1 数据污染的两种面孔数据污染这个问题在 2023 年之前大家重视程度还不够直到很多模型的训练数据里被扒出包含测试集内容整个行业的评测可信度才被摆上台面。污染分两种一种是无意的你爬的网页语料里本身就包含了 MMLU 的题目和答案另一种是刻意的为了让分数好看把测试集放进训练集或者 SFT 数据里。后者已经不是技术问题而是学术道德问题我不展开但前者的普遍性远超大多数人的想象。我举个例子。你在爬 GitHub 上代码仓库的时候很可能顺手把含有 HumanEval 题目的测试文件也爬进去了。就算原仓库只是“讨论”或“备份”这个文件模型在预训练阶段见过这些内容评测时就会通过记忆路径做对题而不是通过真正的代码推理。最终结果是分数虚高上线后一遇到真实代码任务立刻原形毕露。3.2 怎么检测数据污染四个实用手段如果你怀疑自己的预训练语料或 SFT 数据可能和评测集有重叠我常用的检测手段有四种按成本从低到高排序N-gram 重叠扫描把评测集的每道题切成 8-gram / 13-gram 的 token 序列去训练语料里做近似匹配。如果题目有连续的 13 个 token 能在训练集里找到完全一致的片段基本可以判定存在重叠。这个方法成本低适合前置筛查。困惑度Perplexity测试把评测集题目输入模型如果模型对测试集文本的困惑度显著低于它对普通同领域文本的困惑度说明测试文本很可能出现在训练阶段。这个方法不需要训练语料操作最方便但只能定性。记忆探测直接让模型续写某道题的开头看它能不能“背”出后续内容。如果它生成的文本和标准答案高度一致说明存在记忆。这个适合抽查不能全量做。时间线切割如果你的训练语料按时间做了归档可以按时间切训练集和测试集。比如 2023 年 6 月之后的文本不进预训练评测时用这个时间之后的题目。这是最可靠的手段但对数据管线要求很高。3.3 给开源模型做评测前先做“防污染筛查”这里有个特别容易被忽略的场景你现在评测的模型大多是从开源 base 模型继续训练的base 模型本身可能已经被污染了。换句话说即便你完全没有把测试集放进自己的 SFT 数据你的 base 在预训练阶段可能早就见过 MMLU 题目了。所以你评估“你的微调增量”时必须同时跑一遍 base 模型的分数然后看差值和相对变化而不是只报绝对值。3.4 定期刷新测试集动态评测是未来静态基准的生命周期会越来越短因为互联网文本里关于这些基准的讨论文章、题解、博客会不断增长今天干净的数据明年可能就脏了。我的做法是保留一套内部“动态基准”每季度人工编写 200~300 道新题目涉及业务关键能力题目用加密存储不进任何训练流程连参与编写的人都签保密协议评测脚本支持只更新题目、不更新代码分数与历史结果做对齐校准当然这个成本不低但如果你做的是垂直行业模型法律、医疗、金融动态基准几乎是必需品因为你不能指望通用公开基准能测出你的业务正确性。4. 可复现评测流程从我到我们从结果到证据4.1 一套标准的评测工作流长什么样可复现不是说“我记录了命令下次能跑出来”而是“另一个人拿着你的说明能复现出完全一致的数字”。我给自己项目定的标准评测流程是这样准备阶段校验评测集版本用哈希值固定冻结模型 checkpoint保存 tokenizer 配置、模型配置、权重文件的哈希固定评测配置脚本版本、依赖版本、GPU 型号然后写一个评测清单文本。执行阶段用统一的评测入口跑任务日志输出每道题的结果而不是只输出汇总分数。每个任务记录开始时间、结束时间、耗时、显存峰值、异常日志。归档阶段汇总数据生成报告包含提交哈希、评测日期、硬件环境、每个基准的配置、逐题结果文件JSONL、汇总表格、异常说明。上传到内部实验管理系统关联到对应的训练实验。4.2 评测脚本和训练的耦合一个常见的“假复现”陷阱很多团队说“我的评测可以复现”但评测脚本的依赖库是 pip install 的时候顺带装的比如 transformers 和 vllm 的版本在三个月后早就变了那时候再跑采样结果会对不上甚至 inference API 都变了。我踩过这个坑后来强制要求用固定镜像或 requirements-lock.txt锁定 transformers、tokenizers、datasets、peft、vllm、lm-eval 等关键包的精确版本把评测执行代码 Docker 化镜像标签写入评测报告凡是涉及“评测结果对比”的实验尽量在同一批硬件、同一镜像下跑完跨硬件跑要单独做对齐验证4.3 采样参数“差一点”结果差很多可复现评测还有一个很脏的坑生成时的随机性。llm 的推理采样默认有随机性即使你设置了 temperature重复跑两次也会因为不同的随机种子得到不同的生成结果。所以评测任务必须固定 seed并且最好设置成开 deterministic如 vllm 的--seed参数。我习惯每个任务固定 seed42并且把 seed 写在报告里。另外注意有些推理框架为了保证并发效率默认会动态 batchingbatch 内样本顺序变化会导致部分归一化算子产生细微差异从而影响结果。所以真正严格的可复现评测我用单卡串行或者固定 batch 的组合牺牲一点速度换确定性。4.4 评测结果三级存档而不是只留一个数字我参与过几次模型评测体系的内部审计发现大多数团队对评测结果的管理都极为松散。最常见的形态是一张 Excel 表几列分数连日期都没有。这样做的后果是三个月后你想分析“为什么这个 checkpoint 好”你拿不到当时用了哪个版本的测试集和 prompt只能重新跑一次然后发现分数和当时对不上又怀疑是不是模型文件有问题——全套流程都在内耗。所以我建议至少做三级存档原始运行产物每道题的输入输出 JSONL、运行日志处理后的汇总数据按基准、按 seed 汇总的 score 表人类可读报告对比图、结论、决策说明三级数据分别存储权限分离。只有汇总表可以被修改原始产物只读。这样即使有人想“调整”结论也能追溯到底层。5. 搭建一套低成本、可复现的评测环境5.1 直接选择一个成熟的评测框架别自己造轮子实测下来最稳的是以下三个各有侧重lm-evaluation-harnessEleutherAI最普及支持几百个公开基准自定义任务也方便。它的 YAML 配置方式值得学习能把 prompt 模板、few-shot 设置、评测指标都固定在一个文件里。这也是我做所有公开评测的基础。OpenCompass上海人工智能实验室中文和 Code 评测支持更好集成了评测结果的可视化、模型对比适合做中英双语模型的横向评测。HELM斯坦福重在“多维度、多场景”强调评测标准化和覆盖度更适合做研究型全量评测工程上使用成本略高。如果你没有特殊需求我直接推荐 lm-eval-harness 自己的评测集管理仓库。它的学习曲线平缓环境隔离干净社区更新也快。5.2 用 YAML 固化评测任务做到“配置即文档”lm-eval-harness 的 YAML 任务配置非常能打我把它视为评测复现的核心。一个任务配置里你固定了数据集名称、数据集路径、prompt 模板、shot 数、评测指标、tokenizer 相关设置。举一个最小的 GSM8K 配置示例task: gsm8k dataset_path: gsm8k dataset_name: main output_type: generate_until test_split: test fewshot_split: train num_fewshot: 8 doc_to_text: Question: {{question}}\nLets think step by step.\n doc_to_target: {{answer}} generation_kwargs: do_sample: false temperature: 0 max_gen_toks: 1024 metric_list: - metric: exact_match这段配置表达的信息量比你写 2000 字评测说明文档都要高。因为它不只是“文档”它是直接被执行的文件。我要求团队所有评测任务的 prompt 修改必须走 MR 评审合入后自动触发一轮全量回归确保改 prompt 的副作用是被记录的。5.3 评测集管理版本、权限、血缘评测集本身也是需要治管的。我最开始的做法简单粗暴——就是一个目录里面放几个 JSON 文件带日期命名。直到有一次我发现自己同时存在两个版本的“内部指令测试集”一个叫instruction_v2_final.json另一个叫instruction_v2_final_final2.json就知道必须换了。目前的做法是用一个独立的 Git 仓库管理评测集每次更新走版本 tag并使用哈希校验。任何评测报告必须记录评测集仓库的 commit 号和文件哈希。如果你不想用 Git 这么麻烦至少做到评测集目录只读部署对外提供一个带文件哈希的清单文件。5.4 预算不够时先用“黄金集 抽查”策略并不是所有团队都有资源跑全量基准。如果你卡在算力不足我有一个折中策略构建一个 500 条以内的小型“黄金集”覆盖你业务最关心的 8~10 个能力维度每条题目都是精心挑选或人工编写的。黄金集跑一轮只要几分钟适合做迭代中快速反馈全量公开基准每周或每个里程碑跑一轮作为对外宣发和模型存档依据。评测不是越全越好而是越稳越好——稳定、可解释、低成本才能持续跑下去。6. 我以为我稳了结果评测翻车的三个真实案例6.1 案例一并发一开分数悄悄变了有一次我开开心心地用 vllm 的并发跑 LongBench对比上一周的分数发现长了 3 个点。一开始以为是新 checkpoint 更强后来为了确认又关了并发跑了一遍结果掉回原位。原因就是动态 batching 改变了某些样本的 normalize 结果。从那以后我学到一条规矩对比实验结果必须用完全相同的推理设置并发模式也算设置之一。6.2 案例二SFT 数据里藏了测试集题目这个案例尤其值得警惕。一次我在做领域模型的指令微调用了一批从行业论坛爬来的帖子。后来评测时发现模型在内部金融问答测试集上得分异常高高到不像一个 7B 模型能做到的。排查后发现爬取的网页里恰好包含了某平台发布的“金融大模型测试题”讨论帖题目和答案都在里面。这不算恶意但结果已经失真。最后我把这批数据全部重新清洗过滤才得到正常分数。这件事给我的教训是SFT 数据的清洗流程里必须加一道“测试集题目过滤”的检查绝不能假设外部数据源是干净的。6.3 案例三小模型跑出了不可能的高分还有一次我在评测一个 LoRA 微调后的 7B 小模型它的 MMLU 分数比同量级模型高出一大截。第一反应是开心第二反应是怀疑。逐题检查后才真相大白评测脚本用的 model 配置里误加载了未经冻结的 base 模型权重导致实际推理的并不是我微调后的 checkpoint而是一个混血的权重状态。分数当然不对。这个 case 让我强制要求评测前先跑一遍“权重哈希校验”确认加载的权重文件 MD5 和训练产物记录一致。后面我还在评测脚本里加了“防呆断言”逻辑如果模型参数量和我期望的不一致、如果 tokenizer vocab 数量和配置不一致直接报错中止不产出分数。宁可跑不出来也不能让错误的分数流转到下游。7. 把评测报告写成人话最后这点很多人容易忽略但也是评测价值的最终落点。写评测报告尤其写给你团队里不搞训练的人看的时候别一上来就贴 MMLU 的雷达图你要先回答三个问题这个模型比我上一版强在哪它做不好什么暴露了什么短板这次的评测结论下一轮训练该怎么改我见过写得很好的评测报告开头就一句话“v2.3 模型在数学推理上比 v1.9 提升了 5.1%但代码生成的可运行率下降了推测是 SFT 数据中代码与 CoT 的比例失衡下一步准备调整数据配比。”这句话比十个表格更有决策价值。我现在写评测报告的标准模板是三段式先说关键结论一句话再到证据数据和图表最后给出下一步动作含明确的测试假设。整个过程不允许出现“感觉变好了”“好像差不多”这类词。评测这件事做到后面拼的不是上不上 80 分而是能不能每一次都清楚地回答“为什么是这个分数”。你只要把基准的选择逻辑、污染防护流程、可复现环境搭建这三件事做扎实你训练出来的模型就经得起别人的推敲也经得起自己三个月后回头看。这套环境下一次再训新模型的时候你真会发现评测报告从“交差用的”变成了“真正帮你做决策的那个东西”。