OpenRouter 模型名后面的后缀改变了什么:nitro、floor、exacto 各自换掉路由的哪一段

2026-08-18

接手别人写的接入代码时,最容易被跳过的一行往往是 model 那一行。两份看起来一模一样的请求体,一个写 openai/gpt-5.2,另一个写 openai/gpt-5.2:nitro,其余字段完全相同——它们在 OpenRouter 那边并不是同一件事。更麻烦的是,这些后缀在文档里被拆到了七个页面上,每页都很短,看完也很难说清「我加的这个后缀,到底顶掉了默认行为里的哪一项」。

这篇就沿着官方文档把这条路径走一遍:一次请求进来,后缀在哪一步生效,它替换掉的是什么,以及哪些后缀根本不是同一类东西。

先分类:不是所有后缀都作用在同一层

OpenRouter 的 FAQ 页(openrouter.ai/docs/faq)里有一段把这件事说得最干净,它把变体分成两类:

  • 静态变体(static variants):只能用在特定模型上,哪些模型有,列在 models API 里。文档列出三个::free:extended:thinking
  • 动态变体(dynamic variants):可以用在所有模型上,改的是「请求如何被路由或如何被使用」。文档列出四个::online(已标注 deprecated)、:nitro:floor:exacto

这条分界线比后缀本身重要得多。按文档的说法,静态变体改的是你在寻址哪一个模型条目——哪些模型带这个条目,要去 models API 里查;动态变体改的是模型选定之后、在多个供应商之间怎么排序,文档明说它可以用在所有模型上。

一个佐证是 models API 的行为:openrouter.ai/docs/guides/overview/models 这一页写明单模型查询端点支持变体后缀,示例里直接把后缀写进了 URL:

# Variant suffixes
curl "https://openrouter.ai/api/v1/model/openai/gpt-4:free"

同一页还写明,模型不存在且不是别名时返回 404。也就是说静态变体是可以被「查得到 / 查不到」的东西。至于把一个模型并不具备的静态变体写进请求会得到什么响应,官方文档没有说明这一点。

默认路由长什么样:不加任何后缀时

要说清后缀顶掉了什么,得先知道默认值是什么。openrouter.ai/docs/guides/routing/provider-selection 这一页给出的默认策略叫 Price-Based Load Balancing,文档把它写成三步:

  1. 优先选择近期没有出现明显中断的供应商;
  2. 在这些稳定的供应商里,看价格较低的那批候选,按价格的平方倒数加权随机选一个;
  3. 其余供应商作为 fallback。

注意第二步是加权随机,不是「永远挑最便宜那个」。这一点很多人会记错。同一页紧接着写了一句关键的话:如果你在 provider 偏好里设了 sortorder,负载均衡就被关掉,router 改为按顺序依次尝试供应商。

所以动态后缀的作用点,其实就是这一句——它们不是在默认策略上「微调」,而是把默认的加权随机整个换成确定顺序。

:nitro:floor:换掉的是 provider.sort 那一个字段

这两个后缀在文档里的定义没有任何模糊空间。provider-selection 页的 Provider Sorting 一节列出 sort 的三个取值:

  • "price":优先最低价格
  • "throughput":优先最高吞吐
  • "latency":优先最低延迟

然后:

  • Nitro Shortcut 一节写明,给任意 model slug 追加 :nitro,「exactly equivalent to」把 provider.sort 设成 "throughput"
  • Floor Price Shortcut 一节写明,追加 :floor「exactly equivalent to」把 provider.sort 设成 "price"

变体页上的写法是这样的:

{
  "model": "openai/gpt-5.2:nitro"
}
{
  "model": "openai/gpt-5.2:floor"
}

等价的完整写法在同一页里也给了:

const completion = await openRouter.chat.send({
  model: 'meta-llama/llama-3.3-70b-instruct',
  messages: [{ role: 'user', content: 'Hello' }],
  provider: {
    sort: 'throughput',
  },
  stream: false,
});

这里有一个后缀写法覆盖不到的地方,值得单独记一笔。sort 除了字符串,还可以写成对象,带 sort.bysort.partition 两个字段;partition 默认是 "model",可选 "none"。文档说明:指定了多个 fallback 模型时,默认会先按模型分组再排序,也就是主模型的 endpoint 永远先试,跟它们的性能表现无关;设成 "none" 就取消这层分组,让所有模型的 endpoint 全局一起排。而后缀在文档里只被描述为等价于字符串形式的 sort——官方文档没有给出用后缀携带 partition 的写法。需要跨模型全局排序时,只能老老实实写完整的 provider 对象。

