
OpenRouter 实战避坑:同一个模型,换个 Provider 就像换了另一个模型
同一个 DeepSeek V4 Flash,不同 Provider 的 TAU-Bench 成绩能差二十多个百分点。一位处理过 1800 万条消息的开发者,把用 OpenRouter 踩过的 10 个坑整理成了清单。
原文来源:Mo Moustafa — 处理过 1800 万条消息之后,作者把用 OpenRouter 调开源模型踩过的坑整理成了一份清单。
表面上看,用 OpenRouter 很简单:一个 API Key,几百个模型,OpenAI 兼容接口。但作者说,往下走全是坑。
背景值得先说一句。作者在做一个叫 Olly 的 AI 助手,跑在 iMessage 里,用的是 OpenRouter 上的开源模型。到目前为止 Olly 处理了超过 1800 万条消息,其中大约三分之一走开源模型。这个量级足以把每个边界情况都撞上一遍。
先统一词汇:模型指那堆权重;Provider 是 OpenRouter 把你路由过去的那家公司,权重跑在他们的 GPU 上,用他们选的精度和"专有"优化,配他们自己的 XML 和工具解析器——也就是说,每家也有一份"专有"的 bug 清单。当你要 deepseek/deepseek-v4-flash,背后是大约 20 家你多半没听说过的公司。纸面上是同一个模型,实际上差别很大。
1. 同一份权重,Provider 之间能差 20 个点
OpenRouter 会给同一模型上的不同 Provider 跑基准,常见的是 GPQA Diamond 和 TAU-Bench Airline(工具调用任务)。以 DeepSeek V4 Flash 0731 为例,所有 Provider 提供的权重完全一样:
- DeepSeek 官方:GPQA 90%,TAU 81%
- DigitalOcean(同样权重):75% 和 58%
大多数托管商在工具调用上比官方低 5 到 7 个点,还有四家在知识题上直接崩掉。对 Agent 来说 TAU 才是有意义的分数,二十多个点的差距不是噪声。作者补充说 7 月更夸张:Fireworks 的 TAU 只有 46%,和官方差了三十多个点。
结论很简单:信任某个 Provider 之前,先看最贴近你工作负载的那个基准;换模型时也要重新看,因为同一批 Provider 在 GLM-5.3 上的表现完全不同。
—— 广告 ——
2. 图像任务上的不确定性
作者在图像任务上注意到反常行为,就把三张小图(一个字母、一块纯色、一个带背景的词)过了一遍两个开源视觉模型的全部托管商。
结果是:DeepInfra 的 Qwen 把 K 读成 R,把红色说成蓝色,把词"umbrella"描述成"funny",而同样权重的另外四家全对。Venice 和 Together 压根没看到 MiniMax 的图。模型页写着支持图像输入,但有两家 Provider 不支持,更糟的是它们还假装一切 200 OK。
3. reasoning.effort 不是到哪都有用
reasoning.effort 这个参数到处都被接受,但它是否真的起作用取决于模型和 Provider。作者锁定了所有提供 DeepSeek V4 Flash 0731 的 Provider,从生产机器上在 low、high、max 三档各发三次同样的提示,然后对比推理 token 的输出量——差异巨大。结论是:要按 Provider 追踪你的 effort 设置到底有没有生效。
4. 拿精度过滤 Provider 是个坏主意
OpenRouter 允许按声明的精度过滤 Provider,比如 quantizations: ["fp8"],直觉是位数越少模型越笨。作者用这个过滤跑了 DeepSeek 一个月,再把基准榜和各家声明的精度放在一起看——fp4 的托管商落在 fp8 那群的正中间。
DeepSeek 上三个最差的 GPQA 分数,分别来自一家 fp4、一家 fp8,和一家什么都没声明的。GLM 在两个基准上表现最好的 Wafer,什么都没声明。精度是个糟糕的质量代理指标,硬过滤还会缩小 OpenRouter 在 Provider 挂掉时的回退池。作者的建议是:看榜,别看位数。
5. 工具调用的解析器会漏
理想情况是:模型按某种标记发出调用,Provider 的解析器把它转成结构化工具调用,你的代码执行它。但有时解析器会漏,然后模型吐出的原始标记就原样返回,需要你自己兜底。
这种问题的复现率因 Provider 而异,而且很顽固。有两类情况要用相反的思路处理:工具调用被 wrapper 多包了一层,以及回复内容被包住或半包住。
6. 200 OK 但没有答案
推理模型有时把内容全放进 reasoning 字段,返回 content: null、finish_reason: "stop"——345 个补全 token,HTTP 200,但用户那边什么都没拿到。
200 只说明请求被服务了,不代表里面有答案。没有 content 也没有工具调用,就是失败,应该抛错重试。
7. 空洞补全
相关但不同的问题:有些 endpoint 返回 200,content、reasoning 都是 null,连 usage 对象都没有。7 月是 DeepSeek 上的 StreamLake,占了作者约 20% 的流量和 92% 的空补全。一个月后,同样的事换成了 DeepSeek 0731 checkpoint 上的 Together。
8. 历史记录规则因 Provider 而异
DeepSeek 在思考模式下会输出 reasoning_content 块。在 Agent 循环里,模型经常带着空的 reasoning 发起工具调用。如果你把这个空的 reasoning 历史传回去,而它路由到 SiliconFlow,就会 400 报错 20015,提示 thinking 模式下的 reasoning_content 必须回传。Baidu、Alibaba、Cloudflare 收下同样的历史却毫无怨言。
所以契约不是按模型定的,是按 Provider 定的。而且别想着跳过工具历史,否则模型会一直重试同一个任务。
9. 从生产环境测,别在笔记本上测
这既是为了速度和延迟,本身也是个例子:Venice 和 Novita 在作者的 Mac 上跑 DeepSeek V4 Flash 一切正常,但从自己的基础设施探测几乎每次都 429。同一个 Key,同一分钟。作者的判断是它们按 IP 限流。
要测就从生产环境跑,一次几个,样本量要比你以为的更多。
10. 为什么不干脆锁死一个 Provider
作者一度把 provider.order 设成三家的列表并关掉回退,等于锁了 3 家可靠 Provider 而不是 1 家。两周后:Baidu 开始对一切 429,Cloudflare 被发现根本不再提供这个模型,100% 流量落到 Alibaba,然后 Alibaba 也开始 429。OpenRouter 的头号模型锁在最可靠的 3 家 Provider 上,结果把整个 Olly 拖挂了。
压成几条可执行的规则
把这份经验收拢一下:
- 选 Provider 看基准榜,而且要看贴近自己工作负载的那个,不是通用总分
- 用精度过滤代替不了实测,反而会缩小回退池
- 把"200 但没内容"当成失败处理,抛错重试
- 工具调用的解析要有自己的兜底,按 Provider 分别处理和记录
- 历史记录的怪癖按 Provider 记,别按模型记
- 探测从生产环境发,样本要多
- 别把流量锁死在少数几家
原文作者还开源了他在 Olly 里用的解析示例、一个 AI SDK,以及全部原始数据。
© 2026 四月
原文链接:https://www.aprilzz.com/tutorials/openrouter-provider-pitfalls
相关文章
让 AI Agent 直接读你的网站:Accept: text/markdown 内容协商实战教程
手把手教你把网站变成 AI Agent 友好:用 Accept: text/markdown 内容协商,让 Claude Code、Cursor 等工具直接读到干净的 Markdown。含 Caddy、Nginx、Next.js、Cloudflare 配置和验证方法。
在 Mac 上搭建本地编程 Agent:llama.cpp + Gemma 4 + MTP 投机解码完整指南
断网也能用的编程 Agent:用 llama.cpp 在 Mac 上跑 Gemma 4 26B,配合 MTP 投机解码把生成速度从 58 提到 72 token/s,再接上支持图片输入的 Pi 终端 Agent。
Bash4LLM⁺ 使用教程:用纯 Bash 脚本优雅调用 LLM API
Bash4LLM⁺ 是一个纯 Bash 编写的 LLM API 包装器,无需 Python/Node.js,单脚本即可调用 Groq 等提供商的 Chat Completions API