OpenRouter 模型不可用:下线、限流与路由失败的区分

2026-08-31

数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。

「OpenRouter 模型不可用」不是一个错误,是三个完全不同的错误挤在同一句抱怨里:模型 slug 本身已经不在目录里了(官方把这类归为 not_found)、上游供应商宕机或过载(provider_unavailable / provider_overloaded)、以及你自己在 provider 对象里设的偏好把可用 endpoint 筛成了空集(报错原文会直接告诉你「哪些供应商在服务这个模型、而你的偏好只允许哪些」)。这三件事的处理动作完全相反:第一种要改代码里的模型名,第二种要等和加 fallback,第三种要放宽你自己设的条件。OpenRouter 官方在错误文档里明确要求「用 error_type 这个值、而不是只看 HTTP 状态码」来区分错误类别,因为这个字段在三套 API 皮肤下是稳定的,而原生协议码是尽力而为、格式之间可能不一致。所以整篇排查的第一动作就是:把 error_type 打出来。

先看官方把「不可用」拆成了几条

翻 OpenRouter 的错误码清单会发现,跟「模型用不了」相关的条目至少是两条独立的:一条描述的是「你选的模型宕机了,或者我们从它那里收到了无效响应」,另一条描述的是「没有任何模型供应商满足你的路由要求」。前者是上游的问题,后者是你请求参数的问题——官方把它们分开列,就是因为处理方式不一样。

再往下,官方还给了一张按 error_type 分的表,比 HTTP 状态码精细得多。跟可用性直接相关的几个取值是(取值以官方文档当前版本为准):

  • not_found:请求的资源(模型、文件等)不存在
  • provider_unavailable:上游供应商返回了无效或空响应;如果开启了 fallback 路由,OpenRouter 可能自动换一个供应商重试
  • provider_overloaded:上游供应商临时过载,稍后重试
  • rate_limit_exceeded:请求级或 token 级限流,重试前要尊重 Retry-After

同一句「不可用」,落到这四个取值上是四种不同的下一步动作。而且官方还补了一句很关键的实现细节:非 500 的错误会把上游供应商自己的错误码放在 error.metadata.provider_code 里;一旦是 500,message 会被换成一段通用文案,provider_codeopenrouter_metadata 都会被省掉,只有 error_type 还在(值为 server)。也就是说,500 是你能拿到的信息最少的一类错误,别指望从它的 message 里读出原因。

第一步:确认这个模型 slug 现在还在不在

官方在 API 版本策略那一节里写得很直白:模型可用性和 API 版本控制是两回事,模型由供应商独立地增加和移除。换句话说,API 的废弃有变更日志、有破坏性变更流程、有 RSS 可订阅,但某个模型某天不再提供了,不走这套流程。你代码里硬编码的那个 slug,是可能在你毫不知情的情况下失效的。

对应的查法有两个官方接口:GET /api/v1/models 列出当前全部可用模型及其属性,GET /models/{author}/{slug}/endpoints 列出某个具体模型下的全部 endpoint。第二个在排查时更有用——它回答的是「这个模型现在到底还有没有人在服务」,而不只是「目录里还有没有这一行」。

这里有两个官方明文写过的、非常容易踩的具体坑:

一是已废弃的变体后缀。 官方文档给 :extended 变体挂了废弃警告,原话说的是这个变体已废弃、OpenRouter 上当前没有任何模型提供它,请求 model:extended 这样的 slug 没有 endpoint 可路由,会失败。官方给的替代做法是改用基础模型 slug,再从模型浏览页或 models API 的 context_length 字段里挑一个标准上下文能装下你输入的模型;一个模型确实支持的静态变体,会在那里以独立条目出现。所以如果你的模型名带着后缀,先确认这个后缀今天还成立。

二是 ~author/family-latest 这类别名。 官方说它总是解析到该家族里最新的可见模型,新版本上线会自动接管,客户端不用改。但限制那一节里补了一句关键的:别名解析永远不会解析到另一个别名 slug,也不会解析到已被隐藏的模型;如果某个家族没有可用的合格模型,请求会直接返回错误,而不是回落到某个不相干的模型上。这个设计其实是对的——宁可报错也不给你换个东西悄悄跑——但它意味着别名同样会「不可用」,而且报错的时候你手里连一个具体模型名都没有。这时候先看响应体的 model 字段:官方说它报告的是实际服务这次请求的具体模型(成功时),这也是你确认别名当前指向谁的唯一可靠途径。

