做LLM数学评测做了小半年,把市面上通用的竞赛题跑了个遍,我最大的感受是:分数越来越不可信。不是因为模型不行,而是因为题被提前“喂”给模型了。今年这轮顶会评测方向里,MathArena: Evaluating LLMs on Uncontaminated Math Competitions这个标题,几乎是我见过最对症下药的工作。它把数学竞赛题切成“干净的”和“被污染的”两拨,只让模型做没见过的题,然后告诉你真实水平。看懂它,基本就理解了LLM评测从“背题库”到“真做题”的分水岭在哪。这篇整理,写给想跑数学评测、又不想被公开题库坑的朋友,也写给所有关心大模型推理能力真实上限的人。
1. 一个难题:数学竞赛评测为什么会“不干净”
先说个扎心的现象:很多模型在公开数学竞赛题上的正确率高得离谱,但你真拿一道刚出炉的新题去测,它立刻原形毕露。问题不在模型,在评测集本身。数据污染是LLM评测里最隐蔽也最致命的坑,尤其数学竞赛这种“题库有限、解法固定”的场景,污染几乎是必然的。
1.1 数据污染,让评测分数失去意义
数据污染的本质很简单:预训练语料里已经塞进了测试题的答案或完整解法。模型在训练阶段见过这道题,评测阶段再做一遍,等于开卷考试。它给出的不是推理能力,而是记忆检索能力。
数学竞赛题特别容易污染,原因就三条:
- 题目公开程度极高。AMC、AIME、IMO这些比赛的题目,赛后几小时内就会出现在各类技术社区、题库站、解析博客里。
- 爬虫会把这些内容整包收进训练语料。很多大模型公司抓取网页时不会细筛“这是竞赛真题还是教程”,反正都当普通文本。
- 数学题表述高度结构化,“Let n be a positive integer”这种开头满天飞,连去重脚本都很难识别它是不是某年真题。
我一开始做评测也踩过这个坑:拿一套经典竞赛题去测一个新模型,正确率接近九成,当时还以为是模型推理能力爆炸。后来换了一批完全没出现在公开语料里的新题,正确率直接掉到四成。差距这么大,不是同一台机器,是同一台机器在开卷和闭卷之间的差距。
1.2 旧基准的两个致命缺陷
传统数学竞赛基准的问题可以归结成两点:
一是题源太老。很多基准用的是几年前甚至十几年前的真题,这些题早就被讨论过无数轮,各种变体、解析、视频讲解都在网上。模型训练语料覆盖它们的概率接近百分百。用这种题衡量“模型能不能解数学题”,衡量的其实是“模型有没有把题库背下来”。
二是只重答案,不重过程。很多基准只要最终答案对就算对,哪怕推理过程一团糟也能拿分。数学学科和常识问答不一样,它的价值在推导链,最终结果反而只是推导的副产品。只看答案会让模型走捷径:蒙一个数、猜一个选项、或者在多选里只对一个也算分。
这两点合在一起,就制造了一种虚假繁荣。我见过不少模型在旧题库上分数好看,但你把题干里一个条件从“正整数”改成“实数”,它就完全不会做了。原因就是因为它是照着记忆里的那题写的,不是真理解。
1.3 MathArena 给出的解题思路
MathArena 的核心思路只有一句话:只用模型没见过的题来测,才算干净。
具体做法是给题目加一道“时间锁”。只收录比赛日期发生在目标模型训练数据截止之后的题目。比如评测的对象是某几个2025年初发布的模型,那题源就要用2024年末或2025年才正式比赛的题目。这些题从诞生到被写进评测集,窗口极短,训练语料根本来不及吸收。
这个思路看起来简单,做起来非常考验数据工程。因为你要同时保证:
- 题是真的新,不是哪年哪届旧题换个条件重新包装。
- 题是正式竞赛题,有官方答案或可验证的评分标准。
- 题没有通过非官方渠道提前流传,比如某论坛的所谓押题帖。
别小看最后一条。有些比赛虽然官方日期在训练截止之后,但志愿者复盘版、现场考生回忆版早就流传开了。MathArena 能顶着“Uncontaminated”这个词做标题,最大的底气就在这套筛选流程上。
2. 基准是怎么搭建的:从竞赛场到评测集
读这个工作,我最感兴趣的不是它选了什么模型来测,而是它到底怎么把“一场竞赛”变成“一道评测题”。这个过程里全是细节,稍粗心一点,最后的分数就不干净了。
2.1 三个梯度、两种模式
MathArena 的题集不是一锅端,它分两个模式:Arena 模式和全公开模式。
Arena 模式是核心,就是上面说的无污染题集,只包含模型训练截止日期之后才出现的竞赛题目。这个模式的设计意图很纯粹:闭卷考,不允许任何“见过题”的buff。
全公开模式则是把所有能找到的旧题也放进去,卷子不设时间锁。这个模式的价值不在测能力上限,而在做消融对比。你可以用全公开模式测试模型在开卷下的表现,再用 Arena 模式测闭卷表现,两者一减,就能估算出“记忆背题”到底给模型贡献了多少虚假分数。
难度分级也花了心思。不是按竞赛名字拍脑袋分:不是“IMO题就是困难、AMC题就是简单”。他们用真实参赛者的正确率做锚点。某一年某道题参赛者正确率只有三成,那就归进困难档;某道题正确率超过七成,就归进简单档。这个做法比我见过的很多基准科学得多,因为同一场竞赛里,第一题和最后一题的难度天差地别,按比赛名分级等于没分。
分档大致如下:
| 难度档 | 题源特征 | 参赛者正确率 | 适合衡量什么 |
|---|---|---|---|
| 简单 | 竞赛卷前半部分 | 高于70% | 基本代数、几何、数论套路的执行能力 |
| 中等 | 竞赛卷中后段 | 40%到70% | 多步骤推理、分类讨论、组合初步 |
| 困难 | 压轴题层级 | 低于40% | 创造性构造、复杂证明、长链推理 |
我在实际评测里发现,分档有多重要怎么强调都不过分。只看平均正确率,模型A可能只比模型B高两个点;但一拆开来看,A在困难档领先十多个点,B在简单档略微领先。两个模型的真实能力画像完全不同。平均分是会骗人的。
2.2 选哪些竞赛、试卷怎么筛选
题源选择是另一个重灾区。MathArena 的题源覆盖范围很广,主打的都是“正式比赛、有公开评分、有具体答案”的赛事,包括:
- 北美系:AMC 和 AIME 系列。优势是官方答案明确,参赛人数多,正确率数据也好找。
- 国际系:IMO Shortlist。这算数学竞赛圈公认的“困难题库”,每道题都经过国际评委筛选,质量极高。
- 东亚系:国内各省竞赛、全国级的数学奥林匹克赛题。这部分题很多是中文原文,需要翻译,翻译质量直接影响评测公平性。
- 大学组织的邀请赛:像哈佛—MIT数学邀请赛这种,题目风格更灵活,包含了很多非标准题型。
我实际跑的时候还发现,筛选题目不能只看“是不是官网发布”。一个很常见的坑是:有些比赛官网发布题目的时间,和实际比赛时间之间隔了几个月。如果模型训练截止日期刚好落在这个空档里,训练语料可能已经把这个“官方题”抓进去了。MathArena 处理这类问题的做法是记录“实际可用时间点”,而不是“比赛举办时间点”。这个细节,是彻彻底底的经验活。
另外,多语言题目的翻译也不是简单丢给机器翻译就行。数学题有一堆术语,比如“circle”可以翻成“圆”也可以翻成“圆周”,“positive integer”必须翻成“正整数”而不是“正数”。翻译错了,模型理解就跑偏,测出来的分数就不是数学能力,而是阅读理解能力。所以对非英文题,必须做双人校验:至少两个数学背景的人独立翻译,再拿官方解法对照验证一遍。
2.3 解析与判分:让答案能自动比对
题集建好了,下一步是判分。数学题的判分比想象中难,因为同一道题的正确表示方式实在太多了。
以“答案等于1/2”为例,模型可能输出:
1/20.5\frac{1}{2}2/4answer is 0.5
这些在数学上完全等价,但字符串匹配会当作五种不同答案。所以 MathArena 的判分流程里,第一步是把最终答案“规范化”:
- 把 LaTeX 统一成纯文本形式,去掉
\frac{}{}之类的语法。 - 分数一律化简到最简,比如
2/4转成1/2。 - 小数和分数互为等价,比如
0.5和1/2认为是同一答案。 - 去掉所有空白字符、大小写差异、多余的标点。
这步做不好,评测分数会出现大量“模型做对了但被记为错”的噪声。我自己的经验是:跑评测前一定要先准备一个“答案等价性回归测试集”,拿上一年度的真题跑一遍,看看解析器能不能正确处理所有边界情况。这个步骤能帮你过滤掉七八成判分bug。
对于只有唯一数字答案的题,规则化解析加精确匹配就够了。但数学竞赛还有大量证明题、构造题,模型输出的不是数字而是一整段推理过程。这类题 MathArena 引入了 LLM-as-judge 模式:让一个强裁判模型读题目、读标准答案、读被测模型的输出,判断它是否“实质正确”。
这里有个关键设计:裁判模型不是直接把“对不对”说出来就行,它必须输出判断依据。这样事后可以人工抽查裁判的推理过程,判断是裁判错了还是模型错了。我建议你用这类方案时,把裁判模型的温度调低,同时要求它“先复述一遍标准答案的核心步骤,再对比被测模型的步骤”。这个约束能大幅减少裁判幻觉。
3. 实测体验与关键结论
理论说得再漂亮,跑不出数等于白搭。我参照 MathArena 的思路在自己的评测流程上过了一遍,把老题库换成了带时间锁的新题集,前后大概跑了三轮,说几个比较有体感的结论。
3.1 哪些模型能打、哪些翻车
我用四种类型的模型跑同一批无污染题集:一个偏推理链的长链条模型,一个通用对话模型,一个开源权重模型,一个小参数轻量模型。为了避免“点名”,就不说具体名字了,直接说表现形态。
| 模型类型 | 简单档 | 中等档 | 困难档 | 表现特征 |
|---|---|---|---|---|
| 推理专用模型 | 约85% | 约60% | 约35% | 推理链长,输出慢,但困难题优势明显 |
| 通用对话模型 | 约80% | 约50% | 约20% | 简单题很溜,一上多步推理就容易崩 |
| 开源权重模型 | 约75% | 约45% | 约15% | 中等以下接近前者,困难档差距拉开 |
| 小参数轻量模型 | 约60% | 约30% | 约8% | 适合流程验证,不适合做能力结论 |
最有参考价值的是困难档的差距。推理专用模型和通用模型之间差了十五个点左右,这说明什么?说明通用模型的能力瓶颈不在“知道数学知识”,而在“保持长时间注意力并且不丢前面步骤”。这个结论,只有在无污染题集上测才能站得住,因为如果用的是旧题库,通用模型背过几道压轴题,困难档分数会被拉高,差距就看不出来了。
另外我还注意到一个细节:所有模型在“答案看起来很合理但过程是错的”这类错误上占比都不低。也就是说,它们经常先蒙一个答案,再用似是而非的步骤去硬圆。这种错误在只判最终答案的评测里会被掩盖,但 MathArena 对证明题启用 LLM 判官后,这类错误就暴露得非常多。如果你只关心“模型能不能得出正确答案”,可以忽略;如果你关心“模型是不是真的会推理”,这点必须盯着。
3.2 影响排名的硬因素
跑完评测以后我想多说一句:模型选型只是决定分数的因素之一,真正影响最终排名稳定的,反而是那些看起来不起眼的评估参数。
我自己踩过的坑主要有三个:
第一个是自一致性投票数。很多评测会给同一道题让模型采样多次,取多数答案。MathArena 在设置里把采样次数调到一个适中值,而不是盲目拉高。我发现采样次数从1提到8,分数提升非常明显,但从8再往上,收益开始递减,反而把推理模型本来就慢的推理时间拖得更长。所以别一上来就堆采样,先看基础准确率。
第二个是裁判模型的选用。LLM-as-judge 模式下,裁判模型本身也是模型,它也有盲区。如果你让一个数学能力不强的裁判去判困难证明题,它会把“步骤相似但思路不同”的正确解法判错,或者把“看似完整但有关键跳跃”的错误解法放行。我建议裁判模型至少要比被测模型强一个档次,而且要在每一道证明题上附带“标准答案关键步骤列表”,让裁判对照关键点打分。
第三个是输出长度限制。数学推理题动不动就输出上千 token,如果你的解码参数里把 max tokens 设小了,模型会在证明写到一半被截断,后半段干脆胡编。这个不是模型能力问题,是评测配置问题,但会把分数显著拉低。跑数学评测前,把上下文和输出长度都调足,是很必要的体检项。
3.3 观察:题目质量比数量重要
做评测久了你会发现一个反直觉的规律:题量越大,分数越有可能被“垃圾题”稀释。这里的垃圾题不是指题目太难或太简单,而是指区分度低的题。比如所有模型都会做或者都不会做的题,放进评测集只会拉平差距,对你观察能力差异毫无帮助。
MathArena 用“参赛者正确率”做难度锚定,本质上就是在控制区分度。一道题如果真实参赛者正确率是40%,那模型能解出来的概率也会有一个较宽的分布,这类题最能拉开模型差距。如果一道题正确率是90%,所有模型都做对,那它对排名毫无贡献。
所以我现在筛选评测题集时,会优先保证“每一道题都有明确难度证据”,而不是堆数量的好看。一百道有正确率依据的分层题,比两千道随手抓来的杂题有价值得多。
4. 踩坑记录与排查建议
这节直接上干货。按照 MathArena 的框架跑评测,等于在真实战场踩地雷。我把高频踩坑点整理成速查表,再讲几步我建议的排查流程。
4.1 常见问题速查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 模型答案正确但被判错 | 格式差异,如0.5与1/2未归一化 | 在解析器里加分数化简和小数等价规则 |
| 模型刷出过高的正确率 | 题源在训练语料里出现过 | 回退该题,换成时间锁之后的新题 |
| 裁判模型给出与标准答案矛盾的分 | 裁判幻觉,或提示词缺少标准步骤 | 要求裁判先复述标准答案关键步骤再打分 |
| 同一道题两次评测结果起伏大 | 采样随机性,温度过高 | 固定随机种子,开启自一致性投票 |
| 公式乱码、Latex解析失败 | 题源本身有转义错误 | 加一层 Latex 清洗函数,统一转义 |
| 困难题所有模型都做不出来 | 题太难,区分度为零 | 保留做压力测试,但不计入主排名 |
这里说两个我单独想强调的坑。
一个是“同名不同题”。有些竞赛会把同一道题换个人名、换个数字重新拿出来用。比如某题原本是“证明n是偶数”,隔年改成“证明n是奇数”,结构一模一样,只是条件翻转。如果去重只做文本相似度,这种变体题很可能漏掉,导致模型看似在做新题,实际在背旧模板。我用的是结构哈希:把题目的核心句式抽出来,去掉数字和专有名词,只比对骨架结构。这个办法能抓出大部分换皮题。
另一个是“解析器的宽松边界”。你既不能太严也不能太松。太严会把等价答案判成错误,太松会把5和5.0001也当成相等。我建议按竞赛类型分别设宽松度:只有唯一整数答案的题用严格匹配;答案可以带根号、分数、π表达式的题,用等价匹配;证明题则完全交给裁判模型加人工抽检。一刀切的解析策略,在数学评测里一定会出问题。
4.2 我建议的最小验证流程
如果不想第一次跑就跑飞,我建议按下面这个最小流程过一遍再大规模评测。
第一步,做解析器回归测试。挑一百道去年的真题,人工标好正确答案,跑解析器,检查能把多少题判对。这个环节的目标不是正确率百分之百,而是错误率低到不会影响排名——我给自己定的线是低于百分之二。
第二步,做小规模人工抽查。从评测题集里随机抽十道题,把被测模型输出的完整推理过程打出来,自己逐行看一遍。确认模型是正常推出来的,不是在题干里抄线索。这一步能筛掉很多训练数据里的隐性标签。
第三步,跑一个大小模型对照。拿一个你知道能力不强的轻量模型,和最强的模型各跑一遍全题集。如果最强模型没有显著优于轻量模型,先别急着怀疑题集,先回忆评测配置是不是有bug。两种能力差距明显的模型在同题集上跑不出差距,基本就是评测管线出了问题。
第四步,看错误分布而不是只看总分。把所有错误答案按“简单/中等/困难”分档统计,再按错因分三类:格式错、运算错、推理断裂错。看完这个分布,你对模型真实能力的判断会比任何总分都直观。
4.3 长期维护的补丁
无污染基准的最大敌人是时间。你今天选出来的新题,半年后可能就被某个训练语料收录了。所以这类评测集不能是一个静态文件,它必须持续更新。
我的做法是维护一条“新题流水线”:每个季度把最近举办完的竞赛题收集起来,做翻译、去重、解析、标注难度,然后并入评测集。每次更新都记录收录日期,打上时间戳。评测时严格按时间戳选择“模型的训练截止日期之后才收录”的题,而不是“我现在手头所有题”。
另一个长期维护点是跨年份去重。数学竞赛圈有些经典构造会被反复使用,今年这题考费马小定理,明年那题考欧拉定理推广,思路同源但表述不同。我会定期在全部历史题集上跑一遍结构相似度对比,把同源题打一个标记。这个标记不会删除题目,但会在报告里提示“该题与某年某题思路相似”,避免你把人家的迁移能力误当成创新推理能力。
我自己现在跑数学评测,已经默认把时间锁和结构去重写进基线配置了。哪怕只是做内部模型对比,不加这两步,测试结果我都不敢信。这套思路不仅适用于数学竞赛,任何“题库有限、答案公开”的领域都可以借鉴——物理竞赛、程序设计竞赛、围棋死活题,本质逻辑一模一样。
最后还有个体会想分享:评测框架里最值钱的不是那行调用模型的代码,而是题源干净度。一百分的裁判提示词,也救不了一题被背过的题。我见过有人花几周调评估prompt,就为了让模型分数涨两个点,但换一批干净新题,同一个模型分数能原地涨五个点。题管好了,分数自然站得住。