← 返回资讯

七家推理平台的模型 ID 各写各的,多平台路由怎么设计才不崩

2026-08-07

接第二家推理平台的时候,多数人以为工作量是”复制一份调用代码,改个地址和 key”。真接下来会发现,最烦的既不是地址也不是 key,是模型 ID

同一个 DeepSeek 模型,在这家叫 deepseek-ai/DeepSeek-V3,在那家叫 deepseek/deepseek-r1,再换一家变成 accounts/fireworks/models/deepseek-v3p1,还有一家干脆在名字后面挂个日期。而你的代码里,这个字符串很可能被硬编码在了七八个地方。

这篇讲清楚各家的命名形式差在哪、各自会怎么咬人,以及配置层怎么组织才能让”多接一家”真的只是加一行配置。

七家的模型 ID 形式对照

平台形式示例
Groq扁平名llama-3.3-70b-versatile
DeepInfra两段式 组织/模型deepseek-ai/DeepSeek-V3
Novita两段式deepseek/deepseek-r1
Together AI两段式MiniMaxAI/MiniMax-M3
Nebius Token Factory两段式 + 日期后缀deepseek-ai/DeepSeek-R1-0528
Fireworks AI三段式accounts/fireworks/models/deepseek-v3p1
Replicate不是模型名,是请求体里的 version(模型版本 ID)+ input

(各示例均取自对应平台官方文档,模型上下架频繁,实际以官方文档当次为准。)

光看这张表就能得出一个结论:模型 ID 是所有配置项里最不可移植的那个。 base_url 和 key 至少形式统一——一个 URL、一个字符串;模型 ID 连结构都不一样。

每种形式各自怎么咬人

两段式:少写组织前缀,报错却像权限问题

这是最隐蔽的一个。两段式的 ID 里,前半截是发布方,后半截是模型名。只填后半截会失败——这在意料之中。意外的是报错长什么样:Together AI 的这种情况,返回的错误信息看起来像权限问题,而不是”模型不存在”。

后果是排查方向直接跑偏。你会去查 key 有没有权限、账户是不是没开通某个模型、要不要申请白名单,折腾半天,问题其实在那个少写的前缀上。

我的做法是:调不通的时候,先把模型 ID 完整地打印出来看一眼,再去想权限。这一眼花一秒钟,能省掉一小时。

大小写敏感:DeepSeek-V3 不是 deepseek-v3

两段式的 ID 通常是 HuggingFace 风格的,大小写是标识符的一部分。DeepInfra 的示例是 deepseek-ai/DeepSeek-V3——组织名全小写,模型名带大写。

会踩到这个的场景很具体:团队里有人习惯把配置项统一转小写(有些配置框架甚至会自动做),或者从某篇文章里复制时对方手打成了全小写。表现是模型不存在,而你盯着那行配置看半天觉得”这不就是对的吗”。

配置层加一条断言:模型 ID 原样透传,任何自动的大小写规范化都要关掉。

日期后缀:可复现的代价是你要自己跟版本

Nebius 的示例 deepseek-ai/DeepSeek-R1-0528 把版本快照写进了 ID 里。

这是个好设计:今天调这个 ID 和三个月后调它,拿到的是同一版模型,输出行为可复现。做需要留证据的业务,或者刚调好一套 prompt 不想被悄悄改变的场景,快照是你要的。

代价是这条依赖没人替你维护。平台不会把你自动升到新版,某天这个快照下线,你才发现三个月没人看过它。给出可执行的做法:把模型 ID 收进配置的单一位置,并且在服务启动日志里把生效值打出来;每个季度花十分钟对一次官方模型列表。

三段式:完全不可复用,且中间那段有含义

Fireworks 的 accounts/fireworks/models/deepseek-v3p1 是三段式。accounts 后面那段不是装饰——平台提供的公共模型走 accounts/fireworks/...,如果你有自己部署的模型,路径会不同。

它的特点是换平台时这串字符串一点都用不上。扁平名和两段式之间还能靠猜蒙对一半,三段式不行。这反过来说明一件事:如果你的代码里出现了 accounts/fireworks/models/... 这样的字面量,那这段代码已经和这家平台绑死了。

Replicate:根本不在这个体系里

前六家都是”在请求里写一个模型名”,Replicate 不是。它是任务式 API,请求体里给的是 version(模型版本 ID)和 input,而且 input 的字段结构由具体模型自己定义。

