mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
5592 字
15 分钟
我受够了看榜单,于是自己写了个大模型跑分工具
2026-09-27
2026-10-08

一、起因:我对榜单的信任,已经跌到和”网友自我介绍”一个水平了#

每次有新模型发布,整个互联网的反应都像过年——

“史诗级!MMLU 92 分!全面超越 GPT-4!”

然后我兴冲冲地接上 API,问了三个问题,吐了三次血。

于是在某个深夜,我盯着又一个”吊打一切”的模型榜单,做出了一个理性的决定:自己写一个跑分工具。

原因很简单,榜单这东西,坑实在太多了:

坑一:分数可能是背出来的。 公开基准一旦进了训练语料,那就不是考试,是默写。你考 MMLU,它背 MMLU,这跟学生提前偷看答案没区别——这叫训练数据污染(contamination)。

坑二:你调的模型可能不是你以为的那个模型。 你付的是满汉全席的钱,端上来的可能是泡面——只不过叉烧是画上去的。API 中转站偷换模型,是真实存在且相当普遍的现象。

坑三:榜单测的,往往不是你要的。 榜单比你关心的”代码能力”,但你的活儿是”写小红书文案”。榜单拿了 95 分,跟你有什么关系?

所以就有了 model-bench——一个用 Go 写的、单文件、双击即用的本地大模型跑分工具。

自己出题、自己判卷、自己说了算。 至于能不能考出真相……我们往下看。


二、先补课:模型测试到底在测什么#

在炫耀我的玩具之前,得先把场子热一下。模型评测这玩意儿,看着就是”出题、答题、对答案”,实际上水比想象中深。

2.1 评测的三个段位#

段位玩法代表人话版
青铜:客观题标准答案精确匹配GSM8K、MMLU、BBEH对就是对,错就是错,没有感情
黄金:执行型真把代码跑起来HumanEval、LiveCodeBench不看你吹,看你跑不跑得通
钻石:主观题让大模型当裁判AlpacaEval、Arena请一个 AI 来点评另一个 AI,然后祈祷它不偏心

成熟的做法是三段位混搭。只考客观题,“写个网页""画张图”这种开放活儿根本没法测;只靠主观题,那评测就成了玄学——这次的 8 分和下次的 8 分,可能不是同一个 8 分。

2.2 几个你迟早要搞懂的指标#

  • Pass@1:给你一次机会,一次过不过。代码界最爱用的指标——毕竟用户不会给你第二次机会。
  • Token:模型世界的计价单位,输入算 prompt_tokens,输出算 completion_tokens,你的钱包按这个缩水。
  • TTFT(首字延迟):从你发问,到它吐出第一个字。决定”它多久开始打字”。
  • TPS(每秒 token 数):它打字的速度。决定”它打字有多快”。

一个模型可以 TTFT 很短(反应神速)但 TPS 很低(一个字一个字往外蹦),体验就像一个抢答特别积极、但说话特别慢的人——着急又无能为力。

  • 温度(Temperature):越低越死板,越高越发疯。评测时必须调到接近 0,否则同一道题你问两遍,能收获两个不同的错误答案——这不叫评测,叫抽奖。

2.3 两个能把人逼疯的坑#

坑一:请 AI 当裁判,结果裁判是个”追星族”。

用大模型当裁判很省事,但它自带偏见:

  • 品牌偏置:它要是知道这答案是 GPT 写的,笔就开始软了。解法:裁判 prompt 里一个字都不许提被测模型的名字。
  • 位置偏置:两个答案一比,它永远觉得前面那个更好。解法:把顺序换一下再评一次。
  • 自己还发热:裁判也是有温度的,它随机起来比被测模型还离谱。解法:裁判强制 temperature ≈ 0,让它像个没有感情的机器。

model-bench 的策略是:三管齐下。裁判 prompt 不提模型名、强制超低温(0.0001)、输出强制 JSON。

坑二:把”话没说完”当成”答错了”。

这一条我踩过,气得想砸键盘。

推理模型(o1、R1 那一类)有个习惯:先在心里默念三千字,最后才说正事。你要是不懂事地把 max_tokens 设成了 2048——很遗憾,它思考还没结束,额度先没了,正文一个字没吐。