顺带说一个容易混的边界:同一页的 Performance Thresholds 一节写明,preferred_min_throughputpreferred_max_latency 不满足阈值的 endpoint 是被降序(deprioritized,移到列表末尾),不是被排除;文档还专门加了一句,这跟 max_price 不同——价格拿不到时 max_price 会直接让请求跑不起来。排序类的后缀属于前者,它调的是顺序,不是准入。

:exacto:换掉的是排序依据本身,而且它有个自动版

:exacto 是这批里唯一一个不能翻译成「某个 sort 取值」的动态后缀。openrouter.ai/docs/guides/routing/model-variants/exacto 写明,它是一个 virtual model variant,显式启用 quality-first 的供应商排序:偏好那些工具调用质量信号更强的供应商,而不是默认的价格加权顺序。

文档写明它用三类信号:真实流量里的工具调用成功率与可靠性、吞吐与延迟这类供应商性能指标、以及 OpenRouter 自己的 benchmark harness 的结果。表现好的往前排,数据不足的排在成熟供应商之后,质量信号差的进一步降序。

这里最容易踩的一脚,是它和 Auto Exacto 的关系。openrouter.ai/docs/guides/routing/auto-exacto 写明:Auto Exacto 是一个默认就跑的路由步骤,凡是请求里带 tools 的都会走,不需要任何配置。也就是说,如果你在做 agent、请求里本来就带工具定义,那么你不加 :exacto,质量优先排序也已经在生效了:exacto 是让你在某个具体 model slug 上显式请求这套排序模式的快捷方式。

优先级规则写在 exacto 变体页的 Exacto vs. Auto Exacto 一节:如果你显式按 price、throughput 或 latency 排序,那个显式的 sort 仍然优先。 这条读起来平淡,但它是本文最该记住的一句——:floor:exacto 同时出现在一套代码里时,谁生效是有定论的。auto-exacto 页没有重复这句话,但它有一节 Opting out,把「退回价格加权行为」列成了三条路径:把 provider.sort 设成 "price"、给 model slug 加 :floor、或者在账号设置里把默认的 provider sort 设成价格。换句话说,:floor 在带工具的请求里同时还是一个关掉 Auto Exacto 的开关,很多人只把它当成省钱后缀。

关于工具调用成功率是怎么算出来的,auto-exacto 页给了相当细的口径:每个工具调用被分到三个错误类别之一——InvalidJsonJSON.parse(arguments) 抛错)、UnknownNamefunction.name 不在请求的 tools[] 里)、SchemaMismatch(校验器判定不通过);任意一个工具调用落进这三类,整个请求就被记为出错请求,比率的分子分母都按请求计数而不是按单次工具调用计数。文档还自己列了两条 caveat:Draft 2019-09 / 2020-12 才引入的关键字(如 unevaluatedProperties$dynamicRef)在 Draft 7 下不会被强制校验;JavaScript 的正则语义与 JSON Schema 正式引用的方言在一些边角情况下不同,pattern 的判定可能有出入。你自己的工具 schema 写得糙,这个指标会偏向宽松——文档自述这个指标在调用方 schema 有问题时是保守的。

三个静态变体,以及一处口径打架的地方

  • :free:变体页写明「访问模型的免费版本」,并明说免费版的限流或可用性可能与付费版不同。具体数值不在本文范围,去官方限流与定价页看。
  • :extended:变体页写明是「上下文窗口更长的模型版本」,用于处理更长输入、保留更多对话历史。具体长到多少同样是会变的数字,不写。
  • :thinking:变体页写明启用扩展推理能力,示例是把 :thinking 追加到模型 ID 上。

第三个有个坑。openrouter.ai/docs/guides/best-practices/reasoning-tokens 这一页里有一句::thinking 变体对 Anthropic 模型不再支持,改用 reasoning 参数(同页写明 Anthropic 模型只能通过统一的 reasoning 参数、配 effortmax_tokens 来开启推理)。而变体页那边的措辞仍是「append :thinking to any model ID」。两处放在一起就是不一致的:一处说随便哪个模型都能加,一处说某一族模型已经不吃这个后缀了。遇到这种情况按更具体的那一页走,并且以官方文档最新内容为准——这个平台迭代很快,本文引用的都是落盘当天的说法。

:online 已经被标 deprecated

