用 OpenRouter 统一接多家 API,这几个路由参数我一开始完全没注意到
上个月我们团队把后端的模型调用从"每家一个 SDK"迁移到聚合路由方案,目的很简单——业务代码里不想再写 if/else 来区分 OpenAI、Anthropic、Google 的 client 初始化了。迁完之后确实舒服了不少,但 OpenRouter 的 route、provider、transforms 这几个参数,说实话我前两周完全没仔细看文档,直到某天早上收到一封账单邮件,发现一个 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 里显示的名字抄就对了。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)