这时候你的跑分结果是什么?全线飘红,惨不忍睹。

但模型做错什么了吗?没有。是你的预算太小,让它”想太多,还没开口就晕过去了”。

解法:识别 finish_reason == "length",把它标成配置错误,而不是判它错。这一条,是我认为一个评测工具”讲不讲武德”的分水岭。

2.4 数据污染:题目得比模型的记性”新”#

评测题目最好晚于模型的训练截止时间,否则你测的不是智商,是记忆力。

一个体面的题库,会给每道题标上”出生年月”,并且优先挑那些”模型出生之前还没发生的题”。你拿 2023 年的题考 2026 年的模型,它答对了也不值得鼓掌。

2.5 模型测谎:你调的到底是谁?#

这是评测之外的另一门手艺:验证你手上的 API 是不是货真价实。

思路是扔一堆精心设计的”探针”进去,收集它的行为指纹:

  • 拒答阶梯:给它一串从”人畜无害”到”你确定要问这个”的问题,看它在第几级翻脸。不同家族的脾气不一样,翻脸的位置也不一样。
  • 格式口音:项目符号用 - 还是 *?代码块标不标语言?——这些是模型微调时留下的口音,跟东北人和广东人说普通话的差别一个道理。
  • 不确定性习惯:让它估个数,看它爱给整数还是零头。
  • 自述交叉验证:直接问它是谁、知识截止到几号,再和行为指纹对一对。

重点来了:单一证据全都不可信。 一个模型说自己是 GPT-4,这句话的可信度,约等于一个网友在自我介绍里写”本人幽默风趣”。

得靠交叉验证 + 明确的置信度。而且结论里必须敢说那句最难说的话——“证据不足,我不知道。“


三、登场:model-bench 长什么样#

3.1 一句话介绍#

一个用 Go 写的、单文件、双击就用的本地大模型跑分工具:内置六大维度题库,能客观判分、能跑代码沙箱、能请 AI 当裁判,还附赠一个”测谎仪”。

3.2 为什么这么选技术栈#

部分选型心里话
后端Go 1.26编成一个 exe,甩给别人就能用,不用教他配环境
数据库SQLite + GORM(纯 Go 驱动)免 CGO、零配置,数据跟着 exe 走,体面
前端Vue,go:embed 塞进二进制一个文件搞定,用户不需要知道 Node 是什么
题库内嵌 JSON离线可用,题库跟程序版本锁死,不会对不上
限速x/time/rate令牌桶控 RPM,防止把人家 API 薅秃

build.bat 两步走:前端 build → Go embed → 吐出一个 model-bench.exe。双击,自动开浏览器,开跑。 没有安装向导,没有依赖地狱,没有”请先阅读 500 页文档”。

3.3 架构一览#

main.go
  └── api        HTTP 路由、SSE、静态托管
        └── runner   测试执行引擎(队列 / 并发 / 取消 / 落库)
              ├── llm      OpenAI 兼容客户端(限速 / 重试 / 超时)
              ├── judge    判分器(按题型分发)
              └── sandbox  Python 代码沙箱
        └── audit    模型鉴定引擎(94 支探针 + 行为指纹)
        └── dataset  题库加载
        └── store    GORM / SQLite

3.4 六大维度:一次全方位体检#

维度中文名题目出处题量判法
reasoning逻辑推理BBEH20对答案
math数学能力AIME 202630对答案
coding代码能力USACO 2025-26 赛季15真·跑代码
knowledge知识问答HLE 纯文本子集20对答案
chinese中文能力Chinese-SimpleQA20对答案
frontend前端生成自建10请裁判

一共 115 题。其中推理、数学、代码三个维度完全不依赖裁判——这构成了”免裁判模式”:你要是懒得配裁判模型,也能把它按在地上摩擦。

3.5 数据模型:六张表撑起一切#

  • ModelConfig:模型配置。用 Role 区分 test(考生)和 judge(阅卷老师)。任何 OpenAI 兼容端点都能接,不挑食。
  • TestRun:一次考试。状态机 pending → running → completed/cancelled/failed,记录进度和总分。
  • QuestionResult:每道题的答卷。原始答案、提取后的答案、对错、评语、耗时、token 用量,全都留着。
  • DimensionScore:各维度成绩单。
  • FunResult / AuditResult:趣味测试和测谎报告。