这意味着它不能被塞进同一个抽象层。硬塞的结果是你的接口定义里长出一堆只有一个平台会用的可选字段,越写越难看。正确做法是单独做一个适配器,接口对齐在业务语义层(“给我生成一张图”),而不是在参数层。

路由层该怎么组织

上面这些坑,本质上是同一个问题:平台细节泄漏到了业务代码里。解法也就一条主线。

原则一:业务代码只用业务别名

代码里不该出现任何真实模型 ID。该出现的是业务语义的名字:fast-cheapstrong-reasoninglong-contextvision

这个改动的收益不只是可移植。它还让”某个功能该用什么档位的模型”变成一个可以讨论、可以调整的决策,而不是散落在代码里的既成事实。

原则二:映射表按「别名 × 平台」二维组织

很多人第一版会按平台分文件写配置,每个平台一份。这在只有一家的时候没问题,接到第三家就会发现:想知道 fast-cheap 在各家分别对应什么,得翻三个文件。

按二维组织,一眼能看全:

channels:
  groq:
    base_url: https://api.groq.com/openai/v1
    api_key_env: GROQ_API_KEY
  deepinfra:
    base_url: https://api.deepinfra.com/v1/openai
    api_key_env: DEEPINFRA_TOKEN
  novita:
    base_url: https://api.novita.ai/openai
    api_key_env: API_KEY

models:
  fast-cheap:
    groq: llama-3.1-8b-instant
    deepinfra: deepseek-ai/DeepSeek-V3
    novita: deepseek/deepseek-r1

(结构是示意,字段名按你的框架来;模型 ID 请以各平台官方文档当次为准。)

原则三:三件事绑成一个「通道」,切必须一起切

base_url、key 的环境变量名、模型 ID——这三样必须作为一个整体对象存在,切换时原子替换。

这是本文最重要的一条。 多通道系统最典型的线上事故就是:主通道故障,代码切到备用通道,切了 base_url、切了 key,模型 ID 忘了切,于是备用通道全线返回 404 或”模型不存在”。

这种事故的恶劣之处在于:平时完全测不出来。备用通道只在主通道挂掉的时候才启用,而主通道挂掉本来就是个坏日子——你在最糟糕的时刻发现备用方案也是坏的。

避免它的办法是让”只切一件”在类型上就不可能:通道是一个不可分割的结构体,路由层选的是通道,不是分别选地址、密钥和模型。

原则四:启动时打印生效的通道与模型 ID

一行日志,内容是”当前生效通道 = X,模型 ID = Y”。

它的价值在故障时体现:有人报告”最近输出风格变了”,你第一件事就能确认到底调的是哪家的哪个模型,而不用去反推配置的加载顺序、环境变量的覆盖关系。

原则五:非兼容平台单独适配

Replicate 这类不走 OpenAI 兼容的平台,别硬塞进通用通道抽象。给它单独的适配器,在业务语义层对齐。

判断标准很简单:如果为了容纳某个平台,你要在通用接口上加一个别的平台都用不到的字段,那就是该拆的信号。

回退演练:这件事必须主动做

前面说了,模型 ID 没切的事故只在主通道故障时暴露。所以必须主动演练,不能等它自己发生。

最低限度的演练:在测试环境里,把主通道的 base_url 改成一个必然失败的地址,然后跑一遍完整的业务流程,确认请求确实落到了备用通道上、并且拿到了正常结果。这个测试花不了半小时,但它是唯一能证明你的回退真的能用的方法。

进阶一点的做法是把这个演练做成定期任务——比如每次发版前跑一次。多模型网关的整体设计可以参考多模型网关怎么做故障转移,路由策略的部分见模型路由怎么配

自查清单

  1. 业务代码里还有硬编码的真实模型 ID 吗?搜一遍字符串常量。
  2. 映射表是按「别名 × 平台」二维组织的,还是按平台分散的?
  3. base_url、key 环境变量名、模型 ID 是不是绑成了一个通道对象、原子切换?
  4. 配置加载链路上有没有自动转小写、去空格这类”好心”处理?关掉。
  5. 启动日志里有没有打印生效的通道和模型 ID?
  6. 回退通道演练过吗?演练方式是不是”真的让主通道失败”而不是看代码觉得没问题?
  7. 带日期后缀的模型 ID,有没有人负责定期看它还在不在?

这些事单看都是小事,加起来决定了你接第三家平台的时候是花一小时还是花一周。第一家平台接完就把配置层理顺,是回报率最高的一次重构——因为那时候要改的地方最少。

相关阅读