第二步:区分「上游挂了」和「你把候选筛空了」

这一步是最容易误判的。很多人看到请求失败就去查 OpenRouter 的状态,其实错在自己的请求体里。

官方路由元数据文档给了一个 No Providers Available 的完整示例,error.code 是 404,message 原文是这样一句:模型没有被允许的可用供应商,服务该模型的供应商是某某,但你请求里的 provider.only 偏好只允许某某。这句话本身就是答案——它把「谁在服务」和「你允许谁」两个集合都打印出来了,一眼能看出交集为空。

会造成这种「筛空」的字段不止 only 一个。官方 provider 对象里,下面这些都会缩小候选池:

  • only:只允许列表里的供应商。官方在这一节挂了警告,说只允许部分供应商可能显著减少 fallback 选项、限制请求的恢复能力
  • ignore:跳过列表里的供应商,官方同样警告忽略多个供应商会显著削弱恢复能力
  • require_parameters:设为 true 后,不支持你请求里全部参数的供应商连路由都不会路由过去;默认为 false 时它们仍会收到请求,只是忽略不认识的参数
  • data_collection 设为 deny:只用不收集用户数据的供应商
  • zdr 设为 true:只路由到零数据留存的 endpoint
  • enforce_distillable_text:只路由到允许文本蒸馏的模型
  • quantizations:按量化等级过滤(官方列出的取值有 int4、int8、fp4、mxfp4、nvfp4、fp6、fp8、mxfp8、fp16、bf16、fp32、unknown,以官方文档为准)
  • max_price:价格门槛。官方明确说明,价格不可得时它让请求跑不起来
  • preferred_min_throughput / preferred_max_latency:★ 这两个只降权不排除——不满足阈值的端点会被移到候选列表末尾而不是踢出去,官方原话是它们不保证一定拿到某个供应商、但也永远不会导致请求无法执行。排查「模型不可用」时不要动它们
  • allow_fallbacks 设为 false 并配合 order:把可用供应商钉死在你给的那几个上

★ 最阴的一条在 ignore 那节的提示里:当你为单次请求指定忽略的供应商时,这份列表会和你账户级别的忽略列表合并only 和数据策略过滤同样有账户级设置。这意味着你翻遍代码找不到任何限制,问题却真真切切来自账户隐私设置里某次点选。ZDR 那节说得更明确:请求级的 zdr 参数和账户级、guardrail 级的设置是「或」的关系——请求级只能确保开启,无法覆盖掉账户级的强制。排查到这一层还没结果,就该去账户设置里看一眼,而不是继续读代码。

顺带一个容易混淆的邻居:如果错误指向的是权限而不是可用性,那属于另一类问题,官方对应的是 permission_denied,含义是 key 有效但缺少权限、或者被 guardrail 拦截。它和鉴权失败又不是一回事,别把这两条线的排查动作混在一起做。

第三步:让平台自己说出它做了什么

前两步靠猜,这一步开始有证据。OpenRouter 提供了一个按请求开关的路由元数据功能:发请求时带上 X-OpenRouter-Metadata 头、值为 enabled,响应里就会多出一个 openrouter_metadata 对象。官方说这个头的值大小写不敏感,接受 enableddisabled 两个值,其他任何值(包括拼错的、空字符串、没听说过的级别)都会回落成 disabled;不带这个头时默认也是关闭。这一点值得留意——拼错不会报错,只会静悄悄地什么都不给你。

它在四个补全路由上都接了:/api/v1/chat/completions/api/v1/messages/api/v1/responses 和旧版 /api/v1/completions,流式和非流式都带。流式的时候,元数据在 data: [DONE] 之前的最后一个 chunk 上给你(Chat Completions 与 Responses),Anthropic Messages 则是放在终止的 message_stop 事件里。

对排查最有用的几个字段:

  • requested:客户端发来的模型 slug 或别名。官方特意标注它可能和真正服务请求的供应商/模型不同——排查别名问题时先看这个
  • strategy:本次用的路由策略,官方列出的取值有 directautofreelatestaliasfallbackparetobodybuilderfusion(以官方文档为准)
  • attempt:从 1 开始计数的、最终成功的那次尝试的序号。大于 1 就说明前面的尝试失败并发生了回退
  • attempts:路由针对 fallback 重试时,每次尝试的供应商、模型和状态
  • endpoints:本次考虑过的 endpoint 候选快照,以及哪一个被选中。上面那个 404 示例里,available 数组里是有条目的,只是 selected 为 false——这正好证明了「有 endpoint 存在,但没被你的偏好允许」和「压根没有 endpoint 可路由」是两种不同的失败
  • summary:一句人话,描述候选数量和被选中的供应商
  • pipeline:真正改动过请求或响应的插件(压缩、guardrail、response healing、server tools 等)。官方说没实际生效的插件不会留下 stage,所以这个数组是「确实发生过什么」的记录,不是能力清单

