1. 企业多模型 API 管理的真实困境
1.1 从“单点接入”到“多模型混用”的必然趋势
我最早接触大模型 API 管理是在一个中型电商团队的项目里。当时业务方提的需求很简单:给客服系统加一个智能问答。我们选了当时效果最好的一个模型,写了个 Python 脚本直接调 API,两周就上线了。那时候觉得这事没什么难度。
但半年之后情况完全变了。客服团队说某个模型回答太“端着”,想要更口语化的;内容团队要接另一个模型做文案生成,因为那个模型中文创意写作更强;数据分析组又提出需要长上下文模型来处理合同文档。三个团队、四个模型、五套 API Key,散落在不同人的本地配置文件和环境变量里。每次有人离职或者 Key 需要轮换,就是一场灾难。
这不是个例。我后来跟十几个不同规模的技术团队聊过,发现只要公司在大模型应用上走过三个月,几乎都会遇到同样的局面:模型越来越多,调用入口越来越散,成本越来越不透明,安全边界越来越模糊。企业如何统一管理多家大模型 API,本质上不是一个技术选型问题,而是一个治理问题。
1.2 散乱调用带来的四类典型问题
我把踩过的坑和见过的案例归了归类,散乱调用大模型 API 主要带来四类问题。
第一类是密钥管理失控。API Key 被硬编码在代码里、写在配置文件里、贴在聊天记录里,甚至有人直接提交到了代码仓库。一旦泄露,轻则被人盗刷额度,重则业务数据通过模型接口外流。我见过最离谱的情况是一个 Key 同时被七个项目使用,其中一个项目出了 bug 疯狂重试,把整个月的预算在两天内烧光。
第二类是成本黑洞。每个模型厂商的计费方式不同,有的按 token 计费,有的按调用次数,有的区分输入输出价格。财务月底来问“这个月 AI 花了多少钱”,没人能给出准确答案。更麻烦的是,你根本不知道钱花在了哪个业务、哪个团队、哪个功能上,优化无从下手。
第三类是可用性风险。单一模型服务出故障时,业务直接中断。我经历过一次某模型服务商区域机房故障,客服系统整整停了四个小时,而那段时间恰好是促销活动高峰期。如果当时有统一网关做自动降级,切换到备用模型,损失会小很多。
第四类是合规与审计缺失。哪些数据发给了哪个模型?有没有敏感信息外泄?调用日志在哪里?出了问题能不能追溯?这些问题在没有统一管理的情况下几乎无法回答。
1.3 统一管理的核心目标是什么
在动手之前,得先把目标想清楚。我总结下来,统一管理大模型 API 要达成五个核心目标:
- 统一入口:所有模型调用走同一个网关,业务方不需要关心底层是哪家模型。
- 统一鉴权:内部业务用统一的身份认证,外部密钥由网关集中管理,业务代码里不出现任何厂商 Key。
- 统一计费与配额:按团队、按项目、按功能维度统计用量和成本,支持配额限制和预警。
- 统一可观测:调用日志、延迟、成功率、token 消耗全部集中采集,支持问题排查和性能分析。
- 统一策略:支持限流、降级、重试、缓存、内容过滤等策略的统一配置。
这五个目标不是都要一步到位,但方向得对。下面我按实际落地顺序,把整套方案拆开讲。
2. 整体架构设计与技术选型思路
2.1 为什么需要一层 AI 网关
最直接的做法是在业务和模型之间加一层网关。这层网关承担所有对外部模型 API 的调用,业务方只跟网关打交道。听起来像是多了一层转发,但这一层带来的价值远超它的开销。
打个比方,这就像公司从“每个部门自己去找供应商采购”变成“统一走采购部”。采购部知道所有供应商的报价、账期、质量,能谈集采价格,能统一结算,能在某个供应商出问题时快速切换。AI 网关就是大模型调用的“采购部”。
网关的核心职责包括:接收业务请求、做鉴权和权限校验、根据路由策略选择模型、管理厂商 API Key、转发请求、处理响应、记录日志和用量、执行限流和降级策略。这些职责听起来多,但拆开看每一项都不复杂。
2.2 自建还是用开源方案
这是被问得最多的问题。我的建议是:除非你有非常特殊的合规要求或者团队规模很小,否则优先考虑开源方案做二次开发,而不是从零自建。
从零自建的问题在于,你要处理的细节远比想象中多。流式响应的转发和中断处理、不同厂商 API 格式的差异、token 计数的准确性、重试时的幂等性、SSE 连接的保活……每一项都能耗掉几天时间。而这些在成熟开源方案里已经解决了。
目前社区里比较活跃的方案有几类:一类是通用的 API 网关加上自定义插件,比如在 Kong 或 APISIX 上写 Lua 插件;另一类是专门为大模型场景设计的网关,比如 One API 这类项目。前者灵活但开发量大,后者开箱即用但定制空间有限。
我的实际选择是:用专门的大模型网关做基础,在它上面做二次开发。基础功能直接用,特殊需求通过插件或旁路服务实现。这样能在两周内跑通核心流程,而不是花两个月造轮子。
2.3 部署形态:集中式还是边车式
网关的部署形态有两种主流选择。
集中式部署是网关作为一个独立服务集群运行,所有业务通过内网调用它。优点是管理简单、策略统一、成本可控。缺点是网关成为单点,需要做好高可用;另外跨机房调用会带来额外延迟。
边车式部署是每个业务服务旁边跑一个网关实例,业务调用本地网关,网关再转发到模型。优点是延迟低、故障隔离好。缺点是配置分散、版本管理复杂、资源占用高。
我实际采用的是集中式为主、关键业务边车为辅的混合模式。大部分业务走集中式网关,对延迟极度敏感的核心链路(比如实时对话)在业务侧部署轻量边车,边车定期从中心同步配置。这样兼顾了统一管理和低延迟。
2.4 核心数据模型设计
网关要管的东西不少,数据模型设计不好后面会很痛苦。我建议至少设计以下几张核心表:
| 表名 | 用途 | 关键字段 |
|---|---|---|
| 租户表 | 区分不同团队或项目 | 租户ID、名称、配额、状态 |
| 密钥表 | 管理厂商 API Key | 厂商、Key密文、状态、优先级 |
| 模型表 | 注册可用模型 | 模型名、厂商、端点、参数模板 |
| 路由表 | 定义路由策略 | 路由名、匹配规则、目标模型列表 |
| 用量表 | 记录调用消耗 | 租户、模型、token数、时间戳 |
| 日志表 | 存储调用日志 | 请求ID、租户、模型、延迟、状态 |
这里有个细节值得注意:厂商 API Key 必须加密存储,不能明文放在数据库里。我见过有人图省事直接存明文,结果数据库被拖库,所有 Key 全部泄露。加密方案可以用 AES 加 KMS 管理主密钥,成本不高但安全性提升明显。
3. 核心功能模块的实操落地
3.1 统一鉴权:业务侧只认一个 Token
统一鉴权的核心思路是:业务方拿到的不是厂商的 API Key,而是网关颁发的内部 Token。这个 Token 绑定了租户身份、权限范围和配额。
具体流程是这样的:业务方在网关管理后台申请一个 Token,后台生成一个带前缀的随机字符串(比如sk-gw-开头),同时记录这个 Token 属于哪个租户、允许调用哪些模型、每分钟最多多少次、每月最多多少 token。业务方调用时在 Header 里带上这个 Token,网关校验通过后,用自己管理的厂商 Key 去调真实模型。
这样做的好处很明显。厂商 Key 只在网关内部流转,业务方完全接触不到。Token 可以随时吊销和轮换,不影响其他业务。权限可以精细控制,比如内容团队只能用文案模型,不能用代码模型。
Token 的校验逻辑我建议用 Redis 做缓存,避免每次请求都查数据库。缓存里存 Token 到租户信息的映射,设置合理的过期时间。Token 吊销时同时删缓存,保证即时生效。
注意:Token 一定要设置前缀,方便在日志和代码里识别。我见过有人用纯随机字符串,结果在代码审查时分不清哪个是网关 Token 哪个是厂商 Key,容易误提交。
3.2 模型路由:让请求找到正确的模型
路由是网关最核心也最灵活的部分。我把它分成三个层次。
第一层是显式路由。业务方在请求里直接指定模型名,网关按名字找到对应的厂商端点和 Key。这是最简单的场景,适合业务方明确知道要用哪个模型的情况。
第二层是别名路由。业务方不指定具体模型,而是指定一个别名,比如chat-fast、chat-quality、embedding-default。网关根据别名映射到实际模型。这样业务方不需要关心底层模型变更,运维侧可以随时调整映射关系。比如某天发现某个模型降价了,直接把chat-fast指向新模型,业务方无感知。
第三层是策略路由。网关根据请求特征自动选择模型。比如根据输入长度选择:短文本走便宜的小模型,长文本走长上下文模型。根据内容类型选择:代码相关走代码模型,中文创意走中文模型。根据负载选择:主模型限流时自动切到备用模型。
策略路由的配置我建议用 YAML 或 JSON 描述,支持热加载。下面是一个简化示例:
routes: - name: chat-default match: path: /v1/chat/completions alias: chat strategy: priority targets: - model: gpt-4o-mini weight: 80 - model: claude-haiku weight: 20 fallback: - model: qwen-turbo这个配置的意思是:chat别名的请求,80% 走 gpt-4o-mini,20% 走 claude-haiku,两个都不可用时降级到 qwen-turbo。权重路由可以用来做灰度测试,也可以用来分摊成本。
3.3 密钥池与轮询:突破单 Key 限流
厂商 API 通常对单个 Key 有速率限制。业务量大的时候,单 Key 很容易触发限流。解决办法是维护一个密钥池,同一个厂商配置多个 Key,网关轮询使用。
密钥池的实现要注意几点。每个 Key 要记录状态(可用、限流中、已禁用)和最近使用时间。轮询策略可以用简单的轮询,也可以用加权轮询(根据 Key 的配额大小分配权重)。当某个 Key 返回 429 限流错误时,把它标记为限流中,一段时间内不再使用,同时把请求转发到其他 Key。
这里有个坑:不同厂商的限流维度不同。有的按请求数限流,有的按 token 数限流,有的按并发数限流。网关需要针对每个厂商做适配。我的做法是在密钥表里加一个rate_limit_config字段,用 JSON 描述该 Key 的限流规则,网关根据规则做本地预判,减少无效请求。
3.4 用量统计与成本核算
用量统计是统一管理里最容易被低估的部分。很多人觉得“记个日志就行了”,但真正做起来会发现细节很多。
首先要解决token 计数问题。不同厂商的 token 计算方式不同,同一个文本在不同模型下的 token 数可能差很多。网关需要在请求前后分别计数,请求前估算用于限流,请求后以厂商返回的实际用量为准用于计费。
其次是成本换算。每个模型的单价不同,而且经常调整。我建议在模型表里维护单价字段,用量表记录 token 数,统计时实时计算成本。单价变更时保留历史版本,避免历史账单被新价格影响。
最后是多维度聚合。财务要看月度总成本,团队负责人要看自己团队的消耗,开发要看某个功能的调用量。网关需要支持按租户、按模型、按时间、按功能标签等多个维度聚合。我通常会在请求里要求业务方带一个biz_tag字段,标识这个请求属于哪个业务功能,这样统计粒度更细。
| 统计维度 | 用途 | 更新频率 |
|---|---|---|
| 租户+模型 | 团队成本分摊 | 实时 |
| 租户+功能标签 | 功能级成本分析 | 实时 |
| 模型+时间段 | 模型使用趋势 | 分钟级 |
| 租户+配额 | 配额预警 | 实时 |
3.5 可观测性:日志、指标与追踪
可观测性三件套——日志、指标、追踪——在网关场景下一个都不能少。
日志记录每次调用的完整信息:请求 ID、租户、模型、输入输出 token 数、延迟、状态码、错误信息。日志要结构化存储,方便查询和分析。我一般用 JSON 格式写日志,采集到日志系统里。注意日志里不要记录完整的请求内容,尤其是可能包含敏感信息的场景,只记录摘要和哈希值。
指标用于监控和告警。核心指标包括:QPS、P50/P95/P99 延迟、错误率、限流次数、各模型调用占比、token 消耗速率。这些指标推送到监控系统,配置告警规则。比如错误率超过 5% 持续 5 分钟就告警,某个租户 token 消耗达到配额的 80% 就预警。
追踪用于排查跨服务问题。网关生成一个 trace ID,透传到下游,业务侧和模型侧都用同一个 trace ID 记录日志。这样出问题时可以串起整条链路。我用的方案是 OpenTelemetry,网关作为 span 的起点,把 trace context 注入到转发请求的 Header 里。
4. 常见问题与排查技巧实录
4.1 流式响应中断怎么排查
流式响应是问题最多的场景。典型症状是:客户端收到一半内容后连接断开,或者网关日志显示成功但客户端没收到完整响应。
排查思路分三步。第一步看网关日志里的响应状态和耗时,确认网关侧是否正常完成转发。第二步看客户端和服务端之间的网络链路,是否有超时配置过短。第三步看厂商侧是否有流式响应的特殊要求,比如某些厂商要求设置特定的 Header 或使用特定的 SSE 格式。
我踩过的一个坑是:网关的读超时设置得太短。流式响应是逐步返回的,如果网关设置了 30 秒读超时,而模型生成一段长文本需要 60 秒,网关会在 30 秒时主动断开。解决办法是把流式请求的超时单独配置,设置得足够长,或者用空闲超时而不是总超时。
提示:流式请求和普通请求的超时策略要分开配置。普通请求可以用总超时,流式请求建议用“空闲超时”,即两次数据块之间的间隔超过阈值才断开。
4.2 模型返回格式不一致怎么适配
不同厂商的 API 返回格式差异很大。有的把内容放在choices[0].message.content,有的放在output.text,有的用data数组。网关需要做格式归一化,把不同厂商的响应转换成统一的内部格式再返回给业务方。
我的做法是定义一个内部标准格式,然后为每个厂商写一个适配器。适配器负责请求格式转换和响应格式转换。新增厂商时只需要写一个适配器,不影响其他部分。
适配器里要特别注意错误处理。不同厂商的错误码和错误信息格式不同,适配器要把它们统一成内部错误码。比如把“限流”统一映射为RATE_LIMITED,把“认证失败”统一映射为AUTH_FAILED。这样业务方只需要处理一套错误码。
4.3 配额超限时如何优雅降级
配额超限是必然会遇到的情况。粗暴地直接拒绝请求体验很差,优雅降级的做法是:当主模型配额用尽时,自动切换到备用模型,同时记录降级事件并通知相关人员。
降级策略可以分级。一级降级:切换到同厂商的便宜模型,效果略降但成本可控。二级降级:切换到其他厂商的同类模型。三级降级:返回缓存结果或简化响应。每一级降级都要有明确的触发条件和恢复条件。
我实际配置的降级规则是这样的:当某租户的月度 token 消耗达到配额的 90% 时,开始告警;达到 100% 时,自动把请求路由到备用模型;备用模型也超限时,返回一个友好的提示信息,而不是直接报错。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决方案 |
|---|---|---|---|
| 请求返回 401 | Token 无效或过期 | 检查 Token 是否正确、是否被吊销 | 重新申请 Token |
| 请求返回 429 | 触发限流 | 查看是网关限流还是厂商限流 | 调整配额或增加密钥 |
| 响应延迟突然增大 | 厂商侧故障或网络抖动 | 查看各模型延迟指标 | 切换备用模型 |
| 流式响应中断 | 超时配置过短 | 检查网关读超时设置 | 调整流式超时策略 |
| token 计数不准 | 厂商计数方式差异 | 对比厂商返回用量和本地计数 | 以厂商返回为准 |
| 成本统计异常 | 单价配置错误 | 核对模型单价配置 | 修正单价并重算 |
4.5 几个容易忽略的细节
第一个细节是请求 ID 的生成和透传。网关要为每个请求生成唯一 ID,并透传到厂商请求的 Header 里(如果厂商支持)。这样出问题时可以用这个 ID 去厂商后台查日志。我用的格式是gw-{租户ID}-{时间戳}-{随机串},既唯一又可读。
第二个细节是重试的幂等性。网关在转发失败时可能会重试,但有些请求不是幂等的(比如生成了内容但响应丢失)。我的做法是只对明确的网络错误和 5xx 错误重试,且重试次数不超过 2 次。对于流式请求,一旦开始返回数据就不重试。
第三个细节是配置的热更新。路由规则、密钥状态、配额限制这些配置经常需要调整,如果每次都要重启网关,运维成本太高。我用的方案是配置存在数据库或配置中心,网关定期拉取或监听变更事件,实现热更新。
第四个细节是灰度发布。新增模型或调整路由策略时,先对小部分流量生效,观察一段时间再全量。网关支持按租户、按百分比做灰度,这样出问题时影响面可控。
5. 从零搭建的实操步骤参考
5.1 环境准备与基础依赖
假设你从零开始搭建,我按最小可用版本给你梳理一遍步骤。基础环境需要:一台 Linux 服务器(4 核 8G 起步)、Docker 和 Docker Compose、一个 MySQL 或 PostgreSQL 实例、一个 Redis 实例。
选 Docker Compose 是因为部署简单,适合中小规模。如果规模大了再迁移到 Kubernetes。数据库存配置和用量数据,Redis 做缓存和限流计数。
第一步是拉取开源网关项目。以 One API 为例,用 Docker 一条命令就能跑起来:
docker run -d --name ai-gateway \ -p 3000:3000 \ -e SQL_DSN="root:password@tcp(mysql:3306)/gateway" \ -e REDIS_CONN_STRING="redis://redis:6379" \ justsong/one-api跑起来后访问 3000 端口,用默认账号登录,先改密码。
5.2 配置厂商渠道与模型
登录后台后,第一步是添加渠道。渠道就是厂商的 API 端点加 Key。在“渠道”页面新建,选择厂商类型,填入 Base URL 和 API Key,选择该渠道支持的模型列表。
这里有个技巧:同一个厂商可以建多个渠道,每个渠道用不同的 Key,然后设置不同的权重。这样就实现了密钥池和负载均衡。渠道的状态可以单独控制,某个 Key 出问题时禁用该渠道即可。
添加完渠道后,在“令牌”页面创建业务 Token。设置 Token 的名称、配额、过期时间、允许的模型范围。创建后会生成一个sk-开头的字符串,这就是业务方使用的 Token。
5.3 业务侧接入改造
业务侧改造很简单,把原来调用厂商 API 的 Base URL 改成网关地址,把厂商 Key 换成网关 Token,其他基本不变。如果网关做了格式归一化,请求体格式可能也需要微调。
以 Python 为例,改造前是这样的:
import openai openai.api_key = "sk-厂商Key" openai.base_url = "https://api.厂商.com/v1/"改造后:
import openai openai.api_key = "sk-网关Token" openai.base_url = "http://网关地址:3000/v1/"就改了两行。业务代码里不再出现任何厂商 Key,所有调用走网关。
5.4 用量监控与告警配置
网关跑起来后,在后台的“日志”和“额度”页面可以看到调用记录和用量。但光看后台不够,需要配置告警。
我的做法是写一个定时脚本,每小时查询一次用量数据,对比配额阈值,超过就发通知。通知渠道可以用邮件、企业微信机器人或钉钉机器人。脚本逻辑很简单:查数据库,算比例,超阈值就调 Webhook。
import requests def check_quota(): # 查询各租户用量和配额 usage = query_usage() for tenant in usage: ratio = tenant['used'] / tenant['quota'] if ratio > 0.9: send_alert(f"租户 {tenant['name']} 用量已达 {ratio:.0%}")这个脚本虽然简单,但非常实用。我建议配额告警分两档:80% 预警,100% 告警并触发降级。
5.5 性能压测与容量规划
上线前一定要做压测。用工具模拟并发请求,观察网关的延迟、吞吐和资源占用。重点看几个指标:网关自身的延迟开销(应该控制在 10ms 以内)、并发连接数上限、数据库和 Redis 的负载。
容量规划的经验值是:4 核 8G 的网关实例,大约能支撑 500-1000 QPS 的转发(取决于请求大小和是否流式)。如果业务量更大,横向扩展网关实例,前面加负载均衡。
压测时特别注意流式请求的表现。流式请求占用连接时间长,对网关的连接数管理要求高。我建议流式和非流式请求走不同的端口或不同的实例组,避免相互影响。
6. 进阶优化与长期演进
6.1 语义缓存降低重复调用
很多业务场景下,相似的请求会被反复调用。比如客服系统里“怎么退货”这个问题,每天可能被问几百次。如果每次都调模型,成本很高。语义缓存的做法是:把请求的 embedding 存起来,新请求先查缓存,相似度超过阈值就直接返回缓存结果。
缓存的命中率取决于业务场景。客服问答类场景命中率能到 30%-50%,内容生成类场景命中率较低。缓存要注意设置合理的过期时间,避免返回过时信息。敏感场景要禁用缓存,防止数据串扰。
6.2 模型效果评估与自动切换
统一管理之后,你有了所有模型的调用数据和效果反馈,就可以做模型效果评估。比如记录用户对模型回答的点赞点踩,统计各模型在不同场景下的满意度。基于这些数据,自动调整路由策略,把更多流量分配给效果好的模型。
这个机制我称之为“模型 AB 测试常态化”。不需要专门做测试活动,而是把评估嵌入日常调用中。每个请求带一个反馈标识,用户反馈回传后关联到模型,定期生成效果报告。
6.3 多模态与 Agent 场景的扩展
大模型应用正在从纯文本向多模态和 Agent 方向演进。多模态意味着网关要处理图片、音频、视频等不同类型的输入输出,传输和存储的压力更大。Agent 场景意味着一次业务请求可能触发多次模型调用,网关要支持调用链的追踪和聚合计费。
这些新场景对网关提出了更高要求,但核心思路不变:统一入口、统一鉴权、统一计费、统一可观测。只是在数据模型和转发逻辑上做扩展。我建议在架构设计时就预留扩展点,比如用插件机制支持新的模态类型,用调用链 ID 串联多次调用。
6.4 团队协作与权限体系
规模大了之后,网关本身也需要权限管理。谁能添加渠道、谁能修改路由、谁能查看用量,这些都要有权限控制。我的做法是分角色:管理员有全部权限,运维可以管理渠道和路由,财务只能查看用量,普通开发者只能申请 Token 和查看自己的用量。
权限体系不用做太复杂,基于角色的访问控制(RBAC)就够了。关键是要有操作审计,谁在什么时候改了什么配置,都要记录。出问题时能追溯到人。
7. 个人实操体会与建议
我在多个团队落地过这套方案,最大的体会是:不要追求一步到位。第一版只需要把统一入口和统一鉴权做出来,让业务方先接进来。用量统计和成本核算可以第二版再做,高级路由和降级策略第三版再上。每上一版都让业务方感受到价值,而不是憋大招。
另一个体会是文档和自助服务很重要。网关团队不可能响应每个业务方的接入咨询,所以要有清晰的接入文档、示例代码和自助申请流程。我通常会在网关后台加一个“快速开始”页面,业务方照着做就能接入,减少沟通成本。
最后说一个容易被忽略的点:定期做故障演练。模拟某个厂商不可用、某个 Key 失效、数据库连接中断等场景,验证网关的降级和恢复能力。我见过太多网关平时跑得好好的,一出故障就手忙脚乱。演练过的团队,故障恢复时间能缩短一半以上。
这套方案不是银弹,但它能让你从“到处找 Key、月底对不上账、故障时抓瞎”的状态,变成“一个入口、一本账、一套策略”。对于任何在大模型应用上认真投入的团队来说,这层统一管理早晚都要做,早做早受益。