四、判分引擎:这才是技术活儿#

模型不会乖乖配合。它不会只写一个”B”,它会先抒情五百字,再在最后一句把答案藏着掖着。所以判分的第一要务,不是”比答案”,而是”把答案从废话里刨出来”。

4.1 六种题型,六种打法#

switch q.Type {
case "choice":        // 选择题
case "numeric":       // 数值题
case "short_answer":  // 短答案
case "code":          // 代码(丢进沙箱真跑)
case "qa_judged":     // 裁判评分问答
case "frontend_html": // 前端生成(请裁判)
}

4.2 绝活:三级退化提取#

以选择题为例。模型可能回:

“经过我严谨的分析……(此处省略八百字)……综合来看,答案是 B。” 或者更离谱,就回一个孤零零的字母:“B” 或者回:“(B)”

所以提取要层层兜底,一条路走不通就换下一条:

  1. 先找”答案是 B""answer is B”这种明示的;
  2. 找不到就从结尾往前翻,找一个孤零零的字母(还得容忍它后面跟着个句号);
  3. 再找不到,就全文捞出最后一个独立的大写字母,赌一把。

数值题同理,“刨答案”的顺序是:#### 42(GSM8K 祖传格式)→ \boxed{42}(LaTeX 风格)→ “答案是”关键词 → 兜底取全文最后一个数字(赌徒做法,但经常能赌赢)。刨出来再做浮点比较,容差 1e-6;实在比不了就退化成字符串裸比。

短答案题更狠,四路比对:直接比 → 数值比 → 词表比。最后这个是给”排序题”准备的——只要元素集合一样,你排的顺序对不对、用逗号还是空格,我全当没看见。

4.3 代码判分:不看你吹,看你跑不跑得通#

代码题光比字符串是耍流氓,必须真执行。项目上了两套:

① LiveCodeBench 风格(标准输入输出)——正经做法:

# 逐个测试用例跑 solution.py,比对输出
for i, t in enumerate(tests, 1):
    p = subprocess.run([sys.executable, "solution.py"], input=t["input"], ...)
    if p.returncode != 0:      print(f"RUNTIME_ERROR_ON_TEST_{i}"); exit(1)
    if p.stdout.strip() != t["output"].strip(): print(f"WRONG_ANSWER_ON_TEST_{i}"); exit(1)
print("ALL_TESTS_PASSED")

全部用例通过、且屏幕上打出 ALL_TESTS_PASSED,才算这题过关。

② HumanEval 风格(断言式)——保留兼容:把解题函数和测试断言拼一块儿,让断言自己喊”我过了”。

4.4 沙箱:跑陌生代码,得先把笼子锁好#

跑一个陌生模型生成的代码,性质等同于捡起路边一个来路不明的 U 盘插电脑上。必须沙箱。

sandbox 包干了四件事,每一件都是被现实教育出来的:

  1. 临时目录隔离:每次执行建个临时文件夹,跑完就删,来无影去无踪。
  2. 超时强杀进程树:Windows 下 Python 启动器会偷偷派生子进程,普通 kill 杀不干净,所以直接祭出 taskkill /T /F——连根拔起,绝不手软。
  3. 堵住 input():把标准输入接成一个空管子,防止程序卡在那儿等一个永远不会来的输入,像个等人回消息的舔狗。
  4. 自动找 Python:依次试 python → py -3 → python3,全都没有就把这个维度标记为”无法判分”,而不是当场崩溃。

4.5 前端生成:请裁判,但先把丑话说在前面#

前端任务没有标准答案,只能请裁判。但项目把丑话说在了前头:

  • 先做静态体检:从回复里刨出 HTML,要是长度不到 100、或者连个 < 都没有,直接判 0,裁判的调用费省了。
  • 四个维度打分:结构、需求符合度、美观、交互,各 02.5 分,合计 010。
  • 不信裁判的算术:要求它输出 JSON,但每一项都做边界裁剪(clamp(0, 2.5)),而且总分由代码自己重算——怕裁判自己算错总分(它真的会)。
  • 解析失败就重问一次。
  • 全程不提被测模型的名字,防追星。

