ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LLM评测分数为何忽高忽低?解密排行榜背后的配置变量

LLM评测分数为何忽高忽低?解密排行榜背后的配置变量 在 LLM 评测里排行榜经常被直接当成“模型能力强弱”的证据。可现实中同一个模型放在不同的评测配置下结果可能天差地别。论文观点和行业实验里经常出现这样的案例一个代号为 gemma4-31b 的 31B 级模型在只看论文标题给出的评测条件下得分可以从 31% 波动到 89%。如果这个现象成立那它说明排行榜名次并不只取决于模型权重还取决于评测集、prompt 写法、few-shot 数量、解码参数、输出解析方式和评分规则。对于做模型选型、版本回归、模型微调或大模型应用的人来说只知道最终得分而不知道评测配置几乎等于只看结论不看实验条件。这篇文章会拆解 LLM 排行榜背后的评测链路解释哪些配置旋钮会改变分数并给出最小复现实验和一套可信评测流程。读完以后你能回答三个问题为什么同一个模型分数会大幅波动当你自己评测模型时应该固定哪些变量当别人发布一个排行榜分数时你应该追问哪些配置细节。1. 先理解评测分数是评测系统输出的观测值不是模型能力不变的属性1.1 排行榜为什么会出现“同一个模型不同分”如果你做过软件测试会很容易理解一个道理同一个待测系统在不同输入、不同环境、不同测试步骤下测试通过率本来就不同。LLM 也一样。模型权重只是评测系统中的一个组件评测系统由“数据、任务格式、模型推理、输出解析、评分器和统计汇总”共同组成。标题里提到的 31% 到 89% 的跨度并不是模型权重在两次运行中“突然变强”而是评测条件发生了显著变化。比如第一次用“模型直接生成答案再用关键词匹配”的方式来评分第二次用“多选任务中比较每个选项的 log probability对数概率”的方式来评分第一次只用 0-shot prompt第二次用了精心构造的 5-shot 示例第一次让模型自由输出第二次用 prompt 强制模型必须输出 JSON 结构。这些变化中的任何一项都可能让分数产生几个点到几十个点的差异。把它们叠在一起时就会出现“同一个模型从落后变成领先”的效果。1.2 评测分数不是一条流水线而是一条完整的处理链路一次典型的大模型评测至少包含下面几个阶段评测数据选择哪个 benchmark使用哪个 split用多少条题目是否过滤掉模型已经见过的题目。prompt 构造把题目文本转成模型输入包括 system prompt、user prompt、few-shot 示例、输出格式约束。模型推理设置 temperature、top_p、max_new_tokens、停止词等生成参数。输出解析从模型返回的原始文本中抽取出答案比如匹配“A/B/C/D”或从 JSON 中取字段。答案评分把预测答案与标准答案比较比较方式可以是精确匹配、包含匹配、语义匹配或裁判模型打分。分数汇总对不同任务或不同子集的得分做平均也可能是加权平均。每一步都有“默认值”而默认值不一定合理。只要默认值改变最终分数就可能改变。因此LLM 评测首先要做的是把不可见默认值变成可视化的配置记录。1.3 论文观点带来的实用启发如果只从论文标题总结出一个结论那应该是不要把排行榜分数当作模型能力的唯一指标。更实用的启发有三点模型选型时要找到与目标业务接近的评测配置而不是直接搬用某个综合榜单。模型发布方在报告分数时必须同时报告完整评测配置否则结果无法复现也难以比较。应用开发团队在做模型回归测试时要固定评测配置否则你无法判断线上分数波动是因为模型变差了还是因为 prompt 或解码参数被动过。很多人遇到“同一个模型分数浮动”会先去怀疑模型实际更常见的原因是评测链路发生了变化。正确顺序是先检查配置再怀疑模型。2. 拆解评测配置哪些旋钮可以让分数从 31% 变成 89%2.1 评测数据与任务划分同一个任务名内容不一定相同很多排行榜会写“MMLU 得分 70%”但 MMLU 并不是一张固定不变的卷子。它包含多个子任务、多个学科的题目不同报告会使用不同的题目数量是否排除与预训练语料重复的样本使用固定的 test split 还是随机采样一段是否使用中文题目或本地化翻译few-shot 示例是固定顺序还是随机顺序few-shot 示例是否来自同一条训练样本还是从测试集附近选取。一旦数据分布不同同一个模型的分数就不能直接比较。更低级的问题还有“评测泄漏”如果测试题目本身在预训练阶段出现过模型只是在背答案而不是理解问题。设计评测时应该保留一个模型训练阶段没有见过的样本集合。选项顺序同样是容易被忽略的“配置”。选择题里把正确答案固定在 A模型不一定是在做推理可能只是在学“选项位置和概率”的相关性。如果评测配置没有把答案顺序随机化模型可能受益或受害分数也会相对偏高或偏低。2.2 Prompt 模板问法不同同一个模型会输出完全不同的内容LLM 对 prompt 极其敏感。同一个问题只要改为英文、中文、口语化表述、结构化指令输出的可靠性就会变化。评测中常见的 prompt 因素包括是 zero-shot 还是 few-shotfew-shot 示例有几条顺序如何是否让模型先输出推理过程再输出答案是否要求输出 JSON、XML 或 Markdown是否使用很长的 system prompt是否在 prompt 里交代“如果不知道答案就输出不知道”。一个典型配置差异可以是这样的templates { bare: 请直接输出一个选项字母\n{question}, coerce: 请先简短判断然后以“答案X”结尾。\n{question}, json: 请输出 JSON包含 reason 和 answer 两个字段。\n{question}, }对同一个问题三种模板会诱导出不同的生成路径。如果评测报告的 prompt 模板没有记录复现者只能靠猜。更好的做法是把 prompt 模板存成文件模板文件的 hash 值也一并记录。2.3 解码参数Temperature 和 Top_p 不是随便填的解码参数直接影响模型输出结果的稳定性。评测时最危险的设置是使用较高的 temperature 却只运行一次。高 temperature 会放大随机性导致结果不可复现。常见生成参数的影响如下表参数含义常见设置对评测的影响temperature控制采样概率分布的平滑程度0.0 到 1.0越高随机性越强评测通常设为 0.0 或接近 0top_p控制从累计概率达到阈值的 token 中采样0.9 到 1.0与 temperature 同向影响随机性等于 1.0 时不截断max_new_tokens允许生成的最大 token 数32 到 2048太短会截断答案太长可能引入额外噪声stop_sequences遇到特定 token 停止生成如“\n\n”或“endoftextdo_sample是否采用随机采样False 或 True评测常用 False 以获得稳定结果如果需要多样性则用 True如果模型评测时使用temperature0.7并且只跑一次那么重复评测同一个模型分数范围可能跨越好几个百分点。对于有时间限制的短答案任务max_new_tokens16也能造成失真模型答案还没生成完输出就被截断正确答案自然无法被解析。2.4 输出解析和答案匹配对错可能由一段正则决定模型输出的原始文本几乎不会整齐到可以直接比较。常见输出形态包括“答案选 A”“A”“我认为正确答案是 A”“答案是A。因为……所以选择 A”完整 JSON 对象一句很长的话末尾带着答案评分阶段需要从原始输出中抽取答案。抽取得的正则表达式、关键词、字段读取方式不同最终准确率就不同。例如一个问题要求模型输出字母选项模型回答先说结论这道题应该选 D因为哈希表支持快速查找。如果评测器的匹配规则是“如果文本中出现答案D则判定为 D”这个回答可能被判错。如果匹配规则是“通过正则找到最后一个出现的大写 A/B/C/D 字母”它可能判对。同一个模型、同一个生成输出只因为解析规则不同分数就会不同。更隐蔽的是“semantic equivalence”匹配它可能调用 embedding 模型计算句子相似度或调用另一个 LLM 判断两个答案是否一致。这时候评测链路上又增加了一个模型和一组 prompt 配置评测结果不再是单一模型的行为。2.5 评分方式选择题算概率写作题叫裁判模型差异很大同一份 MMLU 题目可以采用两种评分方式计算四个选项字母对应 token 的 log probability选概率最高的一项让模型自由生成答案文本再从答案里解析选项字母。这两种方式本质上是在测不同的能力。前一种更接近“在选项约束下判别正确 token”后一种更接近“在没有完整约束下输出稳定答案”。同一个模型在两种方式下的表现可能存在显著差异。对于开放式任务比如摘要、故事生成、代码解释传统字符串匹配无法使用常见方案是引入“judge model”或人工评分。裁判模型不是没有偏好的它在评“逻辑是不是清晰”“语气是不是友好”时会受到 prompt 模板、temperature、评分量纲的影响。一个 8B 裁判和一个 70B 裁判可能得出不同结论同一个裁判在两个不同 prompt 下也可能给出不同分数。3. 用最小实验复现“评测配置导致分数漂移”这一节使用最简单的自建评测脚本来演示控制变量思路。建议不要在十亿级参数模型上直接跑完整 benchmark而是先准备一份 50 到 100 道题的题目集把 prompt 和温度作为变量观察准确率变化。这个最小实验足够暴露评测配置的敏感性。3.1 实验设计目标实验需要回答的问题不是“哪个 prompt 最好”而是“同一个模型只改一个配置项分数是否显著变化”。所以实验流程应该是固定模型权重和显卡环境。固定同一份评测题目。固定输出解析规则。先以 baseline 配置跑一次。只修改 prompt 模板其他不变。只修改 temperature其他不变。对比分数和输出文本。关键原则是每次只改一个变量。如果同时改 prompt 和温度得到的分差无法归因。3.2 准备 Python 环境示例环境使用 Hugging Face Transformers 加载模型并使用自己的题目 JSON。python -m venv .venv source .venv/bin/activate pip install -U transformers torch accelerate如果你的模型文件较大建议在本地 GPU 环境运行。脚本本身只依赖 transform。生产化评测时可以再引入lm_eval、OpenCompass 等工具但这里不依赖它们。3.3 最小评测脚本骨架下面的脚本只演示读取模型、构造 prompt、生成答案、解析答案四步。实际使用时需要把your-model-name-or-path换成真实模型路径。import re import torch from transformers import AutoModelForCausalLM, AutoTokenizer model_name your-model-name-or-path model AutoModelForCausalLM.from_pretrained( model_name, torch_dtypetorch.bfloat16, device_mapauto, ) tokenizer AutoTokenizer.from_pretrained(model_name) question_bank [ { question: ( 下列关于哈希表的说法正确的是\n A. 哈希表不支持增删操作\n B. 哈希表查找时间与数据量无关\n C. 哈希表一定比数组节省空间\n D. 哈希表存在哈希冲突 ), answer: D }, ] templates { bare: 请直接输出一个选项字母\n{question}, coerce: 请先简短判断然后以“答案X”结尾。\n{question}, json: 请输出 JSON包含 reason 和 answer 两个字段。\n{question}, } def generate(prompt_text, max_new_tokens64, temperature0.0, top_p1.0): messages [{role: user, content: prompt_text}] input_ids tokenizer.apply_chat_template( messages, add_generation_promptTrue, return_tensorspt ).to(model.device) if temperature 0: out model.generate( input_ids, max_new_tokensmax_new_tokens, do_sampleFalse, ) else: out model.generate( input_ids, max_new_tokensmax_new_tokens, temperaturetemperature, top_ptop_p, do_sampleTrue, ) return tokenizer.decode(out[0][input_ids.shape[-1]:], skip_special_tokensTrue) def extract_option(text): # 先匹配“答案X”模式找不到再匹配全文最后一个字母选项。 m re.search(r答案[:]\s*([A-Da-d]), text) if m: return m.group(1).upper() letters re.findall(r\b([A-Da-d])\b, text) if letters: return letters[-1].upper() return def evaluate(template_key, temperature): correct 0 total len(question_bank) for item in question_bank: prompt templates[template_key].format(questionitem[question]) output generate(prompt, temperaturetemperature) predict extract_option(output) if predict item[answer]: correct 1 return correct / total if __name__ __main__: for template_key in templates: acc evaluate(template_key, temperature0.0) print(template_key, accuracy, acc)脚本里的extract_option是用于演示的解析版本。实际测试时你可能需要根据模型输出格式写更严格的解析关键是一定要把解析规则固定下来不要中途随意调整匹配逻辑。3.4 进一步实验只改 temperature在刚才的脚本基础上可以循环多次for temp in [0.0, 0.4, 0.8]: results [] for i in range(5): results.append(evaluate(bare, temperaturetemp)) print(temperature, temp, mean, sum(results) / len(results), results, results)这个实验会暴露一个常见现象temperature 越高多次运行结果波动越大。有些模型在 temperature 0.8 时同一题可能多次给出不同选项甚至有些题目会中途输出无关内容。分数波动不是模型“作弊”而是随机采样在起作用。3.5 观察到的结果和下一步判断运行实验后把结果记录为一张配置与准确率对照表实验组prompt 模板temperature是否多次运行记录分数Abare0.0否待记录Bcoerce0.0否待记录Cjson0.0否待记录Dbare0.8是5 次待记录当观察到以下模式时要警惕评测结果的可信度修改 prompt 后准确率变化超过几个点修改 temperature 后多次运行结果范围很大同一个答案文本在另一种解析规则下被判对或判错。这些都说明你的评测得分不只是模型能力的体现也是评测配置的体现。只有把所有配置固定后分数才有横向比较价值。4. 建立可信评测流程先定义配置再读取分数如果你需要团队内长期使用 LLM 评测建议从第一天起就把评测配置当成代码来管理。评测配置不是一次性命令而是可以被 Git 追踪的文件。4.1 配置中必须包含哪些字段一个完整评测配置至少要包含字段示例值为什么必须记录模型名称和版本your-model-name-or-path同一模型权重不同版本不能混用数据来源和 splitmmlu/test 或自定义数据 v1.2数据版本不同分数没有可比性题目数量100 或 全部样本量会影响统计稳定性随机种子42随机采样需要可复现few-shot 数量5不同数量会显著改变表现prompt 模板文件templates/eval_mmlu.txt模板是评测的关键输入最大生成长度512防止输出截断或过长temperature0.0评测通常建议 greedytop_p1.0与 temperature 配合输出解析器regex_v2不同解析器得分不同评分方式exact_match 或 judge_model决定最终比较逻辑修复次数3结果不稳定时统计均值4.2 用一个配置文件保持评测一致性下面是一个适合提交到 Git 仓库的评测配置示例。它本身不绑定特定工具而是提醒你需要管理哪些字段。experiment_name: eval_exp_001 created_at: 2025-01-01 model: name: your-model-name-or-path dtype: bfloat16 device_map: auto task: dataset: custom_qa_v1 split: test sample_size: 100 seed: 42 num_fewshot: 0 prompt: template_file: templates/user_bare.jinja system_prompt: output_format_hint: generation: temperature: 0.0 top_p: 1.0 max_new_tokens: 64 stop_sequences: [] postprocess: parser: extract_option_regex_v2 normalize: uppercase evaluation: metric: accuracy repeat_times: 1 report_mode: single每次启动评测前先检查配置是否和上次一致。如果不一致就把新配置作为一次新实验。不要直接在旧配置上修改几个参数然后默认结果可比。4.3 多次运行与置信区间评测任务往往包含随机性。比如数据按 seed 洗牌模型从预训练权重加载时在某些算子上的非确定性tokenizer 在不同版本之间的行为不一致这些都可能导致同配置下两次结果不一样。建议至少满足以下三点在配置文件中固定 seed对于需要采样生成的评测跑 3 次以上并记录均值而不是单次结果当分数差异很小时用置信区间判断差异是否在噪声范围内而不是仅凭单次平均分做结论。考虑一个简单例子A 模型平均分 72.3%B 模型平均分 73.1%。如果不看多次运行的标准差可能直接认为 B 更好。但如果标准差是 2%这个 0.8% 的差异在统计上并不能说明任何实质能力差异。5. 看任何排行榜之前先检查五样东西排行榜的价值是“提示线索”不是“最终判决”。下面五样东西能帮助你判断榜单分数是否适用于你的场景。5.1 评测集名称、版本和 split如果报告只写“MMLU 68%”并没有可复现性。你需要自查是原始 MMLU 的 test 集吗是否做了子集筛选是否包含 known 的题目重复过滤是否用了某个团队的私有评测集不同数据集版本之间的题目可能不同。没有数据集版本任何分数都无法判断。5.2 Prompt 模板和 few-shot 策略看 benchmark 页面时要找它是否公开了 prompt 模板和 few-shot 示例。有些榜单的“best prompt”是在评测集上调出来的这相当于拿测试集优化提示词最终分数会乐观。如果你在自己的应用里使用中文客服 prompt但榜单只用英文指令评测这个高分未必能迁移到你的业务里。5.3 解码与评分方式需要明确三个问题它是用生成式评分还是用 log probability 评分如果生成式评分temperature 是多少输出解析和答案匹配规则是什么同一个模型可能因为从生成式评分切成 log probability 评分分数上升很多。这不代表模型变聪明只是评测方式变化了。5.4 是否做过多次运行看过榜单文档后如果整篇报告没有提到随机种子、运行次数、标准差就要默认它的分数是“单次评测条件下的快照”。快照可以用来看方向不适合用来倒推零点几个百分点的差异。5.5 评测场景是否接近你的真实场景排行榜更适合回答“预训练模型在通用任务上的能力基线”不适合回答“哪个模型更适合我的私有文档问答系统”。如果你的场景需要输出 JSON、调用工具、处理长文档就必须自己准备一份贴近场景的评测集。以下几种常见评测任务和敏感配置点可以做一个快速对照评测任务主要得分指标最容易受影响的配置MMLU 类选择题accuracy选项顺序、few-shot、是否用 log probabilityGSM8K 类数学题accuracyprompt 是否要求先推理、温度、输出解析HumanEval 类代码题passk生成次数、k 值、测试用例AlpacaEval 类开放题win ratejudge 模型、prompt、温度、答案长度真实业务问答自定义指标评测集分布、prompt、解析规则6. 评测分数异常波动时的排查路径如果你在同一模型、同一份评测任务上发现了奇怪的结果不要先怀疑模型权重损坏先按链路排查。6.1 高频异常现象与处理建议问题现象常见原因检查方式处理建议两次跑分差了 3 个百分点temperature 高于 0且只跑了一次检查配置文件中的 temperature 和 do_sample改为 greedy或多次运行取均值排行榜复现分低于发布分发布方未公开评测集版本或 prompt 模板查看官方评测配置和脚本按官方 config 重建任务无法复现时保持怀疑prompt 增加“请认真思考”后分数明显上升该能力只在特定提示语下存在对比不同提示语多次运行结果明确这是提示词优化结果不代表默认能力提升同一个答案有的判对有的判错输出解析规则不统一打印原始输出人工核对解析结果固定一种解析器并保证所有样本使用同一逻辑A/B 模型差异很小样本量不足增加测试样本或做多次 bootstrap 抽样用置信区间判断差异关闭随机后两次依然不同模型加载或算子存在非确定性检查 CUDA、batch size、后端版本固定后端版本必要时逐条记录日志6.2 按位置定位变化来源当总分异常变化时可以按照下面的顺序逐层检查输入数据是否一致加载的 JSON、CSV、数据库快照是否同一个版本。任务模板是否一致prompt 模板有没有被无意改动比如多了换行或空格。解码参数是否一致temperature、top_p、max_new_tokens、停止词是否被修改。解析是否一致解析脚本版本是否更新是否改变了正则匹配顺序。评分是否一致精确匹配是否改成了语义匹配或者引入了 judge 模型。统计是否一致是 macro avg 还是 micro avg是否过滤了某些失败样本。这一步的核心是“单变量归因”。先把所有变量固定到与上次完全一致再逐项放开修改才能知道差异来自哪里。6.3 评测日志需要记录哪些内容为了能在问题出现后回查评测不只是输出一个准确率还应该保存原始输出和检索数据。推荐每一轮评测都输出如下格式的 JSONL{ run_id: 20250101_exp001, model_name: your-model-name-or-path, task_id: question_0001, prompt_template: coerce, prompt_text_hash: a1b2c3d4, raw_output: 答案是 D, extracted_answer: D, gold_answer: D, is_correct: true, temperature: 0.0, max_new_tokens: 64, seed: 42 }有了这类日志评测分数只是日志的下游产物。分数异常时可以直接回看某题的 prompt、原始输出和解析结果而不是对着一个裸数字猜测。7. 把评测从“单次榜单对比”变成“长期回归机制”7.1 团队评测流程建议实际项目里不再建议用“跑一个 benchmark得到一个分数然后决定模型”这样的一次性方式。更稳的做法是把评测嵌入模型变更流程配置一个“回归评测集”里面包含业务字段、通用能力、坏例样例。任何 prompt 修改、模型权重更新、解码参数调整都触发同一套评测。每个变更提交后比较新分数和历史基线并把变化归因到具体变量。prompt 优化和模型能力提升分开记录不要把两者的效果混在同一条曲线里。这套流程的价值是避免“上周线上效果很好这周 prompt 改了一行没有评测就上线结果模型看起来变笨”这类问题。其实模型没变是评测配置或 prompt 变了。7.2 每次发布评测结果前过一遍下面的检查清单模型加载路径是否记录了具体版本评测集的源文件 hash 是否记录prompt 模板是否归档到仓库temperature 是否为 0或多次运行取了均值解析规则是否有单元测试保护是否记录了 GPU 和后端版本是否保存了一批原始输出日志对比的基线是否使用了同一套配置只要有一项为“否”这份评测结果的可复现性就有缺口。看到相差很大的排行榜数字时优先查这一项能少走很多弯路。7.3 扩展方向动态基准、裁判模型和场景化评测评测不会静止在 MMLU 和 GSM8K 上。更值得关注的方向包括动态评测集定期抽出新题目降低题目被模型记忆的风险场景化评测针对具体 Agent、代码生成、RAG 问答等任务构建私有评测集裁判模型评测记录裁判模型名称、prompt、温度和随机种子不能让裁判模型成为隐性变量持续回归把评测配置纳入 CI/CD模型更新时自动跑完整评测。最核心的变化是把“排行榜名次”当作结果把“评测配置”当作实验条件。论文标题揭示的现象并不只在某个模型中存在它提醒所有使用 LLM 的人都应该带着实验者的眼光去看分数。以后再做模型选型或者版本回归时先问一句这份分数是在什么评测配置下得到的如果不清楚这个数字只能作为参考不能作为决策依据。
返回列表