两个陷阱要记住。第一,缓存命中永远不带 openrouter_metadata——官方说流式和非流式的缓存重放都会剥掉这个字段,防止客户端把行为绑定在过期的路由数据上。所以拿不到元数据不代表功能没开,可能只是命中了缓存。第二,错误响应上的元数据在顶层,是 error 的兄弟节点而不是嵌在里面,四个路由和流式非流式都一样。解析代码写错层级,就等于白开了。

如果还想更深一层,官方另有一个 debug 选项,debug.echo_upstream_body 设为 true 会把实际发给上游供应商的转换后请求体回显给你。它对本文这个场景有一处专门的用途:官方在用例里写了,使用供应商 fallback 时,每一个被尝试过的供应商都会发一个 debug chunk,你能看到路由到底试过谁、给每一家发了什么参数。两个硬限制别忘:它只在流式模式下工作,非流式请求会忽略这个参数;官方明确警告不要在生产环境使用,因为它可能返回请求里本不该暴露的敏感信息。

第四步:限流引起的「不可用」,长得跟宕机不一样

限流是最常被错记成「模型挂了」的一类。OpenRouter 官方把 429 的来源明确拆成两处:

一处是平台自己,当你触到平台层的限制时触发,具体包括免费模型变体的每分钟/每日请求上限,以及 Cloudflare 的 DDoS 防护——后者会拦截显著超出合理用量的请求。另一处是上游供应商,服务你这次请求的供应商在限流或已达容量。第二种情况下,error.metadata.provider_code 会带上供应商自己的原始错误码,而且官方说 fallback 路由会先自动对同一模型的其他供应商重试,之后错误才会到你手上。

怎么一眼分辨?看响应头。官方说成功的推理响应不带 X-RateLimit-* 头;当 OpenRouter 自己因为平台限制返回限流错误时,错误响应会带上 X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset 三个头来描述被触到的那条限制。另外,当所有被尝试过的供应商都给出了重试提示时,错误响应还会带 Retry-After。所以:X-RateLimit-* 就是平台侧的账,没有但有 provider_code 就是上游那边的账。

还有两条官方明说、但很多人反着做的:

一是多开账号或多开 key 提不了限额。官方原话是容量按全局治理,额外的账号和 key 不会影响你的速率限制;但不同模型的限额不同,所以真正有效的分担方式是把流量摊到不同模型上。

二是账户余额为负时,请求可能失败,连免费模型都在波及范围内。官方说把余额补到零以上才能重新使用这些模型。这条特别值得记,因为它的表现就是「所有模型都不可用」,看起来像平台故障,实际是账户状态。限流本身的通用处理姿势可以参考API 报 429 怎么办,OpenRouter 之外的整体分层排查顺序则见OpenRouter 路由失败怎么排查

流式请求里,「不可用」会伪装成成功

这是本文最需要单独拎出来的一段。官方对流式错误的描述分成两段:

首 token 写出之前,HTTP 响应还没提交,OpenRouter 可以返回正经的 4xx/5xx 状态码,也可以在启用 fallback 路由时静默换一个供应商 endpoint 重试,还能在任何工作开始前做完限流和鉴权检查。官方说你会在这个阶段看到无效 key、请求格式错误,以及所有可用供应商 endpoint 在开始流式之前就被耗尽这类问题。

首 token 写出之后,200 OK 的状态和响应头已经提交、改不了了。这时供应商挂掉,OpenRouter 无法静默切换到另一家,因为部分内容已经交给你的应用了。错误只能以带内的 SSE 事件形式送达:顶层带 error(含 error.metadata.error_type 和可能的 provider_code),同时带一个 choices 数组,其中 finish_reason"error" 用来正确终止流,HTTP 状态仍然是 200,事件之后流就结束。

官方列的常见中途失败原因有五类:上游连接在部分输出后断开(网络问题、供应商崩溃、负载均衡器超时)、供应商在生成中途不再响应且读取超时、生成过程中触到 max_tokens 或上下文被填满、输出内容过滤器在部分文本已经流出后才标记、以及上游在开始流式之后才返回限流或容量错误。