4.6 趣味测试:鹈鹕与糖果#

严肃评测之外,藏了两个社区名场面,用来一眼感受模型的”手感”:

  • 鹈鹕测试:让模型生成”一只鹈鹕骑自行车”的 SVG。这个 prompt 由 Simon Willison 在 2025 年带火,堪称 AI 圈的祖传考试——考验的是空间组合想象力和 SVG 生成功底。生成的 SVG 还会被丢进 iframe 沙箱预览,外加 Content-Security-Policy 禁脚本,双保险,防止它偷偷藏点恶意脚本。
  • 糖果测试:一道精心设计的抽屉原理题,答案是 21。题面里塞了个”西瓜味”当干扰项,所有最坏情况都停在 20 颗,第 21 颗必中。专治”看到数字就上头”的模型。

4.7 测谎仪:94 支探针伺候#

audit 包是个完整的换模检测引擎,探针库来自开源项目 BazaarLink LLMprobe-engine(AGPL-3.0):

  • 五大组:身份识别、子模型识别、安全探针、完整性检查、品质测试。
  • 多种判法:精确匹配、关键词(支持正则)、特征采集、token 计量校验(防虚报用量)、流式检测、长上下文金丝雀。
  • 性能实测:TTFT 采样 8 次取中位数;TPS 用一段 400 字长文现场计时。
  • 结论分级:一致 / 家族相符 / 疑似换模 / 资料不足 / 模棱两可。

最精彩的场景:API 名字写着 A 家族,行为指纹却指向 B 家族——妥妥的”嫌疑人”,直接标”疑似换模”。

而且报告末尾老老实实写着免责声明:“相符 ≠ 保证没换过,单次通过 ≠ 长期诚实。”

一个工具最性感的品质,不是它宣称自己多准,而是它知道自己哪里不准。


五、分数怎么算:克制,再克制#

分数怎么算,直接决定榜单能不能信。这里的规则,朴素得近乎无聊——因为我怕它花里胡哨地骗我。

5.1 维度分#

普通维度:答对题数 ÷ 有效作答数 × 100
frontend:裁判均分 ÷ 10 × 100

注意分母是”有效作答数”,把超时、被截断、API 报错全踢出去了。否则你家网络一抖,模型就无辜掉分——这锅模型不背。

5.2 综合分#

综合分 = 所有"有效维度"(answered > 0)的等权平均

两个讲究:

  • 等权:不搞加权,省得被人说”你这就是为了抬高某家分数才这么配权重的”。
  • 没测出来的维度不参与:某个维度全军覆没(比如没装 Python),它就不进平均,而不是拿 0 分去拖累总分。要是所有维度都没数据,综合分就是 NULL——坦坦荡荡地显示”没测出来”,而不是拿个 0 假装很严格。

5.3 排行榜#

每个模型只取最近一次成功完成的考试成绩。重测就覆盖旧成绩,不会出现同一个模型霸占半个榜单的奇观。


六、执行引擎:并发、进度、以及一个怕抢锁的程序员#

上百道题,串行太慢,无脑并发又会被 API 限流教做人。

6.1 生产者—消费者#

生产者(投喂题目)──► jobs 队列 ──► N 个 worker(问模型 + 判分)──► resultsCh ──► 单个 writer(落库)
  • 并发数:默认 4,上限 8。并发开太高,只会被 API 限流揍得更惨。
  • 单题超时 180 秒:给推理模型留足”思考人生”的时间。
  • 裁判超时 120 秒:单独控制。

6.2 为什么只留一个收银员#

SQLite 的写入是串行的,几个 goroutine 同时写就会撞锁。所以设计成:一群 worker 只管干活,结果全丢给一个 writer,排队落库。

这是一个非常典型、也非常香的取舍——用架构消灭锁竞争,而不是用锁去硬刚。

6.3 实时进度:SSE 直播#

