1. 为什么我最终决定给 AI Agent 套一层本地网关
先说说我这边的情况:手上一共有七八个 Agent 服务,有的是跑在服务端的 QA 助手,有的是内部知识库问答机器人,还有的是给运营部门用的文案生成工具。以前大家各管各的,每个 Agent 里都直接配置各自的模型供应商、各自的 API Key、各自的超时和重试逻辑,看起来井井有条,实际上隐患一大堆。
第一件事让我下决心重构的,是某天供应商 A 的接口突然限流,生产环境里两个 Agent 同时报错,业务方在群里连环问。我去查日志才发现,这两个服务用的同一个上游供应商账号,但各自代码里各写各的重试策略,一个重试 3 次,一个重试 5 次,直接把限流阈值打爆了。如果说这是偶发,那后面还有更大的一次事故:模型供应商要升级模型版本,旧模型要下架,我一个个服务去改配置、重新发布,改了六个服务还不够,发现有个实验性 Agent 直接写死了旧模型名,没人记得它在哪。
就是这些经历让我意识到,AI Agent 的模型管理不是一个单纯的技术选型问题,而是一个基础设施问题。你再也不想每个 Agent 都自己维护供应商连接、模型映射、密钥管理、额度追踪这一整套。所以我把方案定成了:本地部署一个 AI 网关,所有 Agent 只认这一个入口,由网关统一管理上游模型供应商和模型路由。
网关这类组件在非 AI 领域很常见,比如 API 网关之于微服务。但在 AI 场景里它有个独特价值:它不只是转发请求,还要理解模型的对话结构、流式响应、Token 计费这些概念。做一个 AI 网关,本质是把模型供应商的差异挡在外面,把模型管理的复杂度收敛到一处。
这个方案你可以用到任何你觉得自己 Agent 集群开始变乱的地方。不需要多大规模,两三个 Agent 加上多个模型供应商就会开始受益。适合的人群很明确:自己搭 Agent 集群的开发者、团队里需要统一模型入口和密钥管理的人、以及每个月要为模型成本对账头疼的人。
2. 本地 AI 网关要动哪些核心零件:统一协议、模型路由与密钥托管
2.1 统一协议层:为什么模型供应商都在“说”OpenAI 方言
网关要做的第一件事,是定协议。这是最枯燥但最关键的决策。
现在几乎所有主流的模型供应商和自托管方案,都默认兼容 OpenAI 格式的接口。即使不是原生兼容,也会提供兼容层。因此本地网关向上游发请求的时候,用 OpenAI 格式作为统一协议,是当前最稳妥务实的选择。
你的 Agent 只需要处理一种协议:对话补全接口、流式响应、Token 用量字段、错误结构,全部按 OpenAI 格式来理解。网关接收到 Agent 请求之后,会根据路由规则找到实际的那个上游模型供应商,把请求翻译成该供应商的原生格式(如果它有),或者继续用 OpenAI 协议发过去。
这样做有一个非常大的好处:Agent 服务的代码里不再需要依赖特定供应商的 SDK,切换模型供应商只和网关配置有关。我在遇到模型版本升级、供应商临时故障、新模型灰度测试这些场景时,都是在网关侧做调整,Agent 侧什么也不用改。
不过要注意的是,并不存在绝对的“完美兼容”。比如不同供应商的流式响应里,增量内容的字段名可能不同,非流式响应里 finish_reason 的取值也可能有细微差别。网关的作用就是把这层差异消化掉,给你的 Agent 呈现一份稳定、不会变的接口契约。
2.2 模型路由与供应商适配:你的模型地图
模型路由是整个网关的核心决策单元。它负责回答一个问题:Agent 请求里的模型名,到底应该发给哪个真实的上游供应商的哪个实际模型。
这里有一个几乎所有人都会走弯路的概念:Agent 请求里写的“模型名”,不一定是真实模型名,而应当是一个逻辑模型名。什么意思呢?我称之为模型映射。
我在网关里定义了一套逻辑模型名,比如:
fast-chat映射到供应商 A 的轻量对话模型reasoning-pro映射到供应商 B 的深度推理模型embedding-default映射到自托管向量模型的别名
这样带来的灵活性是巨大的。某个逻辑模型对应的实际供应商模型如果涨价或者不稳定,我只需要在网关配置里把它重新指到另一个供应商的模型上,所有调用这个逻辑名的 Agent 都自动切换。这和你当年用 Nginx 做反向代理时,把 upstream 改掉、前端无感知,是同一个思路。
路由策略可以按实际情况做得粗或细。我的初始设计只用了两层:
- 第一层是模型名映射,确定逻辑模型对应哪些真实模型
- 第二层是供应商优先级,决定多个真实模型时优先发给谁
这是最小可用配置,但它已经能解决绝大部分问题。后面如果你遇到不同 Agent 需要不同模型配额的需求,还会引出更高级的路由,比如按 API Key 分组限流,这个我会在后面展开。
2.3 密钥托管与令牌体系:不让 Key 在代码里裸奔
以前的每个 Agent 客户端,各自保存一份供应商 Key。Key 一旦泄露,影响面是一整个供应商账号,而且很难追溯到底是哪个服务漏的。那时候排查起来非常痛苦,每次疑似泄露都要所有服务一起轮换密钥。
网关引入令牌体系之后,事情变得可控了:Agent 不再接触上游供应商的 Key,它只拿一个网关签发的令牌(Token)。网关把令牌与具体上游 Key 绑定,并且可以给每个令牌配置可用的模型范围、速率限制、额度上限。
这张表格是我在内部文档里画的,基本说明了模型密钥托管的关键区别:
| 维度 | 直接使用供应商 Key | 网关令牌方案 |
|---|---|---|
| 泄露影响 | 整个账号失守,需全量轮换 | 单个令牌可单独禁用,不影响其他 |
| 密钥数量 | 每个 Agent 至少一份 | 大部分 Agent 一份令牌,密钥集中在网关 |
| 权限粒度 | 通常只有账号级权限 | 可按令牌控制模型、额度、速率 |
| 审计与追溯 | 需要到供应商后台逐个查 | 网关侧统一日志即可 |
| 轮换成本 | 所有使用方同步修改并重新部署 | 只改网关配置,Agent 无感 |
实际操作上,我给每个 Agent 分配了独立令牌,比如agent-qa、agent-knowledge、agent-copywriting。某天某个 Agent 异常消耗 Token,我可以直接看网关的用量报表,定位到是哪个令牌,然后在网关把它的速率限制调低、甚至临时禁用。这个能力在成本爆炸的时候就是救命稻草。
3. 从零搭一个能上线的网关:开源选型、部署流程与关键配置
3.1 开源网关选型:为什么我选了这套
做网关这件事,我不太建议一开始就自己从零写,除非你只是学习目的。社区里已经有一批成熟的本地部署 OpenAI 格式网关项目,比如兼容 OpenAI API 协议、支持多模型接入、自动重试、渠道负载均衡、Token 配额管理、可视化看板这些能力都有。选择它的理由也很简单:它解决了我前面提到的大部分问题,包括密钥托管、模型路由、用量统计、令牌限额。
如果你有更复杂的企业级需求,也可以考虑自己包一层业务网关,在开源网关外面再加上权限审批、预算审批、内部审计对接这些能力。但底层的模型供应商适配、请求转发、重试机制,没必要重复造轮子。
我选型时核心看的是这几条:
- 是否支持 OpenAI 协议,可以统一暴露给 Agent
- 是否支持多供应商、多渠道的配置与管理
- 是否带令牌体系和限额功能,便于给不同 Agent 分配权限
- 是否有用量、日志、费用统计能力
- 是否支持 Docker 部署,便于快速搭建和迁移
按这些标准筛下来,我选了一个成熟开源网关项目,大概是所有条件都满足的那一个。社区里很多人在用,踩坑的人多也意味着文档和 issue 沉淀多,遇到问题不会没地方查。
3.2 Docker 部署与初始配置:一条命令跑起来
部署非常快,我当时是用 Docker Compose 直接跑的。核心配置大概长这样:
version: '3.8' services: ai-gateway: image: ai-gateway-image:v0.6.0 container_name: ai-gateway restart: always ports: - "3000:3000" environment: - TZ=Asia/Shanghai - SQL_DSN=root:password@tcp(mysql:3306)/gateway_db - REDIS_CONN_STRING=redis://redis:6379 volumes: - ./data:/data depends_on: - mysql - redis mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=gateway_db volumes: - mysql_data:/var/lib/mysql redis: image: redis:7-alpine restart: always这里有两个细节值得单独拿出来提醒。
数据库和 Redis 是必须要有的。我当时想省事,先只用 SQLite,结果跑了两周之后发现日志查询和报表统计越来越慢,会话记录一多就卡。后面果断切到 MySQL,查询速度和稳定性都明显提升。所以如果打算长期用,一开始就上 MySQL 加 Redis,不要走弯路。
端口方面,我暴露在局域网内的固定端口,没有直接映射到公网。本地网关的定位就是内部服务,前面如果再套一层 Nginx 做 TLS 终结和访问控制,会更稳妥。我在生产环境是在网关前面加了 Nginx,只允许内网访问,并且做了 Basic Auth,因为网关控制台里能看到所有上游密钥,安全性不能马虎。
3.3 给 Agent 发令牌:配额、限速与容错
部署好之后,有一段配置过程特别重要,我称之为“初始化三件事”:
第一件,添加渠道。把你要用的每一个上游供应商都作为一个渠道配进去,每个渠道填上它的 Base URL、真实的 API Key、支持的模型列表、以及权重。权重可以用来做负载均衡,同一供应商可以配多个渠道,权重按能力分配。
第二件,添加模型映射。把逻辑模型名和真实模型对应起来。比如:
渠道:供应商A 模型:claude-xxx -> 逻辑名: fast-chat 权重:1渠道:供应商B 模型:gpt-xxx -> 逻辑名: fast-chat 权重:1这样同一个逻辑模型名fast-chat就有两个实际渠道可选,路由器会按权重分发。我在绝大部分情况下都是这么配的,一个逻辑模型配多个渠道,天然实现了高可用。
第三件,创建令牌。给每个 Agent 单独建一个令牌,然后配置它的模型访问范围和额度限制。我通常会设置一个比较宽松的分组限额,但也会给每个令牌设单日请求数上限,避免某个 Agent 的异常循环把预算烧光。
提示:初始化时最容易被忽略的是,上游渠道的模型名和 Agent 请求的模型名是两个体系。一定要先在网关里做模型映射,否则 Agent 请求一个逻辑名,会直接报“模型不存在”,很多人第一天都会卡在这。
跑起来之后我做了一个简单验证:拿命令行工具直接向网关发一个 OpenAI 格式的对话请求,确认响应正常、流式正常、Token 统计正常,然后把某一个 Agent 的 Base URL 改成网关地址,Key 换成网关令牌,验证它也能正常工作。这个验证通过后,基本上可以宣布网关正式接管家里的模型流量了。
4. 路由策略与故障转移:多供应商不是摆设,是保命符
4.1 权重与优先级:主备切换怎么配才不慌
在网关里,同一个逻辑模型后面挂着多个渠道时,路由调度策略就是生命线。大多数开源网关支持按权重轮询,也支持在某个渠道失败后自动切换到下一个渠道。我一开始理解得很浅,以为权重就是负载均衡,把两个供应商设成权重 1:1 就算高可用了。
后来我发现,事情没这么简单。如果两个供应商的模型能力、延迟、价格差别很大,简单的权重轮询会在模型能力要求高的场景(比如代码生成)上出现质量波动。所以我调整了思路:
- 默认场景:主供应商权重拉到 9,备供应商权重 1。优先走主供应商,但保留少量流量给备供应商做健康探测。
- 故障场景:主供应商连续失败次数超过阈值后,网关自动把所有流量切换到备供应商。因为备供应商一直有 10% 的流量在跑,它的连通性是有信心的,切换过去不会出现“备机从来没接过线上的包,一上来就挂”的尴尬局面。
这个策略特别适合那种平时不想因为备机闲置而心中没底、但又不想完全平均分配的场景。它兼顾了质量稳定和故障切换的可靠性。
另外我强烈建议配置模型重定向功能。比如某个供应商已经下线了旧模型,但还有 Agent 在调用旧名字,网关可以在不改 Agent 的情况下,把旧模型名重定向到新模型名。我换过一次模型版本,就是靠重定向平滑过渡的,整个过程没有任何 Agent 需要重新发布。
4.2 故障重试最容易踩的坑
重试机制听起来很简单:失败就重试。但真正做过的人才知道,这里处处是坑。
我碰到过的第一个坑是重试风暴。最初我把重试次数设成 5 次,超时设成 60 秒,结果某个供应商大面积故障时,所有 Agent 都卡在长超时加重试的循环里,网关的连接数直接被打满,连健康检查都慢下来了。这不是供应商的问题,是我自己的网关设计放大了故障。
总结下来,我现在的经验是:
- 单次超时别给太长,建议 30 秒到 60 秒之间,视模型情况而定。超过这个时间还在等,说明大概率有问题。
- 重试次数控制在 2 次以内。第一次失败后立刻切换到备用渠道,比在原渠道上硬重试更有效。
- 必须开启自动重试,但前提是重试时换一个渠道,而不是对同一个渠道反复尝试。
还有一个细节容易被忽略:对于流式请求,如果已经向外吐了一部分内容,中途上游断开,此时重试会造成用户看到重复内容。网关要做的是标记流式会话的状态,如果已经有过内容输出,就不再自动重试,而是向上抛错,由 Agent 侧决定是否重开一个会话。这个判断逻辑如果没做好,你会收到一堆“回复内容重复”的投诉。
最后是熔断机制。我现在会在网关里设置一个面板状态监控,当某个渠道连续出错超过一定次数时,把它标记为不可用,自动摘除流量。等它恢复稳定后再重新启用。这个和微服务里的熔断是一个模式,但放在 AI 网关里尤其有用,因为上游模型供应商的故障往往不是单点超时,而是整个账号限流或服务降级。
5. 用量审计与成本核算:月底对账终于不用靠猜
以前每个月初,我要登录各个供应商后台,把账单导出,再手动按照 Agent 去分摊成本。问题是多个 Agent 共用一个账号的时候,供应商后台只能看到总量,根本无法区分是谁消费的。说白了,全靠猜。
网关存在之后,用量和成本变成了一个内部账单问题,而不是一个供应商后台问题。
5.1 一次调用从发起到记账的完整链路
网关会在每次请求结束时拿到 Token 用量和费用信息。对于 OpenAI 格式的响应,这里面包含了输入 Token、输出 Token 和总 Token 数。把 Token 数乘以对应模型单价,就能得出单次调用成本。
我在网关的日志里观察到,它会把每次调用的模型、令牌归属、Token 数、请求耗时、是否成功都记录下来。这样每个 Agent 每月消耗多少、每天消耗多少、平均延迟多少,全都清晰可见。
这块的价值在日常运维里非常直观:某天成本曲线突然陡增,我可以按令牌和时间维度下钻,很快定位到是哪个 Agent、哪个时间点、因为什么任务导致的大额消耗。而不是像以前一样,只能看着账单金额干瞪眼。
5.2 成本与配额报表到底怎么落库
这里我给自己加了一道练习题:网关自带的日志只保留一段时间,但成本数据我得自己长期留存。所以我搭了一个定时任务,每天从网关的日志里把前一日的用量数据拉出来,按天落库,然后接入了自己的报表。
数据表长这个样子:
| 字段 | 作用 |
|---|---|
| date | 按天粒度聚合的日期 |
| token_name | Agent 令牌名 |
| model_name | 逻辑模型名 |
| tokens_prompt | 输入 Token 数 |
| tokens_completion | 输出 Token 数 |
| tokens_total | 总 Token 数 |
| cost_usd | 估算成本 |
| request_count | 调用次数 |
| avg_latency_ms | 平均响应耗时 |
这个表帮我发现了一个特别有价值的信息:Agent 的调用模型分布。原本我以为某些 Agent 用的全是大模型,结果发现很多简单查询其实用轻量模型就够了。我据此调整了部分 Agent 的模型路由,把日常查询切到便宜模型,深度推理才上贵模型,整体成本降了大约 30%。
注意:不同供应商的计费单位不完全一样,有的按 1K Token 计费,有的按 1M Token 计费。做成本汇总时一定要统一单位换算,否则报表里的成本会差几个数量级。
6. 自研薄网关 vs 开箱即用:什么时候该自己动手写
我前面大力安利了开源网关,但这不是说所有场景都必须用它。实际上我在不同项目里见过三种方案:直接用云端供应商网关、部署开源网关、自己写一层薄代理。三者各有定位。
6.1 自研薄代理的适用场景
如果你的需求极度简单,比如只有两三个 Agent、一个供应商,且未来一年内不太可能增加供应商,那自己写一个几十行代码的薄代理完全可行。它本质上就是一个反向代理,把收到请求里的模型名改一改,往上游转发。可以用任何语言实现,框架随便选。
我当时在自己测试环境里就写过这样一个代理,大概二百来行,功能包括:把逻辑模型名映射到真实模型名、从环境变量读取 Key 注入到上游请求、记录每次调用的 Token 数和耗时。够用,而且清晰。
但为什么生产环境我最终没有选薄代理?因为一旦你要加的东西超过两个,复杂度就上来了。你要处理多密钥轮换、多供应商映射、失败重试、限流熔断、用量报表、令牌管理…这些表面上看起来只是“功能点”,实际上每加一个功能,你重写一遍的工作量都以指数级增长。更麻烦的是,这些功能必须经过生产验证才算数,自研的稳定性评估周期很长。
6.2 现成网关覆盖不了的需求
开源网关也并非万能。我实际碰到过几个它盖不住的需求:
一种是深度绑定组织内部的流程,比如自动化审批某个 Agent 新增模型权限、按部门预算额度做分区管理。这类需求需要改业务逻辑,不只是改网关配置,那我就会在开源网关外面再包一层内部管理 API。
另一种是对数据安全有更高要求的场景。比如不允许任何日志落到第三方、不允许模型请求体经过任何非白名单链路。开源网关默认的信噪比和加解密策略未必能满足,需要二次开发。
还有一种我看到别人踩过的:某些网关的自动重试逻辑,在代理模式下会和内部负载均衡器产生冲突。如果你的网络环境里还有一层 Nginx 或 LB,请求失败重试时可能会重复读请求体,导致流式传输异常。这个问题解决起来需要至少一天时间。
我的总体建议是:现成网关能用就用,但要做好“开箱后用两周”的心理准备。前两周是用它踩坑最多的阶段,配置合不合理、路由策略要不要调整、日志哪些要美化,都会在这段时间暴露出来。两周之后再真正把所有 Agent 流量切全,风险会小很多。
7. 上线三个月后:我踩过的坑和性能调优记录
网关上线运行了三个月,总体稳定,但这期间也踩过一些真实的坑。记录下来,算是给同样在搭网关的人一些提前预警。
7.1 流式输出与网关超时的纠缠
第一个坑是流式输出的超时配置。Agent 走的是流式接口,模型生成内容的时候,不是一下子返回完,而是像打字机一样源源不断吐内容。如果你在上游请求上设置了非常短的超时时间,长文本生成任务就会频繁超时,因为整个请求的生命周期远超普通 HTTP 请求。
我那段时间接到不少“回答到一半就断了”的反馈,查日志发现全是网关层超时。关键是要区分两个超时概念:连接超时和读超时。对于流式接口,读超时应该比连接超时长得多,且最好是基于“两次数据块之间的空闲间隔”来判断,而不是从请求开始到结束的总时长。
我现在是把连接超时设为 10 秒,但流式读取的超时时间放宽到 300 秒。只要模型还在吐词,连接就一直保持。如果连续 30 秒没有任何数据块,才判定为卡死并断开。
7.2 并发控制与上游限流
第二个问题是上游限流。开源网关默认会在渠道层面做并发限制,但这个限制如果设置得太小,业务高峰时会先把自己限死,而不是被上游限流。
我一开始把并发设得比较保守,结果某天运营部门同时触发一批批量文案生成任务,网关拒绝了大量请求。后来我调整了思路:把并发限制调到实际上游供应商允许值的 80%,因为如果每个渠道只有 50% 的额度,高峰期容易误伤正常请求。
还有一个相关的点是流备切换。如果某个供应商的账号限流了,网关能不能自动把流量切到另一个供应商的渠道,这不只是“有备用渠道”就能解决的。我在配置重试时,明确指定了失败时切换到的目标渠道,否则默认情况下它会去混用权重,导致切流不彻底,流量还是会被限流拖住。
7.3 日志观测:别等出问题才想起打点
最后一个建议,早做日志打点。网关面板自带的日志,主要是给技术排查用的,字段比较原始。如果你希望看到“每个 Agent 每天调用了多少模型、花了多少钱、平均响应速度如何”这种报告,最好一开始就设计一条自己的日志管道。
我在网关日志的基础上,接出了一个结构化日志流,重点记录:请求时间、令牌名、逻辑模型名、真实渠道、输入输出 Token、耗时、成功失败标记、失败原因。本来以为这只是锦上添花,结果帮我提前发现了一个问题:有一个 Agent 在凌晨持续调用一个高成本模型,每天 2 小时,额度烧掉得非常快。后来排查出来是那个 Agent 的某个定时任务在批量重跑历史数据,而它的路由里没有限制模型范围。如果没有这套打点,我可能要到月底账单出来才发现。
日志管道不用做得很复杂。最简单的方案,就是从网关日志库定时扫增量,或者接入日志收集组件按字段解析。关键是你要留得住这些数据,并且能按令牌、按天、按模型去聚合。把这一点想明白,网关就不再只是一个转发工具,而成了你管理整个 AI 基础设施的中枢。
从我的实际体会来说,如果重来一次,我会更早做两件事:一是把令牌体系从一开始就分好,每新建一个 Agent 就先分配令牌而不是等它接入后再补;二是把成本报表的落库从第一天就开始,而不是等到月末对账时才想起来。这两件事都不难,但前置做好之后,整个 AI Agent 集群的运营会顺畅很多。