
1. 为什么我要用 MME-COT 重新测一遍 DeepSeek、OpenAI 和 KimiMME-COT 是港中文 MMLab 提出的视觉推理基准它和传统多模态评测最大的区别在于不只看最终答案对不对而是把思维链拆成质量、鲁棒性、效率三个维度来打分。换句话说它关心的是模型怎么想而不只是答没答对。这套基准覆盖数学、科学、OCR、逻辑、时空、通用场景六大领域共 1130 道精选题和 3865 个关键步骤标注感知任务和推理任务被严格区分开避免了过去很多榜单把看图识别和看图推理混在一起算分的问题。我关注这个基准很久了但一直有个现实痛点DeepSeek、OpenAI、Kimi 三家模型的 API 接入方式各不相同Key 管理、Base URL、请求格式、返回结构都有差异。想在同一批题目上做横向对比光是写三套适配代码就够折腾半天。更麻烦的是有些模型还需要处理图片转 caption 的中间步骤评测流程很容易被工程细节打断。这篇内容就是解决这个问题的。我会用 TaoToken 的统一 Key 和 API 通道把三家模型接到同一套调用逻辑里然后跑同一批 MME-COT 风格的视觉推理题逐项对比结果。适合想复现评测流程、又不想被多平台接入细节拖住的人。你不需要有很深的工程背景只要能跑 Python 脚本、会改配置文件就能跟着走完。先说清楚一件事MME-COT 官方仓库和数据集是公开的我这里不会重新发明评测指标而是聚焦怎么用统一通道把三家模型接进来、怎么发同一批请求、怎么验证返回结果。评测结论会结合官方论文里的发现来对照但重点始终是可复现的操作路径。2. TaoToken 统一通道的前置准备与 MME-COT 评测环境搭建在开始写调用脚本之前需要先把通道和环境准备好。TaoToken 的作用是提供一个统一的 API 入口让你用同一个 Key 就能访问 DeepSeek、OpenAI、Kimi 等不同厂商的模型省去分别注册、分别管理密钥的麻烦。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end API 入口是 https://taotoken.net/api 。第一步是拿到 Key。进入控制台的 API Keys 页面创建一个新 Key建议按项目命名比如 mmecot-eval方便后续区分。创建后立刻复制保存页面刷新后就看不到完整 Key 了。这个 Key 就是后面所有请求的凭证。第二步是确认你要调用的模型 ID。TaoToken 的模型列表里DeepSeek 系列、OpenAI 系列、Kimi 系列都有对应的模型标识。你可以在模型对话页面先手动试一次确认目标模型能正常返回再去写脚本。这一步很关键因为不同模型的图片输入支持程度不一样有的直接吃 base64 图片有的需要先转成 caption 文本再输入。MME-COT 论文里对 DeepSeek-R1 和 o3-mini 就是采用图片转 caption 后再输入的方式因为这两个模型本身不是原生多模态。你在选模型时要想清楚是要测原生视觉模型还是要测文本推理模型 caption的组合。第三步是本地环境。Python 3.9 以上即可需要装 requests 和 Pillow如果要处理数据集里的图片再加 datasets 和 huggingface_hub。建议用虚拟环境隔离避免和系统里的其他包冲突。目录结构可以这样组织一个 config 目录放配置一个 scripts 目录放调用脚本一个 data 目录放题目和图片一个 results 目录存返回结果。这样后面排查问题时定位很快。第四步是理解 MME-COT 的数据格式。数据集在 Hugging Face 上每条样本通常包含图片、问题、任务类型感知/推理、以及关键步骤标注。你不需要一次性加载全部 1130 题先抽 20 到 30 题做小规模验证确认调用链路通了再扩大规模。小步验证能帮你快速发现配置错误而不是跑了几百题才发现 Key 写错了。这里有个容易忽略的点MME-COT 区分直接回答和逐步推理两种 prompt 形式。你在构造请求时要把这两种模式都覆盖到否则鲁棒性指标就没法算。我的做法是在脚本里用一个参数控制 prompt 模板同一道题跑两次分别记录结果。环境准备好之后下一步就是写可复制的配置片段和调用脚本。3. 可复制的 Base URL、Key 与模型配置片段这一节给出可以直接抄的配置。我用 JSON 和 TOML 两种格式各写一份你按自己习惯选。核心是三件套Base URL、API Key、Model ID缺一不可。先看 JSON 格式适合 Python 脚本直接读取{ base_url: https://taotoken.net/api, api_key: sk-你的实际Key, models: { deepseek: deepseek-reasoner, openai: gpt-4o, kimi: kimi-k1.5 }, timeout: 120, max_retries: 3 }如果你用 TOML等价写法如下base_url https://taotoken.net/api api_key sk-你的实际Key timeout 120 max_retries 3 [models] deepseek deepseek-reasoner openai gpt-4o kimi kimi-k1.5注意 Base URL 后面不要多加/v1或/chat/completions具体路径在请求时拼接。Key 不要硬编码在脚本里用环境变量或单独的配置文件并且把配置文件加入.gitignore避免误提交。模型 ID 这块要特别说明上面写的只是示例实际可用的 ID 以 TaoToken 模型列表为准。你在控制台或模型对话页面能看到当前支持的完整列表。选模型时注意区分原生多模态和文本推理两类。GPT-4o 和 Kimi k1.5 属于原生支持图片输入的DeepSeek-R1 这类需要先把图片转成 caption。如果你要严格复现 MME-COT 论文里的设置DeepSeek 和 o3-mini 走 caption 路径其他走原生图片路径。如果你用的是 Claude Code 或类似的编码工具配置方式略有不同。以 settings 文件为例需要写全三件套{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的实际Key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }Cline 的 MCP 配置也是同样的逻辑Base URL、Key、Model ID 三个字段都要填对。Codex 的 auth.json 里则是把 base_url 和 api_key 写进对应字段。不管哪种工具只要这三件套对齐了通道就能通。配置写好后先别急着跑评测。用一条最简单的文本请求验证通道是否正常确认返回结构符合预期再进入图片推理环节。这样能把通道问题和模型能力问题分开排查。4. 用同一批 MME-COT 题目验证三家模型的返回结果现在进入核心环节写调用脚本跑同一批题目记录结果。我以 Python 为例给出关键代码结构。先写一个通用的请求函数把配置读进来根据模型名切换请求体import json import base64 import requests def load_config(pathconfig/config.json): with open(path, r, encodingutf-8) as f: return json.load(f) def encode_image(image_path): with open(image_path, rb) as f: return base64.b64encode(f.read()).decode(utf-8) def build_messages(question, image_pathNone, modecot): if mode cot: instruction 请逐步推理后给出答案。 else: instruction 请直接给出答案。 content [{type: text, text: f{instruction}\n{question}}] if image_path: b64 encode_image(image_path) content.append({ type: image_url, image_url: {url: fdata:image/jpeg;base64,{b64}} }) return [{role: user, content: content}] def call_model(cfg, model_key, messages): url f{cfg[base_url]}/v1/chat/completions headers { Authorization: fBearer {cfg[api_key]}, Content-Type: application/json } payload { model: cfg[models][model_key], messages: messages, temperature: 0 } resp requests.post(url, headersheaders, jsonpayload, timeoutcfg[timeout]) resp.raise_for_status() return resp.json()这段代码的关键点temperature 设为 0保证可复现图片用 base64 内联避免外链失效mode 参数控制直接回答还是逐步推理。接下来是跑批逻辑。从 MME-COT 数据集里抽一批题目对每个模型、每种 prompt 模式各跑一次把返回结果存成 JSONLimport jsonlines def run_batch(cfg, samples, output_path): with jsonlines.open(output_path, w) as writer: for sample in samples: for model_key in cfg[models]: for mode in [direct, cot]: messages build_messages( sample[question], sample.get(image_path), mode ) try: result call_model(cfg, model_key, messages) answer result[choices][0][message][content] writer.write({ id: sample[id], model: model_key, mode: mode, answer: answer, usage: result.get(usage, {}) }) except Exception as e: writer.write({ id: sample[id], model: model_key, mode: mode, error: str(e) })跑完之后你会得到一个 JSONL 文件每行是一条题目 模型 模式 回答的记录。接下来做结果验证。验证分两层第一层是格式验证确认没有大量报错、返回内容非空第二层是内容验证对照 MME-COT 的关键步骤标注看模型的推理链是否覆盖了必要步骤。格式验证可以快速统计import jsonlines total, errors, empty 0, 0, 0 with jsonlines.open(results/batch.jsonl) as reader: for obj in reader: total 1 if error in obj: errors 1 elif not obj.get(answer, ).strip(): empty 1 print(f总数 {total}报错 {errors}空回答 {empty})如果报错率超过 5%先别分析模型能力回去查配置和网络。如果空回答多检查是不是图片太大导致超时或者模型不支持该图片格式。内容验证这块MME-COT 论文用的是 GPT-4o 做步骤匹配和切分。你可以简化处理先人工抽看 10 条确认模型的推理步骤是否合理再决定要不要引入自动评分。对于召回率和精确率严格复现需要额外的评分模型成本较高。我的建议是先跑通流程拿到原始回答再根据研究目的决定评分深度。跑完一批之后你会看到一些有意思的现象。比如某些模型在感知任务上加了 CoT 反而变差这就是 MME-COT 强调的有害的过度思考。又比如长 CoT 模型的召回率不一定高说明它可能跳过了关键步骤却碰巧答对。这些现象和论文结论能对上也说明你的评测流程是有效的。5. 本篇常见错误排查401、local proxy failed、reading choices、OAuth跑评测过程中报错是常态。这一节把最常见的几类错误和排查路径列清楚省得你一个个搜。401 Unauthorized 是最常见的。原因通常有三个Key 写错、Key 过期、请求头格式不对。先检查Authorization头是不是Bearer sk-xxx的格式注意 Bearer 后面有一个空格。再确认 Key 没有多余的空格或换行。如果 Key 是从控制台复制的注意别把前后空白带进去。还有一种情况是配置文件里 Key 字段名写错脚本读到了空值这种要看日志里实际发出的请求头。local proxy failed 这类错误通常和本地网络环境有关。检查你的请求是否被本地代理拦截或者环境变量里有没有残留的代理设置。如果你在容器里跑确认容器能正常访问外网。这个错误的排查思路是先用 curl 发一条最简单的请求排除脚本层面的问题再逐步加回图片和复杂参数。reading choices 报错一般出现在解析返回结果时。原因是返回结构和你预期的不一致比如模型返回的是流式格式或者返回体里没有choices字段。解决办法是先打印完整返回体看清楚结构再取字段。有些模型在出错时返回的是error字段而不是choices你的代码要能兼容这两种情况。另外如果开了流式输出choices的结构会不一样评测场景建议关掉流式。OAuth 相关报错通常出现在用编码工具接入时。比如 Claude Code 或 Cline 如果配置成了 OAuth 登录模式而不是 API Key 模式就会报鉴权失败。解决方法是确认工具走的是 API Key 通道把 Base URL、Key、Model ID 三件套填全。如果工具同时支持 OAuth 和 API Key明确切换到 API Key 模式。Codex 的 auth.json 里如果残留了旧的 OAuth token也会冲突清掉重新写。还有一类不那么明显的问题请求成功但回答质量异常。比如模型答非所问或者把图片内容描述成完全无关的东西。这通常是图片编码出了问题比如 base64 字符串被截断或者图片格式不被支持。检查方法是把同一张图片单独发一次看返回是否正常。如果单张正常、批量异常可能是并发太高导致部分请求超时被截断。排查的通用原则先隔离变量。通道问题、配置问题、数据问题、模型问题一层层剥开。每次只改一个变量确认结果变化这样定位最快。把每次报错的完整信息记下来包括请求 ID、时间戳、模型名后面复盘时很有用。6. 把评测流程固化下来从一次性脚本到可复用管线跑通一次评测不难难的是让这套流程可复用。我的做法是把配置、调用、评分、报告四个环节拆成独立模块每个模块有明确的输入输出。配置模块负责读取 JSON/TOML做参数校验Key 缺失时直接报错退出而不是跑到一半才失败。调用模块负责请求重试、超时控制、结果落盘重试策略用指数退避避免短时间内反复打同一个接口。评分模块负责读取标注、匹配步骤、计算指标评分逻辑和调用逻辑解耦方便替换评分模型。报告模块负责把结果汇总成表格按模型、按任务类型、按 prompt 模式分组统计。这样拆的好处是下次你想加一个新模型只需要在配置里加一行不用改调用代码。想换一批题目只需要换数据文件不用动评分逻辑。想调整评分标准只改评分模块历史结果还能重新算。对于长期做模型对比的人可以考虑把评测任务放到 Coding Plan 里跑用更稳定的通道和更长的超时避免本地网络波动影响结果。如果只是偶尔验证一下模型能力用模型对话页面手动试几条就够了不必上完整管线。最后说一个实际经验评测结果的可信度很大程度上取决于题目抽样和评分标准的一致性。同一批题目换一批抽样排名可能就变了。所以报告结果时一定要写清楚抽了多少题、覆盖哪些任务类型、评分用的什么标准。这样别人才能判断你的结论适不适用于他的场景。MME-COT 的价值在于它把推理过程变成了可测量的对象。你用统一通道把三家模型接进来跑一遍得到的不只是分数更是对模型怎么想的一次观察。这个过程本身比最终排名更有意思。