上个月我们团队把后端的模型调用从"每家一个 SDK"迁移到聚合路由方案,目的很简单——业务代码里不想再写 if/else 来区分 OpenAI、Anthropic、Google 的 client 初始化了。迁完之后确实舒服了不少,但 OpenRouter 的 routeprovidertransforms 这几个参数,说实话我前两周完全没仔细看文档,直到某天早上收到一封账单邮件,发现一个 fallback 配置错误让我们多花了 $47,才回头把路由逻辑彻底搞明白。

这篇就把我踩过的坑和最终的配置方案写出来,重点是优先级控制、fallback 链和零改动切模型这三件事。

先说结论

需求 关键参数 一句话说明
指定供应商优先级 provider.order 数组顺序就是尝试顺序
供应商黑名单 provider.ignore 某家挂了或太贵就跳过
自动 fallback route: "fallback" 第一个 provider 超时/5xx 自动切下一个
不改代码切模型 transforms 请求里写 gpt-5.5,实际路由到 claude-sonnet-4.6
强制某个 provider provider.require_parameters 只用支持 function calling 的通道

调用链路长什么样

sequenceDiagram
 participant App as 你的业务代码
 participant OR as OpenRouter 网关
 participant P1 as Provider A (Anthropic)
 participant P2 as Provider B (Azure)
 participant P3 as Provider C (Google)

 App->>OR: POST /chat/completions + route config
 OR->>P1: 尝试第一优先级
 P1--xOR: 503 Service Unavailable
 OR->>P2: fallback 到第二优先级
 P2-->>OR: 200 OK + completion
 OR-->>App: 返回结果 + 实际 provider 信息

provider.order:控制谁先谁后

这是最基础的参数,但文档里埋得挺深。直接看代码:

import requests

response = requests.post(
 "https://openrouter.ai/api/v1/chat/completions",
 headers={
 "Authorization": "Bearer your-openrouter-key",
 "Content-Type": "application/json"
 },
 json={
 "model": "anthropic/claude-sonnet-4.6",
 "messages": [{"role": "user", "content": "写一个快排"}],
 "provider": {
 "order": ["Anthropic", "AWS Bedrock", "Google Vertex AI"],
 "allow_fallbacks": True
 }
 }
)

order 数组里的顺序就是路由优先级。OpenRouter 会先尝试 Anthropic 直连通道,挂了再走 AWS Bedrock,最后才是 Google Vertex。

我一开始犯的错:没写 allow_fallbacks: True。默认情况下如果第一个 provider 返回非 2xx,OpenRouter 会直接把错误透传给你,不会自动切。这个默认行为让我周三凌晨被报警叫醒,Anthropic 那边 502 了大概 12 分钟,我们的对话服务直接挂了。

route: "fallback" 的真实行为

route 字段有两个值:"fallback""priority"

json_body = {
 "model": "anthropic/claude-sonnet-4.6",
 "messages": messages,
 "route": "fallback",
 "provider": {
 "order": ["Anthropic", "AWS Bedrock"],
 "ignore": ["Together AI"] # 这家的 Claude 通道延迟太高,直接排除
 }
}

实测下来的行为:

  • fallback 模式:provider A 返回 429/5xx/超时 → 自动尝试 provider B → 如果都挂了才返回错误。延迟会增加(因为要等第一个超时),实测 P95 从 320ms 涨到 1.8s 左右
  • priority 模式:只用 order 里的第一个,不 fallback。适合你对延迟极其敏感、宁可报错也不要慢的场景

一个坑:route: "fallback"provider.allow_fallbacks: True 不是一回事。前者是请求级别的路由策略,后者是 provider 配置里的开关。两个都写上才是最稳的配置。

transforms:不改代码切底层模型

这个参数的设计挺有意思。场景是这样的——我们有个 RAG pipeline,代码里硬编码了 model: "openai/gpt-5.5",但老板说这个月 Claude Opus 4.7 的效果更好,让我切过去试试。

正常做法是改代码、提 PR、过 review、部署。但用 transforms 可以在请求层面做模型映射:

json_body = {
 "model": "openai/gpt-5.5", # 代码不改,还是写 GPT-5.5
 "messages": messages,
 "transforms": ["middle-out"], # 超长上下文自动压缩
 "provider": {
 "order": ["Anthropic"],
 "allow_fallbacks": True
 },
 # 真正的魔法:通过 model routing 在 OpenRouter 后台配置
 # 把 openai/gpt-5.5 的请求路由到 anthropic/claude-opus-4.7
}