openrouter.ai/docs/guides/routing/model-variants/online 页顶部挂着 Deprecated 警告,明写改用 openrouter:web_search server tool,理由是文档自述的:那样「让模型自己控制何时搜、搜几次」。同一段还写了一条挺实用的迁移说明——如果你的应用本来就提供了 web_search 工具(例如 OpenAI 内建的那个工具类型),OpenRouter 会自动识别并把它提升为 openrouter:web_search server tool,所以可以直接把 model slug 上的 :online 去掉。

要注意接盘的那一侧:openrouter.ai/docs/guides/features/server-tools/web-search 页顶部挂着 Beta 标记,并写明「Server tools 目前处于 beta,API 与行为可能变化」。也就是说这是一次从 deprecated 迁往 beta 的迁移,两端都不算稳定态,排期时心里有数。

还有两处细节值得记:

其一,变体页给出的 :online 等价写法是这样的:

{
  "model": "openrouter/auto",
  "plugins": [{ "id": "web" }]
}

plugins 那半截好理解,但 model 字段里写的是 openrouter/auto 而不是你原本那个 slug。web search plugin 页(openrouter.ai/docs/guides/features/plugins/web-search)给出的等价写法与此完全相同。两页口径一致,这里只如实记下这个写法,不推测它想表达什么。

其二,后缀是可以串起来写的。plugin 页写明可以把 :online 追加到 :free 变体上,并给了这个例子:

{
  "model": "openai/gpt-oss-20b:free:online"
}

文档给的这个例子里,静态后缀在前、动态后缀在后;至于换个顺序写会怎样,官方文档没有说明这一点。上面这些代码块都是从官方文档原样抄的,里面的模型 slug 只是官方当时的示例,平台上有哪些模型随时在变,别当成清单用。

Windows 侧的一点差别

exacto 页给的 cURL 示例是 POSIX shell 写法:

curl https://openrouter.ai/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -d '{
  "model": "moonshotai/kimi-k2-0905:exacto",
  "messages": [
    {
      "role": "user",
      "content": "Summarize the latest release notes for me."
    }
  ]
}'

在 macOS / Linux 或 Windows 上的 Git Bash、WSL 里可以直接这么用。在 PowerShell 里有三处会咬人,这是通用的 shell 常识,不是 OpenRouter 官方文档的内容:换行续行符不是 \ 而是反引号;环境变量要写成 $env:OPENROUTER_API_KEY;单引号包裹的 JSON 在 PowerShell 里不做变量展开但引号处理规则不同,多数情况下把请求体存成一个 .json 文件再用 curl.exe -d "@body.json" 更省事,同时注意 PowerShell 里的 curl 默认是 Invoke-WebRequest 的别名,要用真正的 cURL 得写 curl.exe。以上为按官方文档中的参数语义组合的示例,未经实测,以官方文档与 --help 的实际输出为准。

密钥不要写进代码,用 <YOUR_API_KEY> 这类占位,落到环境变量里再读。

回到那一行 model

把七个后缀按「改掉哪一项」重排一遍,这条路径就清楚了:

后缀类别文档写明它改掉的那一项
:free静态寻址到该模型的免费版本条目
:extended静态寻址到上下文窗口更长的版本
:thinking静态启用扩展推理(Anthropic 模型已不再支持该后缀)
:nitro动态等价于 provider.sort = "throughput"
:floor动态等价于 provider.sort = "price"
:exacto动态显式启用质量优先的供应商排序
:online动态已 deprecated,改用 openrouter:web_search server tool

排查时的顺序也随之固定:先看后缀是静态还是动态。静态查不到就是模型本身没有那个条目;动态出了意外,就去看请求体里是不是另外还写了 provider.sortorder——显式的那个优先,而它们一旦出现,默认的价格加权负载均衡就已经被关掉了。请求里带 tools 的话,还要记得 Auto Exacto 本来就在默认跑着。

至于本文没写的那些:具体便宜多少、快多少、上下文长多少、哪些供应商在列表里——这些数字和名单每周都在动,写进文章就是给自己埋雷,去官方定价页与模型页看当天的值。


本文依据 OpenRouter 官方文档(openrouter.ai/docs)于 2026-08-18 的公开内容整理。 该平台闭源,本文只复述官方文档写明的机制,不推断其内部实现我们没有对文中涉及的功能做过实测,因此不涉及界面外观与运行表现的任何描述。 该平台的供应商、模型与路由策略随时变动,文中不列具体供应商名单与模型清单; 价格、额度与限流的具体数值请以官方定价页与用量说明为准。 安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

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