1. 多模型接入的混乱现场:从三套密钥到一张账单
如果你所在的公司同时用上了三家以上的大模型服务,大概率经历过这种场面:算法团队在代码里硬编码了一串密钥,后端团队在配置文件里塞了另一串,运营侧某个小工具又单独申请了一个账号。月底对账的时候,财务拿着三张不同平台的账单来问“这个月AI花了多少钱”,没人能立刻答上来。更麻烦的是,某个模型服务突然限流或者涨价,想临时切到另一家,结果发现调用代码写死了接口格式,改起来要动好几个仓库。
这就是企业统一管理多家大模型API要解决的核心问题。它不是简单地“把密钥收起来”,而是要在多个模型供应商之上架一层AI网关,把鉴权、路由、计费、限流、日志、降级这些事集中处理。做完之后,业务代码只认一个入口,换模型、加模型、停模型都不用改业务逻辑。
这篇文章适合三类人看:一是正在做AI应用落地的后端或平台工程师,二是需要为团队搭建AI基础设施的技术负责人,三是被多平台账单和密钥管理搞得头疼的运维同学。我会从实际踩过的坑出发,把架构设计、鉴权方案、路由策略、成本归集、故障降级这几个关键环节拆开讲,给出可以直接参考的实现思路和配置示例。
先明确一个前提:这里说的“统一管理”,不是要你去训练或微调模型,而是把已经能用的外部模型服务(比如各家提供的对话、嵌入、多模态接口)通过一层自建网关统一收口。这个定位很重要,因为它决定了你的系统边界——你管的是调用链路,不是模型本身。
2. 为什么直连多家API迟早会失控
2.1 密钥散落带来的安全与审计难题
最开始大家图省事,谁用谁申请,密钥就放在各自的.env或者配置中心里。三个模型三家密钥,看起来还能管。等到第五个、第八个模型接进来,问题就来了:某个离职同事的密钥还在用,某个测试环境的密钥被误提交到了公开仓库,某个密钥的额度被某个跑飞的任务一夜刷爆。你去排查的时候,根本不知道哪个密钥对应哪个业务。
我见过最夸张的情况是,一个中等规模的团队里同一个模型平台有七套密钥,分别来自不同时期的七个人申请。没有统一的鉴权层,你连“谁在用哪个密钥”都说不清楚,更别提按业务线分摊成本了。
统一网关的第一个价值就在这里:所有业务方拿到的都是网关签发的内部凭证,真正的上游密钥只存在于网关的配置里。业务方看不到、也不需要知道上游密钥。要吊销某个业务的访问权限,只需要在网关侧禁用它的内部凭证,上游密钥完全不用动。
2.2 接口差异导致的重复适配成本
不同模型平台的接口虽然大体相似,但细节差异足够让你写一堆适配代码。请求体里有的用messages数组,有的用prompt字符串;返回结构里有的把内容放在choices[0].message.content,有的放在output.text;流式返回的SSE格式、结束标记、错误码定义也各不相同。
如果每个业务团队都自己写适配,那就是N个团队乘以M个模型的重复劳动。更糟的是,当某个平台升级接口版本时,你要通知所有团队改代码。而有了统一网关,适配层只写一次,上游接口变了只改网关,业务方无感知。
2.3 成本归集与配额控制的缺失
没有网关的时候,成本控制基本靠“事后看账单”。某个业务突然用量暴涨,你只能等账单出来才知道。而且多家平台的账单格式不同,想合并统计需要人工整理。
网关可以在请求经过时就打上业务标签,实时累计每个业务、每个模型、每个时间段的调用量和token消耗。这样你不仅能做事后归集,还能做实时配额——某个业务当天额度用完了,网关直接拒绝,不会等到月底才发现超支。
提示:成本归集的前提是网关能拿到准确的token计数。有些平台的返回里带usage字段,有些需要你自己估算。建议在网关层统一做一次token估算作为兜底,避免某个平台不返回usage时统计断档。
3. AI网关的架构分层与核心组件
3.1 接入层、路由层、适配层的职责划分
一个能扛住生产流量的AI网关,我建议至少分三层来设计。
接入层负责对外暴露统一接口,处理内部凭证校验、请求限流、请求日志。这一层不关心具体调用哪个模型,只负责“这个请求合不合法、要不要放行”。
路由层负责决策“这个请求该发给哪个模型”。决策依据可以是业务方指定的模型名、请求内容的特征(比如长度、语言)、当前各上游的健康状态、成本优先级等。路由层是统一管理的大脑,也是最需要仔细设计的地方。
适配层负责把统一格式的请求翻译成各上游的原生格式,再把上游返回翻译回统一格式。这一层是脏活累活的集中地,但也是隔离上游差异的关键。
三层之间通过明确定义的数据结构通信。接入层和路由层之间传的是“标准化请求”,路由层和适配层之间传的是“带目标模型标记的标准化请求”。这样任何一层的改动都不会波及其他层。
3.2 统一请求与响应格式的设计要点
统一格式的设计直接决定了网关好不好用。我的经验是:向上游看齐主流,向业务方保持稳定。
请求侧,我倾向于采用目前最通用的对话格式作为基准:一个model字段标识目标模型(可以是逻辑名而非物理名),一个messages数组承载对话内容,外加temperature、max_tokens、stream这些通用参数。对于不支持的参数,网关要么忽略,要么在适配层做转换。
响应侧,统一成包含id、model、choices、usage的结构。usage里至少要有输入token数、输出token数、总token数。流式响应则统一成SSE格式,每个chunk的结构一致,结束时有明确的终止标记。
这里有个容易忽略的点:错误格式的统一。上游返回的错误五花八门,有的用HTTP状态码,有的在body里放错误码。网关要把它们归一成一套内部错误码,比如RATE_LIMITED、CONTEXT_EXCEEDED、UPSTREAM_ERROR、AUTH_FAILED。业务方只需要处理这套内部错误码,不用去记每家平台的错误定义。
3.3 配置中心:模型清单与路由规则的存放
网关要管理多家模型,配置不能写死在代码里。你需要一个配置中心来存放:有哪些上游、每个上游的密钥和base_url、每个上游支持哪些模型、每个模型的定价、路由规则、限流规则。
配置的更新要支持热加载,不能每次加个模型就重启网关。我一般用数据库存配置,网关启动时加载到内存,同时监听配置变更事件。变更时做一次原子替换,保证正在处理的请求不受影响。
配置结构大致长这样:
upstreams: - name: provider-a base_url: https://api.provider-a.com/v1 api_key: ${PROVIDER_A_KEY} models: - name: model-a-large context_window: 128000 input_price: 0.00001 output_price: 0.00003 - name: provider-b base_url: https://api.provider-b.com/v1 api_key: ${PROVIDER_B_KEY} models: - name: model-b-pro context_window: 32000 input_price: 0.000008 output_price: 0.000024 routes: - match: model == "chat-default" targets: - provider-a/model-a-large - provider-b/model-b-pro strategy: cost_first这个结构里,业务方请求chat-default,网关根据cost_first策略选一个当前可用且成本最低的上游。要调整策略或加新上游,改配置就行。
4. 鉴权体系:内部凭证与上游密钥的隔离
4.1 内部凭证的签发与校验流程
内部凭证是业务方访问网关的通行证。我建议用带签名的token,而不是简单的静态字符串。静态字符串一旦泄露就只能整体更换,而签名token可以设置有效期、绑定业务标识、支持细粒度吊销。
签发流程:业务方在管理后台申请凭证,指定业务名称、可用模型范围、额度上限。网关生成一个token,格式可以是业务ID.过期时间.签名。签名用网关持有的密钥对前两部分做HMAC。
校验流程:请求到达接入层,提取token,验证签名、检查过期时间、检查业务ID是否被禁用、检查请求的模型是否在授权范围内。全部通过才放行,并把业务ID注入到请求上下文,供后续计费和日志使用。
import hmac import hashlib import time def issue_token(biz_id, secret, ttl_seconds=86400): expires = int(time.time()) + ttl_seconds payload = f"{biz_id}.{expires}" sig = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest() return f"{payload}.{sig}" def verify_token(token, secret): parts = token.split(".") if len(parts) != 3: return None biz_id, expires, sig = parts if int(expires) < time.time(): return None expected = hmac.new(secret.encode(), f"{biz_id}.{expires}".encode(), hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, sig): return None return biz_id这段代码是简化版,生产环境还要考虑密钥轮换、吊销列表、时钟偏移等问题。但核心思路就是:业务方拿到的凭证和上游密钥完全解耦。
4.2 上游密钥的加密存储与轮换
上游密钥是网关最敏感的数据。我的做法是:密钥不落明文盘,存在配置中心时用KMS或者主密钥加密,网关启动时解密到内存。内存里的密钥也要做保护,避免被日志或异常堆栈带出来。
轮换方面,每个上游密钥都应该有备用密钥。轮换时先加新密钥,观察一段时间确认新密钥工作正常,再停用旧密钥。网关要支持一个上游配置多个密钥,按权重或轮询使用,这样轮换过程对业务完全透明。
注意:千万不要把上游密钥写进代码仓库,哪怕是私有仓库。我见过太多因为仓库权限管理不严导致密钥泄露的案例。密钥只能存在于配置中心或密钥管理服务里。
4.3 细粒度权限:按业务、按模型、按额度
内部凭证不能是“一把钥匙开所有门”。不同业务方应该有不同的权限范围。比如客服机器人只能用对话模型,数据分析工具只能用嵌入模型,某个实验项目只能用小模型。
权限模型可以设计成:凭证绑定一个策略,策略里包含允许的模型列表、每日token上限、每分钟请求数上限、是否允许流式。网关在接入层校验这些策略,超限直接拒绝并返回明确的错误信息。
额度控制需要实时计数。我一般用Redis做计数器,key按业务ID:日期:模型组织,每次请求前检查、请求后累加。这里有个细节:流式请求的token数在请求开始时是不知道的,需要先按预估上限扣减,请求结束后再按实际用量修正。
5. 路由策略:让请求找到最合适的模型
5.1 按成本、延迟、可用性的多目标决策
路由策略是网关最体现“统一管理”价值的地方。最简单的策略是固定路由——业务方指定模型名,网关直接转发。但既然做了网关,就应该利用它做更聪明的决策。
常见的策略维度有三个:成本、延迟、可用性。成本优先适合批量任务,延迟优先适合交互场景,可用性优先适合关键业务。实际生产中往往是组合策略:先过滤掉不可用的上游,再在可用的里面按成本或延迟排序。
我通常会给每个上游维护一个健康分数,由最近的成功率、平均延迟、限流频率综合计算。路由时先排除健康分数低于阈值的上游,再按策略排序。这样某个上游出问题时能自动被降权,恢复后自动回归。
5.2 灰度与A/B测试的流量切分
新模型上线或者切换上游时,直接全量切风险太大。网关应该支持按比例切分流量。比如新模型先接5%的流量,观察一周没问题再逐步放大。
实现上,可以在路由规则里加权重。业务方请求逻辑模型名,网关按权重随机选一个物理上游。权重可以配置成动态的,通过管理接口调整。
A/B测试也是类似思路,只是切分维度不同。可以按用户ID哈希、按请求特征、按业务标签来切。网关记录每个分支的调用结果,方便后续对比分析。
5.3 上下文超长时的自动降级与截断
大模型都有上下文窗口限制。当请求的token数超过目标模型的窗口时,网关不能直接把错误抛给业务方,而应该尝试降级:要么换一个窗口更大的模型,要么对上下文做截断。
降级策略要配置化。比如chat-default路由到model-a-large(128K窗口),如果请求超过128K,自动降级到model-c-xlarge(200K窗口)。如果所有目标模型都放不下,再返回明确的错误。
截断策略则要小心,不能简单地从中间砍掉。对话场景下,通常保留system消息和最近的几轮对话,把中间的历史消息做摘要或丢弃。这个逻辑放在网关里做,业务方就不用各自实现了。
6. 成本归集与配额控制的落地细节
6.1 Token计数的三种来源与校准
成本归集的基础是准确的token计数。来源有三种:上游返回的usage、网关自己估算、业务方上报。最可靠的是上游返回的usage,但不是所有平台都返回,也不是所有接口都返回。
我的做法是:优先用上游usage,没有就用网关估算,估算算法按模型类型选择。对话模型可以用简单的字符数除以系数来估算,中文大约1.5字符一个token,英文大约4字符一个token。这个估算不精确,但用于配额控制足够了。
定期要用上游账单来校准估算系数。比如发现某个月估算值比账单低了20%,就把系数调高。校准后的估算值用于实时配额,账单用于最终结算。
6.2 实时配额与事后对账的配合
实时配额是“防超支”,事后对账是“算清楚”。两者缺一不可。
实时配额在网关层做,每次请求前检查业务方的剩余额度,不够就拒绝。额度按天或按月重置。这里要留一个缓冲,比如额度用到90%时给业务方发告警,用到100%时拒绝。
事后对账则是把网关记录的调用明细和上游账单做比对。差异可能来自:估算误差、上游计费规则变化、重复计费、漏计。对账周期建议按周,发现问题及时调整。
6.3 按业务线分摊成本的标签设计
成本要能分摊到业务线,前提是每个请求都带业务标签。标签在签发内部凭证时就绑定,请求经过网关时自动注入。标签体系要提前设计好,至少包含:业务线、项目、环境(生产/测试)。
统计时按标签聚合,就能得到每个业务线的成本。如果公司有内部结算系统,网关可以定期导出成本报表对接进去。
| 标签维度 | 示例值 | 用途 |
|---|---|---|
| 业务线 | 客服、搜索、推荐 | 成本分摊 |
| 项目 | 智能客服v2 | 项目核算 |
| 环境 | prod、staging | 区分生产测试 |
| 模型 | model-a-large | 模型成本分析 |
7. 故障降级与可观测性建设
7.1 上游限流、超时、报错的分级处理
上游出问题是常态,网关必须能优雅处理。我把上游故障分三级:
一级:单次请求失败。比如超时、5xx错误。处理方式是重试,但要有次数限制和退避策略。重试还不能解决就降级到备用上游。
二级:上游持续不可用。比如连续多次失败或限流。处理方式是把该上游从健康列表中摘除,后续请求不再路由到它。摘除后要定期探测,恢复后自动加回。
三级:所有上游都不可用。这是最坏情况,网关应该返回明确的错误,并触发告警。同时可以启用“保底模型”——一个虽然贵但稳定的上游,只在其他都不可用时使用。
7.2 全链路日志与调用追踪
出了问题要能快速定位。网关的日志要记录:请求ID、业务标签、目标模型、请求token数、响应token数、耗时、状态码、错误信息。这些日志要能按请求ID串联起来,方便追踪一个请求经过了哪些环节。
如果公司有分布式追踪系统,网关要接入,把每个上游调用作为一个span。这样能看到请求在网关内部和上游的耗时分布。
7.3 关键指标监控与告警阈值
需要监控的指标至少包括:请求量、成功率、P95延迟、各上游的错误率、限流次数、token消耗速度、配额使用率。
告警阈值要根据业务特点设置。比如成功率低于99%告警,P95延迟超过3秒告警,某个上游错误率超过5%告警,某个业务配额使用超过90%告警。
提示:告警要分级,避免告警风暴。上游单次失败不用告警,持续失败才告警。配额使用率这种可以只发通知不发告警。
8. 从零搭建时的几个关键取舍
8.1 自建网关还是用现成方案
市面上有一些开源的AI网关方案,也有云厂商提供的托管服务。自建的好处是可控、可定制、数据不出内网;坏处是要投入人力开发和维护。用现成方案的好处是上手快;坏处是定制能力受限,可能不满足特定的鉴权或计费需求。
我的建议是:如果团队有后端开发能力,且对成本归集、权限控制有明确要求,自建更合适。如果只是想让业务方统一入口、做个简单转发,用现成方案也能凑合。但要注意,现成方案往往在细粒度权限和成本归集上比较弱。
8.2 同步转发与异步队列的适用场景
大部分场景用同步转发就够了:请求进来,网关调上游,拿到结果返回。但有些场景适合异步:比如批量任务、长文本处理、对延迟不敏感的离线分析。
异步模式下,网关把请求放入队列,立即返回一个任务ID。业务方轮询或通过回调获取结果。这样网关可以控制并发,避免上游被瞬时流量打垮。
两种模式可以共存,由业务方在请求时指定。同步适合交互,异步适合批处理。
8.3 多租户隔离的边界在哪里
如果网关要服务多个业务方,租户隔离就很重要。隔离的边界包括:凭证隔离、配额隔离、日志隔离、配置隔离。
凭证和配额隔离前面讲过了。日志隔离是指业务方只能看到自己的调用日志,不能看到别人的。配置隔离是指某些业务方可以有专属的路由规则或模型白名单。
隔离的粒度要权衡。隔离太粗,业务方互相影响;隔离太细,管理成本高。我一般按业务线做隔离,业务线内部共享配额和路由规则。
9. 我在实际落地中踩过的几个坑
第一个坑是流式请求的计费。最开始我们只在请求结束时统计token,结果流式请求如果客户端提前断开,网关拿不到完整的usage,计费就漏了。后来改成请求开始时按预估上限预扣,请求结束后按实际用量修正,客户端断开时按已产生的chunk估算。这样虽然不精确,但不会漏计。
第二个坑是上游密钥的并发限制。有些上游对单个密钥有并发限制,我们一开始所有请求共用一个密钥,高峰期大量请求被限流。后来改成每个上游配置多个密钥,网关做轮询,并发能力上去了。但要注意,多密钥轮询时,某些上游的会话一致性可能受影响,需要确认上游是否支持。
第三个坑是配置热加载的原子性。有一次更新路由配置时,新配置加载了一半,导致部分请求路由到了不存在的上游。后来改成双缓冲:新配置加载到备用缓冲区,加载完成后原子切换指针。切换过程中正在处理的请求继续用旧配置,新请求用新配置。
第四个坑是错误码的语义丢失。上游返回的错误被网关统一成内部错误码后,有些业务方需要知道更具体的原因,比如是内容审核不通过还是模型过载。后来我们在内部错误码之外,保留了一个upstream_detail字段,透传上游的原始错误信息,供业务方按需使用。
第五个坑是配额重置的时间边界。最开始按自然日重置,结果发现跨时区业务方的“一天”定义不同。后来改成按UTC时间重置,并在文档里明确说明。如果业务方有特殊需求,可以支持自定义重置时间。
这些坑的共同点是:都不是架构层面的问题,而是细节处理不到位。但正是这些细节,决定了网关是“能用”还是“好用”。
10. 后续可以继续扩展的方向
网关跑稳之后,可以往上叠更多能力。比如语义缓存:相似的请求直接返回缓存结果,省下上游调用。提示词管理:把提示词模板集中管理,业务方引用模板ID而不是硬编码。模型评测:网关记录每个模型的响应质量,为路由策略提供依据。自动扩缩容:根据流量预测动态调整上游配额。
但这些都是后话。第一步还是把统一入口、鉴权、路由、计费这四件事做扎实。这四件事做好了,后面加什么能力都是锦上添花。做不好,加再多功能也是空中楼阁。
我个人在实际操作中的体会是:统一管理多家大模型API,技术难度不在某个单点,而在整体的协调和细节的打磨。架构设计要留足扩展空间,但第一版不要过度设计。先把最痛的问题解决掉——密钥收口、成本可见、故障可降级——然后再逐步完善。