OpenRouter 可靠性与自动故障转移:请求如何持续成功
OpenRouter Reliability & Automatic Failover: How Requests Keep Succeeding
OpenRouter 默认启用提供商故障转移(provider failover),模型回退(model fallbacks)则为选择加入。这两层机制分别应对不同类型的故障:提供商故障转移在 API 调用失败时自动切换至其他提供商,模型回退则在指定模型不可用时切换到备选模型。公告详细说明了各层的工作原理以及故障转移的停止条件。
开发 LLM 应用的人可以把这篇当生产可靠性检查清单用,虽然通篇在推自家服务,但两层故障转移的思路确实通用。

直接调用单一提供商意味着单点故障。当它宕机时,你的用户会遇到错误,而你在一小时后才从支持工单中得知此事。这正是 OpenRouter 解决的问题:它会为每个请求进行路由,确保请求持续成功,自动跨提供商切换,并在配置后跨模型切换。
借助 OpenRouter,你可以通过 2 项独立配置为应用构建可靠性。提供商故障转移是自动的,且默认开启。模型回退则需要主动启用。
这 2 层覆盖不同的故障情形;如果某个主模型的所有提供商同时故障,提供商故障转移就无处可去。模型回退是第二道防线。
以下是一份值得在每个项目中作为起点的配置。复制它并调整:
from openrouter import OpenRouter
client = OpenRouter(api_key="<OPENROUTER_API_KEY>")
completion = client.chat.send(
model="anthropic/claude-sonnet-4.6",
models=["openai/gpt-5.4-mini"], # fallback if the primary fails
messages=[{"role": "user", "content": "Summarize this incident report."}],
)简而言之
- LLM 请求会因可预测的原因失败:提供商宕机、速率限制(429)、上下文长度错误,以及内容审核拒绝。
- 可靠性分为 2 层:提供商层故障转移(默认开启,在同一模型内恢复)和模型层回退(通过
models数组主动启用,跨模型恢复)。 - 路由层会实时检测提供商健康状况并绕开宕机,因此最坏情况下的正常运行时间也优于你直接集成的任何单一提供商。
- 故障转移会按顺序遍历你的
models列表。一旦列表耗尽,最后出现的错误就会被返回,因此请把可靠的兜底模型放在最后。 - 对于最终失败的请求你无需付费,但用户报告了一些边缘情况(某些 429 路径、部分输出)仍会消耗额度,所以要留意你的活动日志并设置支出上限。
- 用
only/ignore/order限制提供商,是以可靠性换取控制权:候选集合越窄,可用的回退就越少。
为什么 LLM API 请求会失败?
提供商故障、速率限制(429)、上下文长度校验错误以及内容审核拒绝,是 LLM 请求失败的几类可预见原因。单一的直接提供商集成对其中任何一种都没有恢复路径,因此每一种都会变成面向用户的错误。
最简单的例子就是速率限制。你直接调用某一个提供商,触及其每分钟上限,此时你唯一的选择就是退避、排队或失败。这些对盯着加载转圈的用户来说都无济于事。
社区把路由层称为“AI 的 DNS”是有原因的:它能保持在线,是因为它有不止一个地方可以发送请求。
这 4 种失败模式中的每一种都对应 OpenRouter 中一个特定的恢复层,而了解哪一层负责处理什么,正是你正确配置可靠性的关键。
4 种故障模式,映射到对应的恢复层
以下是会出现的故障,以及 OpenRouter 的哪一层可以将其恢复。
| 故障模式 | 表现形态 | 恢复方式 |
|---|---|---|
| 提供商宕机 / 不可用 | 5xx、超时、连接中断 | 提供商层故障转移(切换至下一个提供商) |
| 速率限制(429) | 来自提供商的“Too Many Requests” | 提供商层故障转移,然后是模型回退 |
| 上下文长度错误 | 提示词超出模型的上下文窗口 | 模型层回退(尝试上下文更大的模型) |
| 审核拒绝 | 经过滤的模型拒绝回复 | 模型层回退(尝试未经过滤的模型) |
前两个是基础设施问题,由第二家提供商解决。后两个是模型问题,由第二个模型解决。
在 OpenRouter 上,失败的请求需要付费吗?
简短回答:不需要。当一个请求在故障转移全部耗尽后最终失败时,你不会被计费;你只需为成功的那次运行付费(零完成保险)。
这让重试的设计成本很低:一条在成功之前接连耗尽 3 家提供商的回退链,只会让你支付一次成功完成的费用。你可以放心地采用激进的回退策略,而不必为每一次失败的尝试盯着计费表。
你应该提前规划的那个例外
现实世界中确实存在边缘情况,我们更希望你是从这里读到的,而不是从你的账单面板上发现的。一些用户报告过 429 错误消耗了额度,或者尽管出现错误却仍计入了部分输出的情况。所以政策是“只为成功的运行付费”,但少数 429 路径和部分输出还是漏了过去。
诚实的权衡:零完成保险是真实存在的,但它并非滴水不漏。检查你的活动日志以确认你被收取了哪些费用,并设置硬性支出上限,这样边缘情况就不会让账单飙升。设计时要带上支出上限,而不是假设每一个失败的请求都是免费的。
提供商故障转移 vs 模型回退
OpenRouter 从两个不同层面进行故障恢复。提供商层面的故障转移是自动的,且默认开启;模型层面的回退则需要通过 models 数组主动选择启用。前者让同一个模型在不同提供商之间保持可用,后者则完全切换到另一个模型。
OpenRouter 会在提供商之间自动进行故障转移,你可以通过 ignore、only 和 order 来塑造候选集合。常见情况下你无需编写重试逻辑。
ignore 通过 slug 屏蔽特定提供商。only 限制为一份允许列表。order 设定一个明确的优先尝试顺序。
这 3 个都会缩小候选集合,因此请谨慎使用;符合条件的提供商越少,回退选项就越少。
| 提供商层面的故障转移 | 模型层面的回退 | |
|---|---|---|
| 恢复的内容 | 为你的模型提供服务的提供商出现故障或返回 429 | 整个模型不可用,外加上下文长度和内容审核拒绝 |
| 默认 | 开启(allow_fallbacks: true) | 在你设置 models 数组之前处于关闭状态 |
| 控制它的配置 | allow_fallbacks、order、only、ignore | models 数组(优先级顺序) |
| 恢复范围 | 同一模型,不同提供商 | 完全不同的模型 |