等等,其实 transforms 本身不做模型映射——它做的是上下文压缩(middle-out 会把超出上下文窗口的中间部分截掉)。真正的模型映射要在 OpenRouter 的 Dashboard → Model Routing 里配,或者用他们的 X-Routing-Override header(这个 header 文档里没写,我是翻 Discord 才找到的)。

headers = {
 "Authorization": "Bearer your-key",
 "X-Routing-Override": "anthropic/claude-opus-4.7", # 覆盖 model 字段
 "Content-Type": "application/json"
}

踩坑记录

坑 1:fallback 触发时的账单翻倍

5 月 8 号我查账单发现 Claude Sonnet 4.6 的调用量比预期多了 40%。原因是 fallback 链里 Anthropic 直连偶尔返回 429 Too Many Requests,然后自动切到 AWS Bedrock 的 Claude 通道——两边都计费了。Anthropic 那边虽然返回 429,但它的 rate limit 计数器已经 +1 了(虽然没产生 token 费用),而 Bedrock 那边正常出 token 要付钱。

报错长这样:

{
 "error": {
 "code": 429,
 "message": "Rate limit exceeded. Please retry after 2s.",
 "metadata": {
 "provider_name": "Anthropic",
 "raw": "{\"type\":\"error\",\"error\":{\"type\":\"rate_limit_error\",\"message\":\"Number of request tokens has exceeded your per-minute rate limit\"}}"
 }
 }
}

解决办法:在 provider 里加 "quantization": "fp16" 来减少某些通道的 token 用量——开玩笑的,实际解决方案是给 Anthropic 直连通道单独设了 rate limit buffer,请求前先 check 剩余额度。

坑 2:transforms: ["middle-out"] 把关键上下文截了

我们有个法律文档分析的 pipeline,上下文大概 180K tokens。开了 middle-out 之后,模型回答质量断崖式下跌。后来发现它把文档中间的关键条款截掉了。

最终方案:不用 transforms,改用 Gemini 3.5 Flash 的 1M 上下文窗口处理超长文档,短文档还是走 Claude。

坑 3:provider.order 里的名字必须精确匹配

我写了 "order": ["anthropic", "aws-bedrock"],结果 fallback 完全没生效。正确的写法是 ["Anthropic", "AWS Bedrock"]——首字母大写,带空格。这个错误不会报错,OpenRouter 会静默忽略不认识的 provider 名,然后走默认路由。折腾了大半天才发现。

账单对比:配置前 vs 配置后

我拉了 5 月 1-14 号的数据:

指标 配置前(默认路由) 配置后(精细路由)
日均请求量 ~12,000 ~12,000
日均花费 $38.2 $24.7
429 错误率 3.8% 0.4%
P95 延迟 1,240ms 680ms
fallback 触发率 N/A 2.1%

省下来的钱主要来自两块:一是把低优先级的 summarization 任务从 Opus 降级到 Sonnet;二是 provider.ignore 排除了延迟高的通道,减少了超时重试的 token 浪费。

聚合平台的另一种玩法

OpenRouter 收 5.5% 手续费这事大家都知道。如果你的场景不需要这么复杂的路由逻辑,只是想统一 base_url 调多家模型,OpenRouter、Together AI、ofox.io 这类聚合平台都能做到,ofox.io 是 0% 加价直接对齐官方价格,改个 base_url 就能切:

from openai import OpenAI

# 用 OpenAI SDK 直接调 Claude / Gemini / DeepSeek
client = OpenAI(
 api_key="your-ofox-key",
 base_url="https://api.ofox.io/v1"
)

response = client.chat.completions.create(
 model="anthropic/claude-sonnet-4.6",
 messages=[{"role": "user", "content": "解释一下 fallback 路由的原理"}]
)

不过如果你确实需要 provider 级别的 fallback 和路由控制,OpenRouter 的这套参数体系目前是最完整的。

小结

路由配置这事,核心就三个参数:provider.order 控制优先级,route: "fallback" 开自动切换,transforms / X-Routing-Override 做模型映射。我目前的做法是生产环境写死 order + allow_fallbacks: true,测试环境用 X-Routing-Override 快速 A/B test 不同模型。

provider 名字大小写那个坑,我也不确定是不是所有通道都这样,反正保险起见全部按 Dashboard 里显示的名字抄就对了。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