1. 企业大模型网关到底解决什么问题
1.1 从一个真实场景说起
去年下半年,我帮一家做 SaaS 的中型团队做架构评审。他们的产品要接入大模型能力,最初的做法很直接:前端调后端,后端直接调某家模型厂商的 API,把 key 写在配置文件里。上线两周就出事了——账单暴涨、某次厂商限流导致整个功能不可用、不同业务线各自申请 key 导致成本无法归集、审计时根本说不清哪个请求是谁发的。
这不是个例。只要一家公司开始把大模型当成基础设施用,而不是当成一个玩具调一调,就一定会撞上这几个问题:多模型切换、密钥管理、成本归集、限流熔断、可观测性、内容合规。这六件事,任何一件单独做都不难,难的是它们要在一个统一的入口上同时成立。这个统一入口,就是企业大模型网关。
网关这个词在传统微服务里大家很熟,API Gateway 干的就是路由、鉴权、限流、日志。大模型网关本质上是同一套思路,但针对 LLM 的请求特征做了专门适配。它和普通网关最大的区别在于:LLM 的请求是长连接、流式返回、token 计费、有状态会话,这四点决定了你不能简单套用 Nginx 那套东西。
1.2 网关的核心职责拆解
我把大模型网关的职责归纳成五层,从下往上分别是:
- 接入层:统一 OpenAI 兼容协议。这是目前事实上的行业标准,几乎所有模型厂商、几乎所有 Agent 框架、几乎所有 CLI 工具都支持 OpenAI 格式。网关对外暴露一个
/v1/chat/completions,对内适配各家厂商的差异。 - 路由层:根据模型名、业务标签、成本策略、健康状态,把请求分发到不同的上游。比如
gpt-4o走 A 厂商,claude走 B 厂商,qwen走自建推理集群。 - 治理层:限流、熔断、重试、超时、降级。这一层是保证稳定性的关键。
- 观测层:记录每次请求的 token 数、耗时、首 token 延迟、模型、业务方、成本。没有这层,你永远不知道钱花在哪。
- 安全层:密钥托管、敏感词过滤、审计日志、租户隔离。
为什么强调"OpenAI 兼容协议"?因为这是整个生态的公约数。你去看现在主流的 Agent 框架、CLI 工具,配置里几乎都有一个base_url和api_key字段。只要网关实现了这个协议,你的所有下游工具不用改一行代码就能接进来。这是网关能"一次建设、处处复用"的根本原因。
1.3 为什么自建网关比直连厂商更划算
很多人第一反应是:直连厂商 API 不香吗,为什么要多一层?我算过一笔账。一个 50 人的研发团队,如果每人每天用 Agent 工具写代码消耗 20 万 token,按主流模型均价算,一个月就是几千万 token。直连模式下,你没法做细粒度的成本控制,某个同事写了个死循环把 key 刷爆,你只能事后发现。
自建网关之后,你可以做到:按业务线分配配额、按用户限速、异常流量自动熔断、成本实时看板。更重要的是故障隔离——某家厂商挂了,网关自动切到备用厂商,业务无感知。这种能力在直连模式下几乎不可能实现,因为你得改每一处调用代码。
还有一点常被忽略:密钥安全。直连模式下,key 散落在各个项目的配置文件、环境变量、甚至前端代码里,泄露风险极高。网关模式下,key 只存在于网关一处,下游拿到的是一张内部签发的虚拟 key,即使泄露也能随时吊销。
2. 网关的技术选型与架构设计
2.1 语言与框架的选择逻辑
网关这种 IO 密集型、高并发的组件,语言选型主要看三点:并发模型、生态成熟度、团队熟悉度。目前主流选择是 Go、Rust、Node.js 三选一。
Go 的优势是 goroutine 天然适合高并发 IO,标准库的net/http足够用,生态里有大量现成的中间件。Rust 的优势是性能极致、内存安全,适合对延迟极其敏感的场景,但开发效率偏低,团队学习成本高。Node.js 的优势是生态最贴近 LLM 领域,很多 SDK 都是 JS 优先,但单线程模型在高并发下需要靠 cluster 补。
我的建议是:如果团队没有强偏好,选 Go。它的并发模型和网关场景天然契合,部署简单(单二进制),性能足够。如果你们已经在用 Rust 做 Agent 相关的基础设施,那统一用 Rust 也合理。Node.js 适合快速验证,但生产环境要慎重。
框架层面,Go 可以用 Gin 或 Echo,Rust 可以用 Axum 或 Actix-web。不要一上来就上 Service Mesh 那套,网关本身就是一个进程,过度设计只会增加运维负担。
2.2 核心数据模型设计
网关的核心是"请求-路由-响应"这条链路,数据模型要围绕它设计。我一般会定义这么几张表:
| 表名 | 作用 | 关键字段 |
|---|---|---|
| providers | 上游厂商配置 | id, name, base_url, api_key_encrypted, weight, status |
| models | 模型映射 | id, model_name, provider_id, upstream_model, input_price, output_price |
| api_keys | 下游虚拟密钥 | id, key_hash, tenant_id, quota, used, status |
| request_logs | 请求日志 | id, key_id, model, prompt_tokens, completion_tokens, latency, status |
| rate_limits | 限流规则 | id, key_id, window, max_requests, max_tokens |
这里有个设计要点:api_key 存哈希不存明文。下游拿到的 key 是明文,网关收到后做哈希比对。这样即使数据库泄露,攻击者也无法反推出可用 key。providers 表里的上游 key 必须加密存储,解密密钥放在环境变量或密钥管理服务里,不能和数据库放一起。
request_logs 这张表是成本归集的核心。每次请求都要记录 prompt_tokens 和 completion_tokens,乘以对应模型的价格,就是这次请求的成本。注意流式请求的 token 统计要在流结束后才能拿到,所以日志写入是异步的,不能阻塞响应。
2.3 路由策略的设计
路由不是简单的"模型名到厂商"的映射,要考虑多种策略:
- 按模型名路由:最基础,
gpt-4o走 OpenAI,claude-3-5-sonnet走 Anthropic。 - 按权重路由:同一个模型配多个上游,按权重分流,用于灰度或负载均衡。
- 按成本路由:优先走便宜的厂商,贵的作为兜底。
- 按健康度路由:上游连续失败 N 次,自动摘除,冷却一段时间后再探活。
- 按租户路由:不同业务方走不同的上游,比如内部测试走自建集群,付费用户走商业 API。
实现上,我建议用一个路由链模式:每个策略是一个 handler,请求依次经过各个 handler,最终确定目标上游。这样新增策略不用改核心逻辑,符合开闭原则。
type RouteHandler interface { Next(ctx *RouteContext) (*Provider, error) } type ModelRouter struct{ next RouteHandler } type WeightRouter struct{ next RouteHandler } type HealthRouter struct{ next RouteHandler }这种链式设计的好处是每个策略职责单一,测试和替换都很方便。踩过的坑是:策略顺序很重要。健康检查必须放在权重之前,否则会把请求分到已经挂掉的上游。
3. 自动化编程 Agent 与 CLI 工具的接入实践
3.1 Agent 与 CLI 的关系厘清
很多人搞不清 Agent 和 CLI 的关系。简单说:Agent 是能力,CLI 是载体。Agent 指的是"能自主规划、调用工具、多轮迭代完成任务"的智能体;CLI 是命令行工具,是用户和 Agent 交互的一种界面。
现在主流的编程 Agent 工具,比如各种 codex 类 CLI、各种 agent 框架,本质上都是:接收自然语言指令 → 调用大模型 → 解析模型返回的工具调用 → 执行工具(读写文件、跑命令)→ 把结果喂回模型 → 循环直到任务完成。这个循环就是所谓的agent loop。
CLI 工具的价值在于它把 agent loop 封装成了一个命令行程序,你可以在终端里直接说"帮我把这个函数重构成异步的",它就自动读文件、改代码、跑测试。这种体验比在 IDE 里点来点去高效得多,尤其适合批量任务和脚本化场景。
3.2 把 CLI 工具接到自建网关
这是网关价值最直接的体现。绝大多数 CLI 工具都支持自定义base_url,你只需要:
export OPENAI_BASE_URL="https://your-gateway.internal/v1" export OPENAI_API_KEY="sk-your-virtual-key"然后正常启动 CLI 工具即可。网关会自动接管所有请求,做鉴权、路由、计费、日志。
这里有几个实操要点:
- 虚拟 key 的权限要收窄。给 CLI 工具用的 key 只允许访问代码相关的模型,不允许访问其他业务模型。
- 配额要设合理。Agent 工具很容易陷入循环,一次任务消耗几十万 token 是常事。建议按天设配额,超了自动拒绝。
- 流式响应必须支持。CLI 工具的体验高度依赖流式输出,网关如果缓冲了整个响应再返回,用户会以为卡死了。
- 超时要放宽。Agent 任务动辄跑几分钟,网关的默认超时(通常 30 秒)必须调大,否则长任务会被截断。
我实测下来,一个配置得当的网关,接入 CLI 工具后,团队的整体 token 成本能降 30% 以上,主要来自路由优化和异常流量拦截。
3.3 Agent 框架的接入差异
不同的 Agent 框架接入网关的方式略有差异,但核心都是改base_url。需要注意的是:
- 有些框架把
base_url写在代码里,需要改源码或用环境变量覆盖。 - 有些框架支持多模型配置,可以给不同用途配不同的模型,这时网关的路由策略要能区分。
- 有些框架会自己重试,网关的重试策略要和框架的重试策略协调,避免重试风暴。
一个常见的坑:框架和网关都做重试,导致请求量翻倍。解决办法是让网关做重试,框架层关闭重试,或者反过来。我一般建议网关做重试,因为网关能看到全局的健康状态,重试决策更准确。
3.4 Agent 记忆与网关的关系
Agent 的"记忆"通常分两种:短期记忆(当前会话的上下文)和长期记忆(跨会话的知识)。短期记忆就是对话历史,直接放在请求的 messages 里,网关不关心。长期记忆一般存在向量数据库里,Agent 在需要时检索出来拼进 prompt。
网关在这里的作用是:记录每次请求的完整上下文,用于审计和调试。当 Agent 行为异常时,你可以从网关日志里还原出它每一步看到了什么、做了什么决策。这个能力在排查"Agent 为什么改错了代码"这类问题时极其有用。
注意,记录完整上下文涉及隐私和存储成本,建议只记录元数据(token 数、模型、耗时),完整内容按需采样或加密存储。
4. 网关的稳定性与安全加固
4.1 限流与熔断的具体实现
限流是网关的保命机制。我一般做三层限流:
- 全局限流:整个网关的 QPS 上限,防止被单一业务打爆。
- 租户限流:每个业务方独立的配额,互不影响。
- 密钥限流:每个虚拟 key 的速率限制,防止单个 key 滥用。
算法上,令牌桶适合平滑限流,滑动窗口适合精确统计。我一般用滑动窗口做配额统计(按天/按小时),用令牌桶做瞬时速率控制。
熔断针对的是上游故障。当某个上游连续失败超过阈值(比如 5 次),自动摘除,后续请求走备用上游。冷却 30 秒后放一个探针请求,成功则恢复,失败则继续冷却。这个逻辑用状态机实现最清晰:Closed → Open → HalfOpen → Closed。
type CircuitBreaker struct { state State failures int threshold int cooldown time.Duration lastFailure time.Time }踩过的坑:熔断阈值不能设太敏感。LLM 请求本身就有一定失败率(尤其是长请求),阈值太低会导致频繁误熔断。我一般设连续 10 次失败才熔断,且只统计 5xx 和超时,4xx 不算。
4.2 密钥管理与租户隔离
密钥管理是安全的核心。原则是:上游 key 永不出网关,下游 key 可随时吊销。
上游 key 加密存储,加密密钥用 KMS 或环境变量管理。网关启动时解密到内存,不落盘。下游 key 用哈希存储,签发时返回明文,之后无法再查看。
租户隔离要做到:A 租户的请求不能访问 B 租户的资源,A 租户的日志 B 租户看不到。实现上,每个请求都带 tenant_id,所有查询都强制带 tenant_id 过滤。这是最基本的行级隔离,别偷懒。
4.3 内容安全与审计
企业场景下,内容安全是硬要求。网关可以在请求和响应两个方向做过滤:
- 请求方向:检测 prompt 里是否有敏感信息(如身份证号、手机号),可以脱敏后再发给上游。
- 响应方向:检测模型输出是否有不当内容,拦截或替换。
审计日志要记录:谁、什么时候、用什么模型、发了什么(或摘要)、返回了什么(或摘要)、消耗多少 token。日志要防篡改,建议写入只追加的存储。
这里有个平衡点:过滤太严会误伤正常请求,太松又起不到作用。我的经验是先用宽松策略跑一段时间,收集误报样本,再逐步收紧。不要一上来就上最严的规则,否则业务方会天天来找你。
5. 常见问题排查与实操避坑
5.1 流式响应被缓冲
这是最常见的坑。网关如果用了默认的 HTTP 客户端,可能会缓冲整个响应再返回,导致流式失效。解决办法是:
- 设置
FlushInterval为 -1(立即刷新)或很小的值。 - 关闭响应压缩,或确保压缩不缓冲。
- 检查反向代理层(如果有)是否也缓冲了。
我遇到过一次,网关本身没问题,是前面的负载均衡器缓冲了响应。排查方法是在网关日志里打时间戳,看首字节返回时间,如果网关很快但客户端很慢,问题就在中间层。
5.2 token 统计不准
不同厂商的 token 计算方式不同,流式响应里 token 数通常在最后一个 chunk 才返回。如果网关在流结束前就写日志,token 数会是 0。
解决办法是:流结束后再写日志,或者用异步任务补写。另外,有些厂商不返回 token 数,需要网关自己用 tokenizer 估算。估算会有误差,但用于成本归集足够了。
5.3 超时设置的两难
超时太短,长任务被截断;超时太长,故障请求占用连接。我的做法是分级超时:
| 请求类型 | 建议超时 |
|---|---|
| 普通对话 | 60 秒 |
| 代码生成 | 180 秒 |
| Agent 长任务 | 600 秒 |
| 流式首字节 | 30 秒 |
首字节超时单独设,因为流式请求一旦开始返回,后续就是持续的,不需要整体超时那么严格。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 请求 401 | key 无效或过期 | 检查虚拟 key 状态 |
| 请求 429 | 触发限流 | 查看配额和速率配置 |
| 响应慢 | 上游慢或网络问题 | 看首字节延迟和上游健康度 |
| 流式中断 | 超时或上游断连 | 检查超时配置和上游日志 |
| token 数为 0 | 流未结束就写日志 | 改为流结束后写 |
| 成本异常 | 某 key 被滥用 | 查 request_logs 按 key 聚合 |
5.5 几个独家避坑技巧
技巧一:给每个虚拟 key 打标签。标签可以是业务线、项目名、负责人。这样成本报表能直接按标签聚合,不用事后猜。
技巧二:保留最近 7 天的完整请求样本。不用全存,按 1% 采样即可。出问题时能快速定位,平时不占太多存储。
技巧三:网关的配置要能热更新。新增一个上游、调整一个配额,不应该重启网关。用配置中心或数据库轮询实现。
技巧四:给 Agent 类请求单独打标。Agent 请求的 token 消耗模式和人机对话完全不同,混在一起统计会失真。单独打标后,你能清楚看到 Agent 到底花了多少钱。
技巧五:定期做上游健康巡检。不要等用户报障才发现上游挂了。网关可以定时发探针请求,主动发现故障。
6. 从网关到 Agent 平台的演进路径
网关建好之后,你会发现它天然是一个 Agent 平台的基础。因为 Agent 平台需要的所有能力——模型接入、密钥管理、成本控制、可观测性——网关都已经有了。
演进路径一般是这样的:先有网关,解决多模型接入和成本问题;然后在网关上叠加 Agent 编排能力,比如任务队列、工具注册、会话管理;最后形成完整的 Agent 平台,业务方可以在上面注册自己的 Agent,平台统一调度。
这个演进过程中,网关的 OpenAI 兼容协议是关键。因为它意味着所有现成的 Agent 工具、CLI 工具、框架都能无缝接入,你不需要为每个工具单独适配。这是"一次建设、处处复用"的最大红利。
我在实际项目里的体会是:网关这件事,早做比晚做好。等到业务铺开、key 散落各处、成本失控了再回头做,迁移成本会高很多。而且网关本身不复杂,一个熟悉后端的人一两周就能做出可用版本,投入产出比极高。
最后分享一个小技巧:网关上线初期,先做旁路模式——所有请求照常直连,同时复制一份到网关做记录和统计。跑一两周,你就能拿到真实的流量画像,再据此设计路由和限流策略。这样切换时心里有底,不会手忙脚乱。