模型评测:Benchmark与自动化回归测试实战
专栏:AI/LLM工程化实战 - 从Prompt到Agent的完整落地指南
模块6 模型微调与部署篇 第63篇
摘要
摘要:模型评测决定微调成败,MMLU/GSM8K/C-Eval三大Benchmark各测一种能力,离线评测看固定题集得分,在线评测看真实流量,lm-evaluation-harness一条命令跑分,自定义评测集加CI回归报警把质量守住,本专栏限时¥59.90(原价¥99)
TL;DR 核心要点速览
- MMLU测57个学科的综合知识,选择题形式,5-shot是公认标准配置,0-shot会让分数掉10个百分点
- GSM8K测小学数学多步推理,答案可自动校验,一个任务就能当回归哨兵
- C-Eval是中文Benchmark,52个中文科目,国产模型选型的必跑项
- lm-evaluation-harness 0.4.x一条命令跑完主流Benchmark,1.5B模型跑MMLU子集约40分钟
- 离线评测用固定题集求可复现,在线评测用真实流量求真实,两者各管一段
- 自定义评测集要把业务规则写成可判分的标准,规则打分免费可复现,GPT打分贴近人评但花钱
- 回归测试接进CI,每次发布前自动跑分,得分下降超阈值自动报警到群,MMLU阈值2个点,自定义评测5到8个点
- 评测分数会被few-shot口径、数据泄漏、采样方差骗到,对比前先统一口径
- 本专栏限时¥59.90(原价¥99)
开篇故事:上线前夜被差评打醒
我负责的客服机器人做完一轮微调,业务方催着上线。我挑20个常见问题跑了一遍,模型回答得像模像样,就签了发布单。第二天用户投诉率翻了一倍,群里全是截图,说机器人答非所问,'退货运费谁承担’这种高频问题开始胡说八道。我翻出那20个问题一对比才发现,它们全是我自己顺手的场景,模型把训练集里的话术背了下来,换个问法就露馅。当晚我在工位上把评测流程从头设计了一遍,从Benchmark跑分到自定义业务评测,再到每次发版前的自动回归。这套东西后来拦住过一次事故,也成了这篇要讲的内容。
回头想想,那次翻车最伤人的是团队对评测的信任崩塌,用户投诉倒排第二。业务方问我,你们说测过了,测的什么?我拿不出一个能说服人的数字。从那以后我给自己立了条规矩,任何模型上线,必须带着三样东西,Benchmark跑分、自定义评测得分、回归对比记录,缺一样不上线。这条规矩现在写进了部门的发布检查单,后来每个新人都受益。
一、三大Benchmark:MMLU、GSM8K、C-Eval各测什么
1.1 MMLU:知识广度的体检报告
MMLU全称Massive Multitask Language Understanding,用57个学科的选择题考察知识面,从高中物理到法律伦理都有。模型要5-shot答题,题面先给5个示例,再让模型选答案。为什么固定5-shot,因为给0个示例和给5个示例,同一个模型的得分能差出10个百分点,大家约定俗成用5,分数才可比。我见过团队直接拿默认参数跑,然后拿分数和别人对比,实际上口径完全不一致。跑分之前先确认num_fewshot,这是对比的地基。
MMLU的题目全是单选题,模型只需要输出一个字母或答案文本,判分逻辑简单,所以它跑得快、争议少。但选择题测不出生成质量,模型选对答案和说人话是两回事,这一点后面还会讲。
MMLU还有一层隐藏用途,监控数据泄漏。如果某次评测换模型时,新模型的MMLU得分高得反常,先别高兴,查它是不是见过题。业内流传过好几轮刷榜事件,某个模型的MMLU分数高到不合理,后来证实训练语料里混进了评测题。跑分前用一篇独立的新闻报道做抽查,模型能答出训练截止日期之后的新闻细节,基本可以断定语料有问题。
1.2 GSM8K:推理能力的标尺
GSM8K是8000多道小学数学应用题,考察多步算术推理,比如"小明有3个苹果,又买了2倍,再送人1个,还剩几个"。它的价值在于答案是一个具体数字,程序就能自动校验,不需要人眼打分。GSM8K很适合放进自动化回归里当哨兵,得分下降就是推理能力退化的直接信号。
1.5B模型的GSM8K得分通常在0.35到0.45之间,7B模型能到0.6以上。我见过全参微调把GSM8K从0.45打到0.20的案例,这种级别的退化用肉眼看对话样例很难发现,跑一次分立刻现形。注意GSM8K的少样本示例是内置的,跑lm-eval时不用自己传,但不同评测框架的模板可能有差异,跨框架对比要谨慎。
GSM8K还有一个衍生用法,配合温度参数做推理稳定性测试。我把temperature从0调到1,跑同一批题,得分波动超过0.1说明模型在推理上不稳定,生产环境会表现为同一个问题时而答对时而答错。我的回归脚本里固定temperature=0,只让prompt和权重变化,这样才能把变量隔离出来。
1.3 C-Eval:中文世界的入场券
C-Eval是国内团队做的中文评测,52个科目覆盖人文、社科、理工,全部中文出题。国产模型发布时都会贴C-Eval分数,选型阶段先看它。C-Eval分验证集和测试集,测试集答案不公开,跑分要按官方脚本走,拿验证集分数当测试集分数宣传属于业内常见乌龙。C-Eval对中英混用能力敏感,英文基座模型在C-Eval上明显吃亏,这也是判断模型中文底子的快速办法。
C-Eval的科目里有大量需要领域知识的题,医学、法学、计算机都有,适合快速定位模型的知识短板。我选型时会同时看C-Eval和MMLU,英文模型MMLU高、C-Eval低,说明中文语料占比少,需要补中文数据。国产模型两个分数都高,说明双语训练做得好。单看一个分数选型,容易漏掉语言能力的短板。
1.4 四个评测放到一张表里比
| 维度 | MMLU | GSM8K | C-Eval | 自定义评测 |
|---|---|---|---|---|
| 测什么 | 57学科综合知识 | 小学数学多步推理 | 52科中文知识 | 业务规则与真实场景 |
| 题目形式 | 四选一选择题 | 应用题,答案可校验 | 中文选择题 | 业务问答与生成任务 |
| 适合谁 | 模型选型、通用能力体检 | 推理能力验证、回归哨兵 | 中文场景、国产模型 | 上线前的最后把关 |
| 运行成本 | 1.5B单卡约40分钟(子集) | 便宜,10分钟内 | 与MMLU相当 | 构建成本高,运行几乎免费 |
| 局限 | 选择题不反映生成质量 | 只测算术,覆盖面窄 | 中文选择题,与业务脱节 | 只代表你定义的能力 |
这张表按团队阶段选,不必四个都跑。起步期只跑MMLU加GSM8K,了解模型底子。业务期加自定义评测,守住上线线。成熟期补C-Eval和在线评测,覆盖中文和真实分布。预算和人力紧张时,自定义评测优先于C-Eval,业务线比通用线更贴近你的收益。
二、离线评测与在线评测:两条腿走路
评测和训练的关系要先摆正。评测从数据准备阶段就要开始,贯穿整个训练和部署周期。数据清洗完先跑一轮基线评测,选好模型再跑一轮,训练中每个checkpoint跑轻量回归,训练完跑全套,上线后持续监测。五轮下来,每次改动都有分数对应,出问题能快速定位到是哪一步引入的。
2.1 离线评测:固定题集,求可复现
离线评测用一套固定不变的题集,每次跑完得到一组数字,存进文件。它的价值在可复现,今天跑和三个月后跑,同一模型同一配置,分数应该一样。我维护一个评测仓库,题集、脚本、配置都进git,每次跑分固定版本号。可复现是回归测试的前提,分数没法复现,报警就无从谈起。评测集本身也要纳入版本管理,谁加了题、删了题都有记录,防止有人偷偷改题把分数刷上去。
2.2 在线评测:真实流量,抓漂移
离线题集再贴近业务,也是人造样本。真实用户的问题分布会变,今天问退款的占三成,下周问发票的占四成。在线评测就是每天从线上日志里采样一批真实问题,跑一遍评测脚本,把得分和离线得分放一起看。我习惯在线上日志里按问题类型分层抽样,保证每个类型都有样本,抽300到500条就够统计了。在线评测的判分和离线共用同一套标准,只有题源不同,这样两组数字才有可比性。
在线评测的样本标注是人力活,抽300条题,每条要人工判一次对错。我建了一个每周30分钟的标注轮值,团队每个人轮流判,判分标准挂在群里,分歧样本当场讨论。标注结果直接回写评测库,积累三个月就是一份真实的线上分布档案,训练数据重采样时直接从这里取。
2.3 评测频率怎么排
我现在的节奏是三层,模型发布前跑全套Benchmark加自定义评测,每周跑一次在线采样评测,每次发版前跑回归哨兵。发版前的回归只跑轻量集,比如GSM8K加20条业务题,10分钟出结果,不会拖慢发布节奏。整套流程跑下来,一天约1小时算力,换来的是一旦模型退化当天就能发现,用不着等用户骂上门。
2.4 评测基线:全组的共同记忆
评测基线是一组固定的参考分数,存成JSON放在评测仓库里,全组共用。基线的建立时机是模型第一次通过验收的时候,那次跑出来的分数就是基线。之后每次改模型、改prompt、换参数,都以基线为参照。基线文件只允许评测负责人更新,其他人改不了,防止有人为了过回归把基线调低。我遇到过一回,回归报警天天响,排查半天发现是有人偷偷把基线里的MMLU分数改高了0.05,报警阈值跟着失效。现在基线文件加了权限控制,改动留痕,谁改的、为什么改都有记录。
评测基线也要应对版本升级,lm-eval升级、transformers升级都可能让分数整体平移。我每次升级评测框架,都会用当前生产模型重跑一遍全套,新旧框架的分数差异记录在案。差异超过2个点,说明框架变更引入了口径变化,基线要重打,并且通知所有依赖基线的人。框架升级后第一次跑分,永远先和旧框架结果对比,再谈模型好坏。
三、用lm-evaluation-harness跑MMLU子集
自己写评测脚本并不难,难的是把几十个Benchmark的few-shot配置、判分逻辑、模板全部统一,这些细节lm-evaluation-harness已经替你处理好了。它维护了每个任务的少样本示例和判分函数,还支持hf、vllm、openai等多种后端。0.4.x版本接口稳定,社区还在持续修模板bug,比自研划算。
lm-evaluation-harness是HuggingFace维护的评测框架,0.4.x版本用lm_eval这个包,命令行和Python接口都支持。下面脚本跑MMLU的STEM子集加GSM8K,把结果存成JSON,给后面的回归脚本用。
# 63_eval_harness.py# 用lm-evaluation-harness跑MMLU子集和GSM8K,结果存JSON供回归脚本对比# 安装: pip install lm-eval==0.4.7 transformers accelerate# 运行: python 63_eval_harness.pyfromlm_evalimportsimple_evaluateimportjson# 模型参数,trust_remote_code=True是因为Qwen系列需要读自定义代码model_args="pretrained=Qwen/Qwen2.5-1.5B-Instruct,trust_remote_code=True"# simple_evaluate返回一个dict,results键下面按任务名存各指标# mmlu_stem是MMLU的子集,约2200题,1.5B模型单卡约40分钟# num_fewshot=5是MMLU的标准配置,换成0会让分数掉一大截,对比时必须固定results=simple_evaluate(model="hf",# 用transformers的AutoModel加载model_args=model_args,tasks=["mmlu_stem","gsm8k"],num_fewshot=5,batch_size="auto",# 自动选batch,显存小就改成具体数值device="cuda:0",# 没GPU可以去掉这行,用CPU跑,时间翻几倍)# 0.4.5版本把指标key从acc,none改成了acc,nf,两个都兜底取scores={}fortask,metricsinresults["results"].items():acc=metrics.get("acc,nf",metrics.get("acc,none"))scores[task]=accprint(f"{task}:{acc:.4f}")# 保存成标准格式,回归脚本按任务名读取withopen("eval_result.json","w",encoding="utf-8")asf:json.dump({"scores":scores},f,ensure_ascii=False,indent=2)跑完会在终端打印两个分数,同时生成eval_result.json。命令行版本等价于lm_eval --model hf --model_args pretrained=Qwen/Qwen2.5-1.5B-Instruct --tasks mmlu_stem --num_fewshot 5,习惯命令行就用命令行,脚本的好处是能直接落盘给回归用。第一次跑会下载模型权重,需要联网。
我踩过一个坑,batch_size用auto时1.5B模型在16G显存上能跑,换成7B模型直接显存溢出。报错信息是torch.cuda.OutOfMemoryError,日志里一串显存占用表。改成batch_size=1就稳了,慢一点但不会崩。评测脚本的batch和训练不一样,评测不需要累积梯度,batch只是流水线吞吐,小一点完全无妨。
跑出来的分数怎么解读,我有一套固定的动作。先把当前分数和上一次跑同一任务的分数放一起,差在2个点以内属于正常波动,超过3个点就要查原因。再翻评测日志,看具体哪些题答错了,错题样本比总分更有信息量。最后把分数贴到团队的评测看板上,配一句模型版本说明,这样每次发版都有历史可查。
四、自定义评测集:把业务标准写成可判分的规则
自定义评测是Benchmark和业务之间的桥。Benchmark告诉你模型有多聪明,自定义评测告诉你模型能不能干活。桥怎么搭,先列业务场景,再为每个场景写题和判分标准。场景列表要业务方签字确认,评测集覆盖不到的场景,上线后出事责任在需求方。
4.1 评测集怎么建
Benchmark反映通用能力,业务能力要靠自己的评测集。建评测集就干三件事,收集真实问题、定参考答案、写判分规则。我维护的评测集分两类,问答类每题配必含词列表,生成类每题配参考答案加评分prompt。收集渠道是线上日志按类型抽样加人工补写,目标数量按场景定,高频场景50到100条够用。每条样本要有独立的来源备注,方便追溯。题目的难度分布要贴近真实,全挑简单的题,评测分数好看但没参考价值。
评测集要区分难度梯度,我的做法是按线上数据统计,把问题按高频低频排序,高频题占七成,低频难题占三成。低频难题是区分度来源,两个模型在简单题上都拿满分,就靠难题拉开差距。评测集还要定期轮换,同一批题跑三个月,模型可能被无意中过拟合,换一批同分布的新题再跑,分数会更真实。轮换时保留旧题做历史对比,新老两批题各跑一次,保证过渡期分数可追溯。
4.2 规则打分与GPT打分
判分有两种路子。规则打分是程序检查必含词和格式,零成本、可复现、不依赖外部API,缺点是死板,同义表达容易误判,比如"7天"写成"七日"就漏了。GPT打分是把模型输出和参考答案一起丢给GPT,让它按评分标准打分,贴近人评,但每次调用花钱,而且GPT本身有随机性。我一般高频回归用规则打分,上线前终审加一轮GPT打分,两种判分的结果偏差超过0.1就去查评测集本身的问题。
判分标准要写下来,不能留在评测员脑子里。我写过一份判分规范文档,定义了算对的三个层次,必含词全中算满分,部分命中算半分,答非所问算零分。GPT打分时把这套规范直接写进system prompt,比让GPT自由发挥稳定得多。规范文档每年评审一次,业务规则变了,判分标准跟着改,改完重新跑一遍历史评测,更新基线。
【踩坑】有一次我把训练集里的客服话术直接复制进评测集当参考答案,模型上线后评测得分高得离谱,业务方照单验收,结果线上被打脸。后来查出来,那些话术就在微调训练集里,评测等于开卷考试。现在我的评测集和训练集做去重,任何一条训练样本都不允许出现在评测集里,用文本相似度扫描,相似度超过0.8的直接剔除。这条规则写进了评测仓库的README,每个新人都要先读再动评测集。
# 63_custom_eval.py# 业务自定义评测:规则打分加GPT打分两种判分方式# 安装: pip install openai transformers# 运行: python 63_custom_eval.pyfromtransformersimportpipelinefromopenaiimportOpenAI# 评测样本:question是提问,expect是答案必须覆盖的必含词,answer是参考答案# 必含词要覆盖常见同义表达,比如"7天"和"七天"都算命中samples=[{"question":"你们支持几天无理由退货","expect":["7天","七天"],"answer":"支持7天无理由退货"},{"question":"怎么申请退款","expect":["订单","申请"],"answer":"在订单页点申请退款,联系客服协助"},{"question":"发货一般要多久","expect":["48小时","工作日"],"answer":"48小时内发货,偏远地区2到3个工作日"},]# 规则打分:生成回答后逐条检查必含词,全部命中算对# 优点:零成本,可复现,适合每天跑回归defrule_score(model_id):pipe=pipeline("text-generation",model=model_id,max_new_tokens=64,do_sample=False)# 固定采样,结果可复现hits=0forsinsamples:out=pipe(s["question"])[0]["generated_text"]# all()要求所有必含词都出现,漏一个就算错ifall(kinoutforkins["expect"]):hits+=1returnhits/len(samples)# GPT打分:把模型输出和参考答案一起发给GPT,按1到5分打分# 优点:接近人工判断,能理解同义表达;缺点:花钱,有随机性client=OpenAI(api_key="sk-你的key")# 也支持base_url指向中转服务defgpt_score(model_id):pipe=pipeline("text-generation",model=model_id,max_new_tokens=64,do_sample=False)total=0forsinsamples:out=pipe(s["question"])[0]["generated_text"]resp=client.chat.completions.create(model="gpt-4o-mini",messages=[{"role":"system","content":"你是评测员。按参考答案给模型输出打分,1分最差5分最好,只输出数字,不要解释。"},{"role":"user","content":f"问题:{s['question']}\n参考答案:{s['answer']}\n模型输出:{out}"},],temperature=0,# 温度设0,降低打分随机性)total+=int(resp.choices[0].message.content.strip())returntotal/len(samples)if__name__=="__main__":model="Qwen/Qwen2.5-1.5B-Instruct"print(f"规则打分:{rule_score(model):.2f}")print(f"GPT打分:{gpt_score(model):.2f}")GPT打分返回的数字可能带多余字符,比如"4分"这种带单位的回答,现在解析时统一用正则只取第一个数字。规则打分偶尔会把"48小时"和"48 小时"判成两个词,预处理时把空格全去掉再比,误判率明显下降。
GPT打分的成本账要算清。gpt-4o-mini按token计费,一个评测样本来回约600个token,100条样本跑一轮约0.02美元。每周跑3轮,一个月约0.3美元,几乎可以忽略。贵的是人,人工终审100条样本要一个工程师半天时间。所以我把GPT打分放在发版前终审,日常回归全走规则打分,人工只抽分歧样本复核。
五、自动化回归:把评测接进CI和报警
5.1 回归脚本的职责
评测跑完只是第一步,分数要有人看才有意义。我写了一个对比脚本,拿本次结果和上次基线比,每个任务设定阈值,下降超阈值就发报警。脚本挂在CI上,微调后的模型每次出adapter都自动跑,不用等人手工看。基线文件本身也受保护,只有评测负责人能更新,防止有人把报警改没了。
CI接入的细节,我用GitHub Actions的schedule跑每日回归,模型出adapter时触发全量评测。脚本里按任务拆并行,MMLU和GSM8K各开一个job,跑完汇总结果。CI日志里固定打印评测指纹和得分表,出问题直接从CI日志定位,不用翻本地文件。
5.2 阈值怎么定
阈值定小了天天误报,定大了漏报。我的经验是先收集两周的评测历史,看每个任务的自然波动范围,阈值设在波动上限的1.5倍。MMLU这类大数据集方差小,设2个百分点。GSM8K题目类型集中,设1个百分点。自定义评测集题少方差大,设5到8个百分点。报警文案里带上历史得分曲线,收到报警的人能直接判断严重程度。
误报处理也有讲究。报警出来先查三件事,评测环境有没有变、基线有没有被动过、这次跑分的题集和上次是否同一批。三件事都正常,再怀疑模型本身。我遇到过一回误报,CI机器上显存紧张,batch_size自动降低,GSM8K结果波动变大,触发了报警,排查后发现是环境问题。现在回归脚本在开头记录环境指纹,GPU型号、显存、框架版本都写进结果文件,排查误报时先对指纹。
# 63_regression_watch.py# 对比基线和本次评测结果,得分下降超阈值就发企业微信报警# 安装: pip install requests# 运行: python 63_regression_watch.py baseline.json current.jsonimportjsonimportsysimportrequests# 每个任务允许的最大得分下降幅度,超过就报警# MMLU样本多方差小,阈值给2个点;GSM8K给1个点;业务评测题少方差大,给5个点THRESHOLDS={"mmlu_stem":0.02,"gsm8k":0.01,"business_eval":0.05}defload_scores(path):# 读取eval_result.json,兼容{"scores": {...}}和裸dict两种格式data=json.load(open(path,encoding="utf-8"))returndata.get("scores",data)defcheck_regression(baseline,current):alerts=[]fortask,thinTHRESHOLDS.items():b=baseline.get(task)c=current.get(task)# 缺任务不报警,只报有对比的任务ifbisNoneorcisNone:continuediff=b-cifdiff>th:alerts.append(f"[回归报警]{task}本次{c:.3f},基线{b:.3f},下降{diff:.3f},阈值{th:.3f}")returnalertsdefsend_wecom(msg):# 企业微信机器人webhook,在群里添加机器人后复制URLwebhook="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的key"resp=requests.post(webhook,json={"msgtype":"text","text":{"content":msg}},timeout=5)# 非0说明消息没发出去,打印出来排查ifresp.json().get("errcode")!=0:print(f"报警发送失败:{resp.text}")if__name__=="__main__":# 命令行传两个文件:基线结果和本次结果baseline=load_scores(sys.argv[1])current=load_scores(sys.argv[2])alerts=check_regression(baseline,current)ifalerts:send_wecom("\n".join(alerts))print("检测到回归,已报警")else:print("全部通过,无回归")这套脚本上线后拦住过一次事故。那次有人改了推理参数把temperature从0.1调到0.7,MMLU分数没怎么动,GSM8K从0.42掉到0.31,回归脚本立刻报警,群里讨论后把参数改了回来。单看MMLU完全发现不了,这正是多任务回归的价值。
报警之后要有人接手,报警本身不算结束。我的报警群里有固定值班表,报警触发后值班人必须在30分钟内回复处理结果。处理结果的三种走向,确认回归改回参数,确认误报更新基线,确认评测集问题修题集。三种走向都写进当天的记录,月底汇总一次误报率和回归率,这两个率决定阈值要不要调。
六、评测结果的可信度:那些骗过你的分数
评测分数是给人看的证据,证据链要完整。一份合格的评测报告包含四样东西,评测版本号、模型版本号、解码参数表、得分明细。少一样,分数就无法被复核。我收到过一份只贴了总分的外部评测报告,想复核参数都找不到,这种报告当参考可以,当决策依据不行。
6.1 few-shot和模板的口径
同一个模型,5-shot比0-shot高10个百分点很正常。对比两个模型,必须保证few-shot数量、prompt模板、解码参数完全一致。我见过一份内部报告,两个模型一个用5-shot一个用0-shot,分数差被当成模型差距写进了选型结论,浪费了一周的验证工作。评测脚本里把模型参数写死,谁想改要走评审,这是我现在立的规矩。
解码参数里影响最大的是采样开关和temperature。同一个模型,do_sample=False和do_sample=True跑MMLU,分数能差3到5个点。评测统一用贪婪解码,分数稳定,和线上生产用采样解码不冲突,评测测的是模型能力上限,生产测的是体验。跑分报告里必须附上完整的解码参数,别人拿你的分数做对比时,先核对参数表再下结论。
6.2 数据泄漏
评测集和训练集重叠,分数虚高。自定义评测集一定要和训练集做去重扫描,公开Benchmark也有泄漏风险,闭源模型可能见过题目。判断方法是跑一个对照模型,用规模相近的另一个模型跑同一套评测,如果某个模型的得分异常高,先怀疑泄漏。C-Eval这类中文题集被塞进训练语料的消息传过不止一次,分数高不等于能力强。
自定义评测集的泄漏更隐蔽,训练数据的改写版也可能泄漏。我做过一次事故复盘,评测集里的题只是把训练话术换了个人称,模型照样拿满分。现在去重扫描同时比原文和改写后的相似度,用n-gram重叠率,超过0.6就报警让人工复核。扫描脚本挂在评测仓库的CI上,每次提交评测集自动跑。
6.3 采样方差
小评测集跑一次的结果波动很大,20条题目的评测集,抽中难的10条和容易的10条,得分能差20个百分点。缩小方差的办法是加大题量或多次采样取平均,我跑回归时最少取3次结果的中位数,不用单次值。业务评测集扩容到100条以后,方差就压到3个点以内,报警阈值也敢设得更紧。
还有一类方差来自评测模型本身的随机性,用GPT打分时特别明显。同一个模型输出,GPT连打三次,分数可能从4跳到2。处理办法是每个样本打3次取平均,再把temperature固定为0。成本翻三倍,但换来的是回归报警不误报,这笔账划算。
评测的分数最终要服务于决策,决策的场景有三类,选型、验收、回归。选型比通用Benchmark,验收比自定义评测,回归比差值。三类场景的评测配置可以不同,但同一类场景内部必须统一。我见过团队把三类场景的评测混着跑,结论互相打架,后来强制按场景分目录管理评测集,每个场景一份配置文件,这才不再打架。
七、一套完整的评测落地清单
把前六节压缩成一张落地清单,照着做就能搭起最小可用评测体系。
第一步,跑通lm-eval,把MMLU子集、GSM8K、C-Eval的基线分数落盘,存成eval_result.json,花半天时间。
第二步,建自定义评测集,从线上日志抽50到100条业务题,配必含词和参考答案,和训练集去重,花一天时间。
第三步,写回归对比脚本,设好阈值,接进CI,发版前自动跑,花半天时间。
第四步,开通在线采样,每周抽300条线上问题跑评测,把得分画成趋势图,花半天时间搭好,之后每周半小时。
第五步,把基线文件、判分规范、评测仓库权限管起来,改动留痕,花半天时间。
这套清单的总成本,一周内可以完成,算力上1.5B模型每天1小时。它带来的回报是,模型每一次变更都有分数说话,上线前不用靠拍脑袋。我搭这套东西的第二天就拦住了一次冒烟测试,新模型的GSM8K掉了0.08,回归报警先于任何用户反馈到达。
这套清单的每一步都有对应脚本,评测脚本、判分脚本、回归脚本在文中都给了完整代码。抄下来改改模型名和题集就能用,不用从零搭。
常见问题FAQ
- Q1: 评测工具用哪个
- A1: 开源首选lm-evaluation-harness 0.4.x,一条命令跑MMLU/GSM8K/C-Eval,业务评测自己写脚本
- Q2: 我的业务场景评测集怎么建
- A2: 线上日志按类型抽样,每题定必含词和参考答案,50到100条起步,和训练集做去重扫描
- Q3: 为什么MMLU分数高但线上效果差
- A3: MMLU测选择题知识,测不出生成质量、语气和业务规则,线上能力要看自定义评测加在线采样
- Q4: lm-eval跑起来报错
- A4: 先查版本,lm-eval要0.4.x,transformers要4.40以上;再查模型是否需要trust_remote_code=True;显存溢出就把batch_size改成1
- Q5: 跑一次评测要多久
- A5: 1.5B模型跑MMLU子集约40分钟,GSM8K在10分钟内,7B模型时间翻3到5倍
- Q6: 离线评测和在线评测都要做吗
- A6: 都要,离线保证可复现,在线保证真实,发版前跑离线,每周跑在线采样
- Q7: GPT打分和规则打分怎么选
- A7: 高频回归用规则打分,免费可复现;上线终审加一轮GPT打分,更接近人评,两种结果偏差超0.1就查评测集
- Q8: 评测要花钱吗
- A8: 开源工具免费,GPT打分按量付费,1.5B模型跑全套Benchmark主要是时间成本,一天约1小时算力
- Q9: 回归报警阈值设多少
- A9: 先收集两周历史看波动,MMLU设2个点,GSM8K设1个点,自定义评测设5到8个点
- Q10: 怎么判断一个评测分数可不可信
- A10: 查三件事,few-shot口径是否一致、评测集有没有泄漏、样本量够不够,三点都过再信
为什么订阅本专栏
- 免费教程只贴Benchmark分数表,本专栏把跑分脚本、判分规则、回归报警完整给出,拿过去就能用
- 培训班动辄几千元,本专栏用三个可直接运行的脚本覆盖评测全流程,含阈值设定和数据泄漏排雷
- 每篇带真实事故复盘,上线前夜的翻车、开卷考试的评测集,这些坑提前帮你排掉
- 与第20篇Prompt评测、第31篇RAG评测、第52篇LangSmith衔接,从Prompt到模型到RAG的评测体系一次学完
- 一次订阅终身回看,代码随lm-eval和transformers版本更新持续修正
相关推荐
- LangSmith:LLM应用的监控与评测平台
- RAG评测:RAGAS与TruLens自动化评估
- Prompt评测:自动化测试与回归体系
限时¥59.90,30秒完成订阅,今天就能开始学习