这只是静态视角。下图展示了运行时实际发生的情况:单个请求如何流经这两层,以及它在何处以成功或最终错误退出。

提供商层故障转移:一个模型,多个提供商
像 Claude Sonnet 4.6 这样的单个模型通常由多个提供商提供服务。如果 OpenRouter 选中的提供商返回 5xx 或触发速率限制,它会自动尝试同一模型的下一个提供商。这由 allow_fallbacks 控制,其默认值为 true(提供商选择文档)。
零配置。你发送请求的那一刻就能获得这一能力。
模型层回退:当整个模型不可用时
如果主模型的所有提供商都失败了,提供商层故障转移就无处可去了。这时就轮到 models 数组接管:OpenRouter 会切换到列表中的下一个模型(model-fallbacks 文档)。这一层是可选的,因为它会改变由哪个模型来回答,而这是只有你才能做的决定。
上下文长度错误或审核拒绝也会触发这一层,因为这些问题换一个提供商也解决不了。
这两层协同工作,但在幕后它们的工作方式并不相同。提供商层故障转移无需任何设置即可自动运行。以下是它在每次请求中实际做的事情。
提供商层故障转移如何保持单个模型持续可用
对于每个模型,OpenRouter 会在各提供商之间进行负载均衡,以最大化正常运行时间,采用的是公开的 3 步规则:优先选择过去 30 秒内没有重大故障的提供商,按价格的平方反比加权挑选成本最低的稳定候选者,其余则保留作为故障转移备选(provider-selection 文档)。这首先是一套可靠性机制,其次才是成本机制。
在实践中,任何在过去 30 秒内出错的提供商都会被排到队尾,而在稳定的提供商中,最便宜的那个会优先被选中,其概率大约与价格差的平方成正比。可靠性优先,成本其次,全自动。
30 秒的中断窗口正是对正常运行时间至关重要的部分。在过去半分钟内出现抖动的提供商会被自动从前排剔除,无需你采取任何操作。
解析负载均衡的数学原理
文档中的示例展示了可靠性与成本如何协同作用。假设提供商 A 的成本为 $1/M tokens,提供商 B 为 $2/M,提供商 C 为 $3/M,而 B 最近出现了几次中断。
OpenRouter 会优先路由到 A,而由于平方反比加权(1/3² = 1/9),A 被尝试的概率大约是 C 的 9 倍。如果 A 失败,接下来是 C。而最近不太稳定的 B 则最后才被尝试:中断历史会将不可靠的提供商推到后面,但并不会将其排除。

