1. 复旦测评13家大模型高考数学成绩,为什么值得亲手复现一遍
复旦 NLP 实验室 LLMEVAL 团队那份高考数学评测出来之后,我朋友圈里做模型应用的人几乎都在转。核心结论很直接:2024 高考数学新 II 卷的 14 道客观题里,字节豆包客观题正确率 74.66%,在 13 家大模型里排第一,阿里千问和 GPT-4o 分列二三位;新 I 卷里豆包也进了前列。GPT-4o 是 OpenAI 今年 5 月发布时重点秀数学能力的模型,结果被部分国产模型反超,这个反差就是热点本身。
但热点归热点,真正做应用的人关心的不是「谁第一」,而是「我自己业务里该选哪个模型」。榜单是别人的题、别人的判分口径、别人的调用参数,你直接拿结论去选型,很容易踩坑。比如同一道题,temperature 设 0 和设 0.7 结果可能完全不同;再比如有些模型默认不开思维链,你直接问答案它可能连步骤都省了,正确率自然低。
所以这篇不聊八卦,聊怎么用一套统一的 Key 和 API 通道,把 13 家模型拉到同一个脚本里跑同一批高考数学题,自己统计得分。这样你得到的不是「复旦说豆包第一」,而是「在我的调用参数下,豆包、千问、GPT-4o 分别答对几道」。这个结论才是你能拿去写技术方案的。
适合谁看:正在做模型选型的产品/算法同学、想批量对比多家模型效果的开发者、以及单纯想验证「榜单结论在我这儿成不成立」的技术爱好者。下面从接入配置讲到批量跑题脚本,再到得分统计和报错排查,全部可复制。
2. TaoToken 统一 Key 前置准备:一个通道调 13 家模型
要复现多模型对比,第一个拦路虎不是数学题,是「你得有 13 家的账号和 Key」。GPT-4o 要一家、豆包要一家、千问要一家、文心一言又要一家,注册、实名、充值、看各自的文档格式,光配环境就能耗掉一整天。而且每家的 SDK 和请求体结构都不一样,写对比脚本时你要维护 13 套调用逻辑,改一个参数要改 13 个地方。
我试过用统一网关来收敛这件事,TaoToken 就是这类通道:它对外暴露一套 OpenAI 兼容的接口,你用同一个 Base URL 和同一个 API Key,通过改model字段就能切换到不同厂商的模型。对复现评测来说,这意味着一份脚本、一个循环、一张模型列表,就能把 13 家跑完。
先把地址记清楚,后面配置要用:
- 官网入口:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=
- API 基址:https://taotoken.net/api (这个不加 UTM,直接作为 Base URL 用)
拿 Key 的路径是:进官网后到控制台的 API Keys 页面创建,模型对话页可以直接试跑单条请求,接入文档页有各语言的示例。这几个 deep link 我也放一下,方便你直接跳:
- 模型对话(先试一条):https://taotoken.net/console/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
- 控制台(建 Key):https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
- API Keys 管理:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
这里要强调一个概念:TaoToken 是统一调用通道,不是编辑器替代品,也不是让你绕过什么。它的价值在于把「多厂商鉴权 + 多套请求格式」收敛成「一套 OpenAI 兼容格式」,让你把精力放在题目和判分上,而不是环境配置上。对做评测复现这种「要横向拉多家」的场景,这个收敛特别值。
模型 ID 这块,不同厂商命名不一样,比如豆包系列、千问系列、GPT-4o 各有各的写法。你不用背,接入文档里有当前支持的模型清单,脚本里把 model 字段填成清单里的 ID 即可。下面配置章节我会给一个可复制的模型列表模板,你按文档核对一遍就能用。
3. 可复制配置:settings.json / config.toml / .env 三件套
配置这块我按三种常见形态给,你按自己用的工具挑一个。核心三件套永远是:Base URL、API Key、Model ID。这三个填对,剩下就是发请求。
3.1 通用 .env 配置(Python 脚本用)
如果你直接写 Python 脚本跑批量题,用.env最省事:
# .env TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_API_KEY=sk-你的Key粘贴在这里 # 模型 ID 按接入文档核对,下面只是占位示例 TAOTOKEN_MODEL_DOUBAO=doubao-pro TAOTOKEN_MODEL_QWEN=qwen-max TAOTOKEN_MODEL_GPT4O=gpt-4o注意 Base URL 结尾不要多加/v1或斜杠,OpenAI 兼容客户端一般会自己拼/chat/completions,多写了会 404。Key 从 API Keys 页面复制,别带空格。
3.2 Claude Code / 类 CLI 工具的 settings.json
如果你用 Claude Code 这类 CLI 工具做代码或问答,配置通常落在settings.json。路径按你工具的实际约定来,字段结构如下:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key粘贴在这里", "ANTHROPIC_MODEL": "claude-sonnet-4" } }这里三件套对应关系是:Base URL 填https://taotoken.net/api,Key 填你创建的,Model ID 填文档里对应的 Claude 系列 ID。改完重启工具生效。
3.3 Codex 类工具的 auth.json
如果你用的是 Codex 风格的工具,鉴权常落在auth.json:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key粘贴在这里", "model": "gpt-4o" }同样三件套:Base URL、Key、Model ID。不同工具字段名可能略有差异,以接入文档为准,但值就这三个。
3.4 模型列表模板(复现 13 家用)
把要对比的模型 ID 写成一个列表,脚本里循环。下面结构你按文档核对后替换:
MODELS = [ {"name": "字节豆包", "id": "doubao-pro"}, {"name": "阿里千问", "id": "qwen-max"}, {"name": "GPT-4o", "id": "gpt-4o"}, {"name": "文心一言", "id": "ernie-4.0"}, # ... 其余模型按接入文档清单补齐 ]配置阶段最容易犯的错是把 Base URL 写成官网首页地址。记住:请求走的是https://taotoken.net/api,不是带 UTM 的那个官网链接。UTM 链接是给人点的,API 基址是给程序调的,两者别混。
4. 验证请求与批量跑题:13 家模型 II 卷数学得分统计
配置好了先别急着跑 13 家,先用一条请求验证通道通不通。
4.1 单条验证请求
import os from openai import OpenAI from dotenv import load_dotenv load_dotenv() client = OpenAI( base_url=os.getenv("TAOTOKEN_BASE_URL"), api_key=os.getenv("TAOTOKEN_API_KEY"), ) resp = client.chat.completions.create( model=os.getenv("TAOTOKEN_MODEL_DOUBAO"), messages=[ {"role": "user", "content": "2024高考数学新II卷第1题:已知集合A={-1,0,1},B={x|x^2≤1},求A∩B。只给最终答案。"} ], temperature=0, ) print(resp.choices[0].message.content)跑通会看到模型返回答案。如果这里就报错,先跳到第 5 节排查,别往下走。
4.2 批量跑题脚本
验证通过后,把 14 道客观题整理成一个列表,循环 13 家模型。判分逻辑:客观题答案通常是选项或数值,做字符串归一化后比对。
import os, json, re from openai import OpenAI from dotenv import load_dotenv load_dotenv() client = OpenAI( base_url=os.getenv("TAOTOKEN_BASE_URL"), api_key=os.getenv("TAOTOKEN_API_KEY"), ) # 题目与标准答案(示例结构,实际按你整理的 II 卷客观题填) QUESTIONS = [ {"qid": 1, "text": "已知集合A={-1,0,1},B={x|x^2≤1},求A∩B。", "answer": "A"}, {"qid": 2, "text": "……", "answer": "B"}, # ... 共 14 道 ] MODELS = [ {"name": "字节豆包", "id": "doubao-pro"}, {"name": "阿里千问", "id": "qwen-max"}, {"name": "GPT-4o", "id": "gpt-4o"}, # ... 补齐 13 家 ] def normalize(s): s = s.strip().upper() s = re.sub(r"[^A-D0-9\.\-]", "", s) return s def ask(model_id, question): resp = client.chat.completions.create( model=model_id, messages=[ {"role": "system", "content": "你是数学答题助手,只输出最终答案,不要过程。"}, {"role": "user", "content": question + "\n只给最终答案。"}, ], temperature=0, ) return resp.choices[0].message.content results = {} for m in MODELS: correct = 0 detail = [] for item in QUESTIONS: try: out = ask(m["id"], item["text"]) ok = normalize(out) == normalize(item["answer"]) correct += int(ok) detail.append({"qid": item["qid"], "out": out, "ok": ok}) except Exception as e: detail.append({"qid": item["qid"], "error": str(e)}) acc = correct / len(QUESTIONS) * 100 results[m["name"]] = {"correct": correct, "total": len(QUESTIONS), "acc": round(acc, 2), "detail": detail} print(f"{m['name']}: {correct}/{len(QUESTIONS)} = {acc:.2f}%") with open("math_eval_result.json", "w", encoding="utf-8") as f: json.dump(results, f, ensure_ascii=False, indent=2)跑完你会得到一张自己的成绩表。实测下来,同一批题在不同 temperature 下结果会浮动,所以对比时务必固定temperature=0,否则你统计出来的排名没有可比性。另外注意:复旦那份评测用的是 14 道客观题,你复现时题目数量、题目本身要和标准答案严格对应,判分归一化规则也要统一,不然「豆包 74.66%」这种数字你复现不出来是正常的,因为口径不同。
4.3 结果对照
跑完可以拉一张表,把「我的复现结果」和「复旦公布结果」并排放:
| 模型 | 复旦 II 卷排名 | 我的复现正确率 | 备注 |
|---|---|---|---|
| 字节豆包 | 第 1 | 脚本输出 | 固定 temp=0 |
| 阿里千问 | 第 2 | 脚本输出 | 固定 temp=0 |
| GPT-4o | 第 3 | 脚本输出 | 固定 temp=0 |
如果你的排名和复旦一致,说明通道和判分没问题;如果不一致,先查是不是模型 ID 填错、或者某家默认开了思维链导致输出格式不同。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
复现过程中最容易卡在这几类报错,逐个说。
401 Unauthorized:九成是 Key 问题。检查.env里TAOTOKEN_API_KEY有没有多余空格、有没有把官网 UTM 链接误当 Key、Key 是不是在 API Keys 页面创建后没复制全。还有一种情况是 Key 被删了或额度用尽,去控制台确认状态。
local proxy failed / connection error:这类通常是 Base URL 写错。确认是https://taotoken.net/api,不是官网首页,也不是带/v1的地址。如果你本地有网络层工具干扰,先关掉再试。注意别把这类报错和任何网络规避手段联系起来,就是单纯地址或本地环境问题。
reading choices 报错(KeyError: 'choices' / 返回体没有 choices 字段):说明返回的不是标准 chat completion 结构。常见原因是 model ID 填错,通道把请求路由到了不支持该格式的模型;或者你请求的模型 ID 在文档里根本不存在。去接入文档核对 model 字段,确保拼写一致。
OAuth 相关报错:如果你用的是 Claude Code 这类带 OAuth 流程的工具,报 OAuth 错通常是settings.json里字段名不对,或者工具版本和配置结构不匹配。确认三件套字段(Base URL、Key、Model ID)都填了,且 JSON 没有语法错误(多余逗号最常见)。改完重启工具。
返回空内容或只有思考过程:有些模型默认输出思维链,你判分时拿到一堆过程文字,归一化后匹配不上答案。解决办法是在 system prompt 里明确「只输出最终答案」,或者调大 max_tokens 防止被截断。
13 家里某几家一直超时:先单独用模型对话页试那家的模型 ID,确认通道侧是否正常。如果单条能通、批量超时,多半是你脚本并发太高,加个time.sleep(1)或降低并发数。
排错时建议按「单条验证 → 单模型批量 → 全模型批量」三步走,哪一步挂就在哪一步查,别一上来就跑 13 家,报错信息会混在一起。
6. 把复现脚本用起来:从评测到选型的下一步
跑完这一轮,你手里就有了一份「自己口径下」的 13 家模型高考数学成绩表。它的价值不在于推翻或证实复旦的结论,而在于你知道了在固定 temperature、固定 prompt、固定判分规则下,各家模型在你这条通道上的真实表现。这个数据可以直接进你的选型文档。
如果你要长期做这类多模型对比,甚至想把对比脚本接进 CI 定期跑,那单次调用按量付费的模式可能不如包月划算,可以看看 Coding Plan 这类长期方案:https://taotoken.net/console/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
如果只是想再手动试几条题、换换 prompt 看效果,用模型对话页最快:https://taotoken.net/console/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
要新建或管理 Key,去 API Keys 页:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
各语言接入示例和模型清单在文档里:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
最后一个实操建议:把QUESTIONS和MODELS抽成独立的 JSON 文件,脚本只负责读文件和跑循环。这样下次换一批题(比如换成物理、化学)或者换一批模型,你不用改代码,改配置就行。评测这件事,可复现的前提是配置和逻辑分离,不然跑第二次你自己都记不清上次改了啥。