这段的实际后果很硬:如果你的客户端只判断 HTTP 状态码,流式模式下的模型不可用会被你统计成成功请求。 监控里于是出现一个诡异现象——成功率很好看,用户却在抱怨回答被截断。判据只有一个,就是解析每个 chunk,看有没有 error 字段和 finish_reason: "error"

还有一种更安静的形态:官方单列了「没有生成任何内容」的情况,说这通常发生在模型从冷启动预热、或系统正在扩容以承载更多请求时,预热时间通常从几秒到几分钟不等,取决于模型和供应商。官方给的建议是做一个简单的重试机制,或者换一个近期活跃度更高的供应商或模型。这里有一句得让财务知道:官方说在某些情况下,即使没有生成内容,你仍可能被上游供应商收取提示词处理的费用。

让「不可用」不再变成故障

排查完之后要做的是把这件事变成不需要人介入的。官方提供的机制是 models 参数:给一个按优先级排序的模型 ID 数组,第一个模型报错时自动尝试下一个。官方明确说默认情况下任何错误都能触发 fallback,并列举了上下文长度校验错误、被过滤模型的审核标记、限流、宕机四类——注意这一句正好把本文讨论的三类原因全覆盖了。

配套的三个机制要一起记:

  • 计费按最终实际用的那个模型算,具体是哪个会在响应体的 model 属性里返回。所以配 fallback 会改变你的成本结构,账单波动时先去看这个字段的分布,成本口径的通用做法见API 成本监控
  • fallback 也失败就到头了。官方说如果 fallback 模型宕机或返回错误,OpenRouter 就把那个错误返回给你,不会无限往下试
  • allow_fallbacks 默认为 true。这是供应商层的自动兜底,关掉它等于主动放弃恢复能力——官方在 onlyignore 两处都挂了同样意思的警告

用 Anthropic Messages 皮肤的话,对应参数叫 fallbacks,形状和 Anthropic SDK 一致,映射到 OpenRouter 的 models 路由,触发条件和上面列的一样(限流、宕机、审核拒绝),不是只在拒绝时才触发。它有几条硬限制:每个条目只接受 model 字段,max_tokensthinkingspeedoutput_config 这类按次覆盖会被拒并返回 400;不能和 models 参数同时用,同时发返回 400;条目数有上限,超出返回 400,具体上限以官方文档当前版本为准。

最后是默认路由本身的自愈能力,理解它能省掉一大半误判。官方给的默认负载均衡策略是三步:先优先选取近 30 秒内没有出现显著故障的供应商(是降低优先级而非排除——官方示例里近期有故障的供应商仍会被放到最后去尝试),再在稳定的供应商里按价格取低成本候选、按价格的平方倒数加权选一个,剩下的作为 fallback。这意味着单个供应商短暂抖动通常轮不到你感知。但官方紧跟着一句:如果你设置了 sortorder,负载均衡就会被禁用。 很多「换了个模型突然变得不稳定」的案例,根源就在这里——为了省钱或提速加了排序偏好,顺手关掉了平台的抗抖动能力。

最容易栽的坑

按踩中频率排:第一,只看 HTTP 状态码不看 error_type,于是把限流当成宕机、把自己筛空候选当成平台故障。第二,流式请求不解析 chunk 里的 error 字段,让失败伪装成 200 成功,监控全是假绿。第三,忘了账户级的供应商忽略/只允许/隐私设置会和请求级合并,在代码里找一整天。第四,模型 slug 硬编码后从不复核——模型由供应商独立增删,废弃的变体后缀请求过去会因为没有 endpoint 可路由而直接失败。

下一步最值得做的一件事:给你的客户端加上 X-OpenRouter-Metadata: enabled,把 strategyattemptendpoints 三个字段落进日志。等下次「模型不可用」再来的时候,你不用猜是哪一类,日志里写着。切换厂商时的兼容性核对项,可以另外对着换厂商迁移清单过一遍。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。

留言讨论

评论发布后会被人工复核,违规内容将被删除。

    还没有人评论,来说说你的看法

    如果发表没有反应,可以前往联系我们告诉我们。

    OpenRouter 充值不方便?

    国内直连的 OpenAI 兼容端点,一期提供 DeepSeek,注册送 ¥5。

    看替代方案

    这个页面有问题?

    提交时会附带当前页面地址和浏览器信息,帮助我们定位问题。不填联系方式即为匿名。