模型越接越多就乱了:两类 AI 网关的边界本来就不一样
被问得最多的一个判断题是”我们要不要上一套 AI 网关”。提问的团队听起来一样,往下追两句就分成两类。一类是应用团队:产品里调了七八个模型,代码里散落着各家 SDK、各家错误码、各自的超时与重试逻辑,换模型要改三个服务。另一类是平台组或业务管理部门:手里有一笔共享预算,要把额度切给几十个团队、几百个人,甚至对外开放申请。前者要的是”应用的基础设施”,后者要的是”额度的分发系统”。这两件事被同一个词包在一起,选型就一定跑偏。

这个分叉不是口味问题。它决定了三件最难回改的事:鉴权模型、观测粒度、数据留存责任。
一、鉴权模型:一个请求进来时,系统知道的是”谁的应用”还是”谁的额度”
应用侧网关的调用方是自己写的应用。身份粒度是”环境 + 服务”,凭证由部署系统注入,请求量在设计时就能估出来,出了问题能定位到具体代码分支。这类网关里,鉴权的作用是”别让人随便用”,不是”算清每个人用了多少”。
分发型网关正相反。调用方可能是任何拿到令牌的人,身份必须落到令牌主体、所属分组、剩余额度这三层,于是它必然带着一套账务动作:签发、发放或充值、暂停、过期、余额扣减、账单出账。同一份上游凭据被大量主体共享,隔离就成了第一需求而不是附加功能。
三条直接后果:
- 应用团队不需要账户体系,硬加上去只是多养一套用户表、一套权限逻辑和一堆没人认领的历史令牌。
- 分发场景没有配额与主体归属等于裸奔:任何一把 key 外泄,成本由共享池承担,事后追不到人。
- 观测的聚合键不同。前者按调用链、按业务场景聚合,关心首包延迟、超时率、fallback 命中率;后者按主体、按渠道、按倍率聚合,关心消耗分布、余额告警和异常主体。
二、职责对照:八项能力在两类产品里的实现深度不一样
同名列在不同产品里的完成度差距很大,问”支不支持”没意义,要问”以什么粒度支持”。
| 职责 | 应用基础设施型 | 额度分发型 |
|---|---|---|
| 协议归一 | 核心能力,要抹平各家接口差异,含流式、工具调用、结构化输出的语义对齐 | 通常具备,但优先保证可转发、可计量,语义细节常有损 |
| 路由与降级 | 按模型能力、成本、延迟做动态选择与 fallback | 按渠道可用性、倍率与剩余容量选上游 |
| 限流与配额 | 按服务和场景限并发,保护上游配额不被自己打满 | 按主体分余额,按分组定速率 |
| 密钥托管 | 上游凭据集中,应用只持有网关凭证 | 同前,另需令牌签发、暂停、到期与批量吊销 |
| 计费口径 | 成本归属到应用与场景,供内部分摊 | 账务化:单价、倍率、余额、出账 |
| 多租户隔离 | 弱需求,环境级隔离一般够 | 强需求,主体之间不可见、不可互占容量 |
| 审计留痕 | 以调用链与错误上下文为主 | 以主体行为、余额变动、凭证使用为主 |
| 异常恢复 | 熔断、重试预算、降级到更小的模型 | 渠道切换、排队削峰、余额保护 |
边界在开源实现里是模糊的:应用侧网关会长出虚拟 key 和预算字段,分发型网关也做协议归一。如果一定要落到具体项目上,通常被当作前者的是 LiteLLM 这一类代理,被当作后者的是 one-api、New API 这一系带账户与渠道倍率的转发层——但两边都在往对方的功能区间生长,版本之间差异也不小。所以判断依据是”你是否准备承担账务与主体隔离”,而不是项目名字。答不出这个问题,两边的功能都会缺一块。
三、成本口径陷阱:网关给出的”成本”是估算,不是账单
这一条最容易在季度对账时爆掉。原因不是算错,是不同上游的用量字段本来就不能直接相加:
- 上下文窗口长度与计入口径不同。系统提示、工具定义、检索片段是否算进输入 token,各家处理不一样。
- 思考链与推理 token 的归属不同。有的并入输出 token 计费,有的单列一项,有的干脆不回传。
- 缓存命中后的输入单价与非命中不同,而用量里是否回传缓存字段也不统一。
- 单价本身有三套数:公开标价、合同折扣、网关里配置的渠道倍率。系统里通常只存其中一套。
于是网关面板上那个”总成本”是估算视图。拿它直接进财务或部门分摊,第一次核对就会得出”系统数字和账单对不上”的结论。要补的动作是一次窗口对账:选若干时间窗,把网关记录的原始 usage 与供应商账单逐项比差额,再把差额拆开归因到字段缺失、倍率配置、重试计费、未回传的用量、税费与汇率这几类。
工程上建议把账本设计成两层:不可变的用量事实(原始 usage、来源字段、上游响应标识、时间戳)单独存,成本作为可重算的派生视图,单价与倍率规则版本化。这样调口径不用改历史数据,也能回答”某一历史窗口按当时规则和按当前规则各算出多少”。内部摊派时还要写明摊的是估算成本还是实际账单,两者差多少要落在说明里,否则第一次质疑就没人能答。
四、路由与降级的工程现实
路由表写起来只有一行,运行时的坑都在参数上。
超时至少要分开两个值:首包/首字节超时和整体完成超时。流式请求在首包之后长时间停滞,与批量补全慢返回,是两种不同的故障,用同一个超时值会同时误判。重试要按上游语义分流:限流类与明确的服务端错误可以重试;已经发出、已经可能完成生成却因为本地超时而失败的请求,重试会带来重复计费,因为上游对已经产出的 token 照收。重试次数要有上限、退避要加抖动,并且检查调用方 SDK、网关、上游三层是否会叠加——三层各自重试两次,实际就是八次放大。
fallback 换模型之后的问题是输出分布漂移。同一套提示词在替代模型上不等价,质量下降常常先由业务方察觉而不是由监控发现。因此评测集必须跟着路由表一起切换,路由规则变更要触发一次固定的回归评测,而不是等下一批投诉。所有路由决策都要落日志:命中了哪条规则、原始错误码是什么、最终调了哪个模型,否则事后无法解释”为什么某个时间段的回答质量变差”。
五、密钥进网关之后:解决了什么,没解决什么
解决的是泄露面。上游凭据从各应用、各前端、各脚本里收回来,轮换只改一处,离职与代码外发的风险显著下降。
没解决的是:网关本身成了单点高价值目标。它同时持有上游凭据、所有人的请求体和会话内容,一旦被越权访问,损失不是”一个 key”而是全部。四件事必须一起补:入口鉴权分层,应用凭证与终端用户凭证分开、不能互换;上游凭据短周期轮换,并且轮换后要验证服务是否热生效(私钥换了进程还在用旧凭据这类事故在别处常见,这里同理);请求体日志做字段级脱敏,落在写盘之前,而不是靠”日志不给别人看”;按主体限并发,防内部滥用和脚本刷取。
部署形态这条线单独说一句。私有化或混合部署时,跨境链路带来的抖动会直接改变重试与超时的合理取值,重试预算要按链路质量定而不是写固定值。自建与用托管之间真正的取舍项是合规与数据留存责任、新模型接入速度、以及运维带宽。中小团队的瓶颈通常不是”选哪个开源项目”,而是没人跟版本:升级、依赖冲突、漏洞通告、故障时的定位能力都落在同一个人身上,这个人一旦转岗,网关就变成一个没人敢动的组件。按”谁长期负责跑这个进程”来判断,比按功能表判断更准。
六、洹拓视角:八条选型自检
- 调用方是我们自己写的应用,还是要发凭证给外部主体?这一条答不清,不要进功能对比。
- 系统能不能回答”哪一笔消耗属于哪个主体”,粒度到应用、团队还是个人。
- “成本”这个字段的计算规则是否版本化,能否用原始用量事实重算。
- 有没有做过一次与上游账单的窗口对账,差额归因是否写下来。
- 超时是否分开定义首包与整体;重试预算是否检查过三层叠加。
- fallback 切换模型时评测集是否跟着切,谁负责看输出质量漂移。
- 请求体是否落日志,哪些字段被过滤,留存多久,谁有权查,越权查询怎么拒。
- 这个进程由谁维护,升级路径和回滚方案是什么,负责人转岗后怎么办。
按这八条问完,结论通常不是”选 A 还是选 B”,而是”我们其实需要两套东西”:一个贴着应用的网关,一个面向使用者的额度与凭证管理,中间用明确的接口分开。别用一个词解决两个问题——把分发能力塞进应用网关,得到的是没人审计的账务;把路由代理接到公开申请者手里,得到的是一个替陌生人保管全部凭据的单点。