前端用 SSE(Server-Sent Events) 实时收进度,不用轮询。事件有:

  • progress:每做完一题推一次
  • dimension_done:某个维度全部完成,推该维度得分
  • run_done / error:收工或翻车

于是你能亲眼看着雷达图一个角一个角地长出来——这大概是我做过最有仪式感的进度条。

6.4 一些”不性感但救命”的细节#

  • 同时只允许一场考试,免得几场跑分互相抢 API 额度。
  • 随时可取消,已做完的题目结果照样留着。
  • 指数退避重试:撞上 429 / 5xx / 网络抖动,就按 2s → 4s → 8s 道歉式重试,最多 3 次;至于 4xx 这种”你请求本身就有问题”的,直接失败,别浪费重试。
  • 令牌桶限速,按你配的 RPMLimit 走,优雅地控制请求节奏。

七、上手:三步开始折磨模型#

:: 1. 构建(需要 Node + Go 环境)
build.bat

:: 2. 运行(双击或命令行)
model-bench.exe

启动后浏览器自动打开 http://127.0.0.1:8080。开整:

  1. 在模型管理里加一个被测模型——填 BaseURL、APIKey、ModelName,任何 OpenAI 兼容端点都欢迎;
  2. 想跑”前端生成/裁判类”维度时,再加个裁判模型(建议请个聪明点的当考官);
  3. 新建运行、勾维度、开跑,欣赏雷达图慢慢长出来。

环境变量(想改就改):

变量默认值说明
BENCH_PORT8080监听端口
BENCH_DBmodel-test.db数据库文件
BENCH_LOG_DIRlogs日志目录

八、题库从哪来:新,且诚实#

题库不是随便扒的,每个数据集都标了来源和许可证(dataset/LICENSES.md)。核心原则两条:能新则新,不能新就老实交代。

  • 数学用 AIME 2026、代码用 USACO 2025-26 赛季——都是模型出生之后才发生的真·新题,天然抗污染。
  • **推理(BBEH)、中文(Chinese-SimpleQA)**是”如实标注的遗留项”——没有更新的同类基准,就承认,而不是硬装它很新。
  • 知识维度换成 HLE 之后难度飙升,前沿模型也只能拿 10~30 分。分数掉下来是正常现象,别慌——维度之间的相对比较依然有意义。

抗污染的真谛,不是找一个”永不过期”的题库——那种东西不存在。 而是清楚知道自己的题是新是旧、脏不脏,然后在结论里如实说出来。


九、写在最后:几条血泪心得#

做完这个项目,有几句话想留给同样对模型评测感兴趣的同行:

  1. 能用客观判分就别用裁判。 精确匹配 > 跑代码 > 请 AI 评分。LLM 裁判是最后手段,不是第一选择——请神容易送神难,请个追星的裁判更难。
  2. 把”配置错误”和”模型答错”分开。 被 max_tokens 截断、超时、API 报错,这些不是模型的锅。一个评测工具的公信力,全建立在这种细节的较真上。
  3. 分数要敢为空。 没测出来就显示”空”,别拿 0 分糊弄。0 分和”没数据”是两码事,混为一谈就是耍流氓。
  4. 承认能力边界。 换模检测不可能 100% 准,那就明说。越是敢承认自己局限的工具,用户越敢信它。
  5. 工程细节决定生死。 单文件分发、自动找 Python、SSE 直播进度、优雅退出……这些不性感的活儿,才是一个工具能不能被真正用起来的关键。漂亮的功能让人惊艳,扎实的细节让人留下。

评测这件事,说到底就是在回答一个问题:

“这个模型,到底行不行?”

而一个负责任的答案,从来不是一句”它得了 92 分”,而是——

“在你关心的场景下,用可复现的方法、抗污染的题,测出来它表现如何……以及,我有多大把握。”

至于那个 92 分?先让它在我这儿考完再说。


model-bench 是个本地自用的小工具,结构清晰、依赖极少,如果你想练手,是个相当不错的选择。祝你和 API 的每一次对话,都不会被”疑似换模”温暖。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

我受够了看榜单,于是自己写了个大模型跑分工具
http://www.zhima778.cloud/posts/001/
作者
知不知马
发布于
2026-09-27
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录