这是默认行为。但如果你已经知道某个提供商不行,就不必等待路由数学去发现这一点。
控制候选集合
你可以限定哪些提供商符合条件,这就是屏蔽不可靠提供商的方法:
order:按显式顺序尝试提供商,例如order: ["anthropic", "together"]。only:请求的提供商 slug 允许列表。ignore:阻止列表,例如provider: { ignore: ["deepinfra"] },用于跳过你发现提供过度量化模型的端点。allow_fallbacks: false:硬性停止到你选定的提供商,没有自动备份。
诚实的权衡:用 only、ignore 或 order 收窄范围“可能会显著减少回退选项并限制请求恢复”(提供商选择文档,原文如此)。你排除的每一个提供商,就少一个可恢复的地方。限制候选池换来的是控制力,付出的是可靠性,所以要审慎地裁剪。
在不损失候选池的前提下限定最坏情况延迟
如果你需要可预测的延迟,可以设置 preferred_max_latency 或 preferred_min_throughput,并基于滚动 5 分钟窗口设置百分位阈值(提供商选择文档)。未达到阈值的端点会被降低优先级,而不是被排除。下面是它与 ignore 结合使用时的样子:
completion = client.chat.send(
model="deepseek/deepseek-v4-flash",
provider={
"preferred_max_latency": {"p90": 3}, # prefer <3s for 90% of requests
"ignore": ["deepinfra"], # skip a known-bad endpoint
},
messages=[{"role": "user", "content": "Classify this ticket."}],
)以上所有做法都是让同一个模型在多个提供商之间保持可用。但如果该模型的所有提供商都宕机了,提供商故障转移就无处可去了。
模型回退会接管,并尝试你列表中的下一个模型。它们是协同工作的顺序层级,而 models 数组就是你开启第二层的方式。
如何设置模型回退
按优先级顺序传入一个 models 数组,如果第一个模型的所有提供商都报错,OpenRouter 会尝试下一个模型(模型回退文档)。一个数组,无需重试代码。OpenRouter 的 SDK 将 models 作为一等字段;使用 OpenAI SDK 时,你通过 extra_body 传入它。
cURL:
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"models": ["anthropic/claude-sonnet-4.6", "openai/gpt-5.4-mini"],
"messages": [{"role": "user", "content": "Draft a release note."}]
}'TypeScript:
import { OpenRouter } from '@openrouter/sdk';
const openRouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
const completion = await openRouter.chat.send({
models: ['anthropic/claude-sonnet-4.6', 'openai/gpt-5.4-mini'],
messages: [{ role: 'user', content: 'Draft a release note.' }],
});完整的触发条件列表
理解什么会触发回退,比知道回退存在更重要。以下 4 种条件中的任何一种都可以触发它,直接来自 模型回退文档:
| 触发条件 | 含义 | 由哪一层恢复 |
|---|---|---|
| 宕机 | 提供商无法访问或返回 5xx | 提供商层,然后是模型层 |
| 限流 | 提供商返回 429 | 提供商层,然后是模型层 |
| 上下文长度校验错误 | 你的提示词超出了模型的窗口 | 模型层(切换到上下文更大的模型) |
| 审核标记 | 被过滤的模型拒绝回复 | 模型层(切换到未过滤的模型) |
计费依据实际作答的模型,该模型会在响应的 model 字段中返回。请检查该字段以确认是哪个模型处理了请求,尤其是在触发回退时。
触发条件列表涵盖了回退何时触发。它没有告诉你的是回退何时停止。
只有撞上才会知道的限制
回退会在你的列表末尾停止。“如果回退模型宕机或返回错误,OpenRouter 将返回该错误”(模型回退文档)。它会按顺序遍历你的 models 数组一次,绝不会形成无限重试链。
当失败并非 OpenRouter 归类为可回退的错误时,回退也不会触发(例如,格式错误请求导致的 400 会直接返回)。
实用的解决办法是调整你的 models 数组顺序,让最后一项成为你最可靠的基础模型,也就是当它前面所有模型都失败时,你仍愿意信任它来作答的那个。
OpenRouter 如何实时绕开服务中断
OpenRouter 持续监控所有提供商和路由的响应时间、错误率与可用性,并基于这些实时反馈进行路由(uptime-optimization 文档)。你无需自建监控,就能获得自动的提供商健康检测,而这正是企业评估者最先问到的可靠性功能。这些实时数据支撑着 30 秒中断窗口:一个正在退化的提供商会在当下就被绕开,比状态页面更新还快。
可验证的公开可用性
文档中嵌入了 Claude Sonnet 4.6 和 GLM 5.1 等模型的实时可用性组件,因此提供商可用性是你能够亲眼查看的,而不是只能凭信任接受(uptime-optimization 文档)。有 3 个信号共同决定路由决策:
- 响应时间会降低慢速端点的优先级。
- 错误率会让返回 5xx 的提供商退出队列前列。
- 可用性驱动着 30 秒中断窗口。
如果你是在为生产环境评估这一点,那这就是你的答案:实时健康路由、30 秒的故障窗口,以及可实际验证的按模型发布的正常运行时间,而不是幻灯片上的一个正常运行时间百分比。
平台健康与路由健康
按提供商的路由健康负责实时引导单个请求。平台级健康,即网关本身,位于 status.openrouter.ai。
监控状态页面,以了解影响整个网关的事件;信任实时路由来自行处理某个不稳定的提供商。
OpenRouter 自动处理路由健康。网关本身则需要你自己监控。但故障转移不覆盖哪些情况?
故障转移不覆盖哪些情况
故障转移能从提供商和模型错误中恢复,而这就是它的边界。它不会无限重试,不会捕获非错误的坏响应,不会在每个提供商上为已取消的流退款,也无法让网关自身免受其自身故障的影响。下面正是它止步的地方,以及针对每一种情况你该怎么做。
| 限制 | 含义 | 你的缓解措施 |
|---|---|---|
| 受你的列表约束 | 当你的 models 数组中的每个模型都出错时,会返回最后一个错误 | 将 models 排序时,把可靠的兜底模型放在最后 |
| 非错误的拒绝 | 一个“糟糕”但并非错误的响应不会触发回退 | 当正确性至关重要时,请自行验证响应 |
| 流式取消 | 中止流式请求在某些提供商处仍会计费(其中包括 Bedrock、Groq、Google、Mistral) | 路由到支持可取消流的提供商,或为此预留预算 |
| 网关依赖 | 路由层自身也会发生故障(2025 年 8 月,约 50 分钟) | 在你这一侧设计重试;关注 status.openrouter.ai |
受你的列表限制,且仅针对已分类的错误
回退会按顺序尝试你的 models 数组中的每个模型。当最后一个也失败时,该错误会返回给你(模型回退文档);除了你列出的内容之外,不存在额外的重试链。
更糟的是,如果模型返回垃圾内容却带着 200 状态码,回退机制根本不会触发。OpenRouter 只在已分类的错误上触发。把你的 models 数组按顺序排列,把最可靠的基础模型放在最后,并在正确性至关重要时自行验证响应。
流取消在部分提供商处仍会继续计费
当流在客户端停止渲染,但全额费用仍然记到你的账户上时,你的第一反应通常是去翻日志。你会以为提示词触发了内容审核标记,或者白白花时间去找一个根本没发生过的 5xx 错误。
一部分提供商,包括 Bedrock、Groq、Google 和 Mistral,不支持流取消(流式传输参考)。当你在响应中途中止流时,连接在你这一侧关闭,但模型在它们那一侧仍在继续生成(并继续计费)。
要应对这一点,可以把对成本敏感的流式路径显式路由到仅支持可取消流的提供商,或者为超支预留预算。
网关本身也是一种依赖
2025 年 8 月,一次约 50 分钟的数据库故障导致路由层宕机。路由层也有自己的单点故障。
Hacker News 讨论帖自己的结论是公允的:“正常运行时间仍然优于任何单一提供商”,但这并非零风险。请在你这一侧设计重试机制,并关注 status.openrouter.ai 以了解网关级别的事件。
为生产环境配置故障转移:一份检查清单
将这两层与支出护栏结合起来。下面的配置是大多数生产环境部署所期望的形态:一个带有可靠兜底模型的模型链、默认开启的提供商故障转移、排除已知有问题的端点,以及面向用户路径的延迟上限。
| 步骤 | 操作 |
|---|---|
| 1 | 设置一个 models 数组,将可靠兜底模型放在最后,这样最终的备选就是你最信任的那个。 |
| 2 | 保留 allow_fallbacks: true(默认值),除非合规或 BYOK 合同强制要求使用单一提供商。 |
| 3 | 使用 ignore 排除你发现服务表现不佳的提供商端点;每个模型页面上的提供商正常运行时间标签页就是发现它们的方式。 |
| 4 | 为用户侧路径添加 preferred_max_latency 百分位截断,以约束尾部。 |
| 5 | 依赖零完成保险,但要设置支出限额,并留意活动日志中的 429 边缘情况。 |
| 6 | 监控 status.openrouter.ai 以了解网关级故障。 |
这是每个项目推荐的起始配置。复制它并进行调整:
from openrouter import OpenRouter
client = OpenRouter(api_key="<OPENROUTER_API_KEY>")
completion = client.chat.send(
model="anthropic/claude-sonnet-4.6",
models=["openai/gpt-5.4-mini", "google/gemini-3.5-flash"], # floor model last
provider={
"ignore": ["deepinfra"], # exclude a known-bad endpoint
"preferred_max_latency": {"p90": 3}, # bound worst-case latency
# allow_fallbacks stays true by default
},
messages=[{"role": "user", "content": "Summarize this thread."}],
)
print(completion.model) # confirm which model answered获取一个 API key,故障转移默认已开启。我们建议在第一天就添加一个 models 数组。这是你能设置的最便宜的安全网。
常见问题
当某个提供商宕机时,OpenRouter 如何处理故障转移?
对于由多个提供商服务的单个模型,当所选提供商返回 5xx 或触发速率限制时,OpenRouter 会自动尝试下一个提供商。这种提供商层故障转移默认开启(allow_fallbacks: true),无需配置(提供商选择文档)。
提供商故障转移与模型回退之间有什么区别?
提供商层故障转移通过切换提供商来让同一个模型保持可用,而且是自动的。模型层回退则通过 models 数组完全切换到另一个模型,并且需要主动开启。前者可从提供商故障和速率限制中恢复;后者还能从上下文长度错误和审核拒绝中恢复。
在 OpenRouter 上,什么会触发自动回退?
4 种情况:宕机、速率限制、上下文长度校验错误,以及针对被过滤模型的审核标记(model-fallbacks 文档)。宕机和速率限制先在提供商层处理,然后在模型层处理;上下文长度和审核则在模型层处理。
OpenRouter 会对失败的请求收费吗?
不会。你只需为成功的那次运行付费;在故障转移耗尽后仍失败的请求不会被计费(zero-completion insurance)。但请为一个有记录的例外做好准备:用户报告称,某些 429 路径和部分输出仍然消耗了额度,因此请设置支出限额并检查你的活动日志。
OpenRouter 在生产环境使用中的可靠性如何?
它利用 30 秒健康窗口和已发布的各模型正常运行时间(正常运行时间优化文档),实时绕开提供商故障,这使得最坏情况下的正常运行时间优于任何直接集成的单一提供商。这并非零风险:2025 年 8 月的一次网关故障表明,路由层有其自身的依赖项。请设计重试机制并监控 status.openrouter.ai。
如何在 OpenRouter 上设置回退模型?
按优先级顺序传入一个 models 数组。OpenRouter SDK 将 models 作为一等字段接收,例如 models=["openai/gpt-5.4-mini"];使用 OpenAI SDK 时,通过 extra_body 传入(模型回退文档)。
把你最可靠的模型放在最后,这样最终的回退就是你的底线。
来源:OpenRouter:Announcements(RSS) · openrouter.ai