One-API 网关架构拆解:多模型路由与计费#
当公司里有多个模型供应商(通义、DeepSeek、GPT、自研),每个业务方各接各的 key、各写各的兼容层,计费对账要手动从 8 个后台导出——这就是我们上 One-API 网关前的情况。
一、网关要解决的四件事#
| 问题 |
网关方案 |
| 接入乱:每业务方一套 key/SDK |
统一 OpenAI 兼容入口,业务零改造 |
| 路由:哪个模型放量、哪个降级 |
按渠道/模型/优先级路由 |
| 限流:防一个业务打爆账号 |
令牌桶按用户/渠道限流 |
| 计费:用多少、花多少、谁花的 |
统一计量 + 计费对账 + 余额扣减 |
二、整体架构#
关键设计:对外永远一个 OpenAI 兼容协议——业务方已经用 OpenAI SDK 的直接切换 base_url 就行,不用改代码。
三、模型路由#
路由规则(优先级从高到低)#
1
2
3
4
5
6
7
|
// 路由核心(简化)
func route(ctx, model string) *Channel {
pool := channelsForModel[model] // 该模型的所有可用渠道
pool = filterHealthy(pool) // 剔除熔断/超限渠道
if len(pool) == 0 { return nil } // 全部不可用 → 报错
return pickByPolicy(pool, policy) // 按策略选一个
}
|
模型名即路由键:qwen-max、deepseek-chat 在配置里映射到对应渠道池,新增模型=加配置,不改代码。
熔断与重试#
- 渠道连续失败 N 次 → 熔断 60s
- 上游超时/5xx → 换渠道重试 1 次(幂等安全才重试,流式已出 token 不重试)
- 渠道恢复探测:熔断结束后放少量流量试探
四、限流#
双层令牌桶:
1
2
3
4
5
|
// 令牌桶(golang.org/x/time/rate)
limiter := rate.NewLimiter(rate.Limit(qps), burst)
if !limiter.Allow() {
return 429, "rate limit exceeded"
}
|
渠道层限流最重要:供应商账号有并发限制,超了会封 key。渠道限流宁可误杀(429 可重试)不可放行(封号不可逆)。
五、计费:商业化闭环的核心#
计量(网关侧)#
每次请求完成,网关按模型单价计算成本:
流式请求的 token 统计:SSE 结束帧(usage 字段)里带完整用量,网关必须等流结束才落账——断流请求要按已产生的 token 结算。
计费(业务侧)#
- 按用户扣减:请求带
x-user-id,网关记账,余额不足直接 429
- 体验卡/会员:不同用户组对应不同模型白名单和配额
- 对账:网关每日结算报表 vs 供应商账单,自动比对,差异告警
关键:计费必须和流式解耦#
别在流中间扣钱——流中断时扣多了用户会炸,扣少了公司亏。统一"流结束按 usage 结算",且记账失败要重试(Outbox 模式),对账不丢单。
六、踩坑记录#
- 模型名混用:业务方直接传供应商原始模型名,路由失效 → 强制走网关统一模型名映射
- SSE 透传把鉴权丢了:转发流时 header 要重建,别把上游的 key 透给客户端
- 并发计费竞态:同一用户并发请求同时扣费 → Redis 原子扣减(Lua),扣失败回滚
- 渠道 key 泄漏风险:渠道 key 只存在网关配置中心,业务方永远接触不到
One-API 网关的本质是把 AI 供应商变成可插拔的资源池:
- 统一入口:OpenAI 兼容协议,业务零改造
- 路由+熔断:模型即路由键,渠道故障自动降级
- 双层限流:保业务公平,保账号安全
- 计费闭环:计量在网关,结算在业务,流结束才落账
网关不是转发代理,是 AI 商业化的基础设施——没有它,多模型策略和商业化计费都无从谈起。
微信公众号「福清而不淡」
后端架构 · AI 工程 · 云原生的一线实践,扫码关注,不错过更新。
本文已同步发布到公众号,欢迎留言交流。