
简介在大模型应用快速落地的今天企业普遍面临多厂商API协议不统一、密钥分散、计费不透明等痛点。API网关作为微服务架构中的核心组件能够在接入层统一处理鉴权、限流、路由与监控这一原理同样适用于大模型调用场景。通过协议适配机制将OpenAI、Claude、DeepSeek、通义千问等异构供应商接口转换为标准格式结合Redis令牌桶限流、熔断降级、AES-GCM密钥加密存储和用量计量计费可以构建一套轻量级LLM API统一管理系统。文章完整展示了基于Java 17、Spring Boot 3、Redis和MySQL的实现细节涵盖从系统架构设计、核心模块编码到Docker Compose部署上线的全流程并给出了流式响应转发、连接池调优等真实踩坑经验适合企业统一模型接入和毕业设计参考。 最近在做一个统一管理大模型 API 的项目调研了一圈市面上的方案要么太重、要么只适配单一厂商最后决定自己动手实现一套 LLM API 统一管理系统。从项目立项、系统设计、源码编写到部署上线整个过程踩了不少坑今天把我的完整思路和核心代码实现整理出来分享给大家。这个项目不只是一个简单的 API 转发代理而是一套完整的管理体系统一协议转换、多厂商适配、密钥安全管控、限流熔断、计量计费、可视化监控、审计日志全部都有。源码和论文我都整理好了项目中使用到的设计模式、技术方案、关键配置本文都会给出具体实现细节。我写代码的工具这边用的是 Java 17 Spring Boot 3 Redis MySQL Vue3这些技术栈比较主流方便有基础的同学直接上手改造。如果你是刚开始接触大模型应用开发或者正在做毕设、公司内部想搭一套统一的模型网关这篇文章应该能帮到你。1. 为什么需要一套“统一管理”大模型 API1.1 大模型 API 扩散带来的真实痛点先说一个我实际工作中遇到的情况。公司内部有好几个业务团队算法团队接了 OpenAI 和 Claude后端团队接了 DeepSeek 和通义千问前端团队还自己注册了智谱的 key。发展到后来每一个团队的代码里都藏着半打 API key调用的协议五花八门OpenAI 用/v1/chat/completionsClaude 用/v1/messagesDeepSeek 兼容 OpenAI 但参数细节不完全相同通义千问又有一套自己的风格。最头疼的是下面几个问题密钥失控每个团队自己管 key什么时候过期了、有没有超预算、被谁拿去调用了完全不可控。项目代码仓库的.env文件里就躺着好几个生产环境 key。计费不透明月底财务拿过来一堆大模型账单根本分不清哪个业务线花得多、哪个页面调得太频繁甚至分不清哪部分是测试环境调的、哪部分是生产环境调的。切换厂商成本高今天 DeepSeek 的 API 不稳定想临时切到通义千问但因为各家协议不同代码要改好几处才能切过去改完还得回归测试。重复代码严重每个团队都自己封装了一套“对接大模型的 SDK”只是参数略有不同。后来我统计了一下全公司至少有 7 套类似的封装。1.2 这套系统要解决的核心问题所以我要做的这套 LLM API 统一管理系统核心目标很明确所有业务方不直接对接任何一家大模型厂商而是统一走我们自己的网关。业务方的代码里只出现一个 baseURL用标准协议发请求由网关做协议适配、流量调度、密钥管理和计量统计。这个思路跟微服务架构里的 API 网关是一样的把“鉴权、限流、路由、监控”这些横切关注点从业务代码里剥出来下沉到网关层统一处理。这样设计有几个明显的好处业务方接入成本极低统一协议后端只需要维护一套对接代码厂商切换只发生在网关层业务代码零改动所有密钥集中在网关侧加密存储从源头上消灭密钥散落的问题每一次调用都有日志、有计量、有审计成本归属一目了然2. 系统架构与核心模块设计2.1 整体分层思路整个系统的架构并不复杂但设计的时候我特意按照“控制面”和“数据面”分离的思路来组织。所谓控制面就是管理后台、配置中心、审计报表这些不直接参与请求转发的部分数据面则是真正处理 API 请求的网关核心链路。下面是系统分层的逻辑接入层面向业务方提供一个统一的 HTTP 入口兼容 OpenAI 风格的请求格式这样业务方几乎不需要修改代码就能接入。核心网关层包含路由分发、协议适配、鉴权认证、限流熔断、计量计费、审计日志等六大部分。这里就是整个系统的“大脑”和“调度中心”。存储层MySQL 存放用户、API Key、模型配置、调用日志等结构化数据Redis 存放限流计数器、令牌桶、分布式锁等实时性要求高的数据。控制台层Vue3 管理页面用于配置模型供应商、管理 API Key、查看调用监控、导出账单报表。这个分层借鉴了 API 网关的经典架构但又针对大模型场景做了专门的优化协议适配层是核心因为大模型厂商的协议实在太不统一了。2.2 核心模块划分与职责我画模块图的时候把整个系统拆成了下面这些模块每个模块的职责边界都比较清晰模块核心职责关键技术点路由分发根据请求参数决定转发到哪家厂商模型名到供应商映射、加权轮询协议适配各家厂商请求/响应格式统一转换适配器模式、SSE 流解析密钥管理存储和注入上游厂商 API KeyAES 加密 每次请求动态注入鉴权认证识别调用方身份、校验权限API Key 前缀模式 哈希校验限流熔断保护上游资源和下游稳定性Redis 令牌桶、滑动窗口熔断计量计费记录 token 用量、费用分摊token 校验与用量解析审计日志全链路调用留痕异步落库、日志采样系统管理用户管理、供应商管理、模型配置RBAC 权限模型2.3 技术选型的取舍我选型的时候有两个核心考量一是生态成熟度二是团队后续维护成本。后端选了 Java Spring Boot 3因为我的生产环境里已经有很多 Spring 基础设施运维工具链都是现成的。网关核心没有引入 Spring Cloud Gateway而是自己封装了一层基于 Servlet 的转发逻辑原因是我们的场景没有那么庞大的服务发现需求大模型 API 的转发本质上是 HTTP 调用不需要走 Service Mesh 那套。存储方面MySQL 存元数据和调用流水Redis 做实时计数和分布式限流。因为要对上游 key 做细粒度的缓存和防抖Redis 是刚需。前端控制台选了 Vue3 Element Plus这是目前国内使用率最高的中后台技术组合接手门槛低。3. 核心实现协议适配层如何做到“一次接入随处调用”协议适配是整个系统里技术含量最高的部分。不同大模型厂商的 API 差异很大我一开始接到一个需求“是不是只要把请求转发出去就行了”实际做起来才发现完全不是这么回事。3.1 统一 API 协议设计我定义了一套内部的“标准协议”所有请求进入网关后先转换成这个标准格式再交给适配器去转换成各家厂商的格式。核心请求模型长这样public class UnifiedChatRequest { private String requestId; // 全局唯一请求ID private String provider; // 指定供应商可选 private String model; // 模型名如 gpt-4o-mini / deepseek-chat private ListChatMessage messages; // 对话消息列表 private Double temperature; // 采样温度 private Integer maxTokens; // 最大输出 token 数 private Boolean stream; // 是否流式返回 private MapString, Object extraParams; // 各家特有参数透传 } public class ChatMessage { private String role; // system / user / assistant private String content; private String name; // 可选多轮对话时使用 }选择这个模型有两个关键考量第一它完全兼容 OpenAI 的请求格式这样从 OpenAI 切换过来的业务方基本零成本第二message 结构上留了name字段和extraParams可以承接各家特有参数。3.2 适配器模式的具体实现我用适配器模式把“标准协议”转换成各家协议。核心是一个接口public interface LLMProviderAdapter { String getProviderName(); UnifiedChatResponse chat(UnifiedChatRequest request); void chatStream(UnifiedChatRequest request, StreamCallbackUnifiedChatResponse callback); }每个厂商实现一个 Adapter 类例如OpenAIAdapter、DeepSeekAdapter、QwenAdapter、ClaudeAdapter。路由分发的时候根据请求里的模型名或指定的 provider从 Spring 容器里取出对应的 Bean 执行。这里最关键的一个设计细节是模型名到适配器的映射关系是数据驱动的存在 MySQL 表里而不是写死在代码里。这样运营人员可以在控制台上配置一个新的模型名deepseek-chat映射到 DeepSeek 供应商不需要改一行代码。数据库表设计如下CREATE TABLE llm_model_registry ( id bigint(20) NOT NULL AUTO_INCREMENT, model_name varchar(128) NOT NULL COMMENT 业务可见的模型名, provider_code varchar(64) NOT NULL COMMENT 供应商编码, upstream_model_name varchar(128) NOT NULL COMMENT 上游真实模型名, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 0-停用 1-启用, remark varchar(512) DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_model_name (model_name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这样设计的好处是当上游厂商把gpt-4o换成了gpt-4o-mini只需要在配置中心后台把upstream_model_name改掉业务方完全无感知。3.3 流式响应的处理细节流式接口是整个协议适配里最容易出 bug 的地方。OpenAI 的 SSE 流返回格式跟 Claude 的流返回格式完全不一样而且还有一个大坑业务方连接断开时网关必须能感知到并立即终止上游请求否则 token 费用会一直累计下去。我的实现方案是在转发层使用 OkHttp 的异步流式调用把上游的 SSE 字节流实时转发给下游。核心是一个 ResponseBodyCallbackprivate void forwardStream(okhttp3.Response upstreamResponse, HttpServletResponse downstreamResponse) throws IOException { downstreamResponse.setContentType(text/event-stream); downstreamResponse.setCharacterEncoding(UTF-8); downstreamResponse.setHeader(Cache-Control, no-cache); try (BufferedReader reader new BufferedReader( new InputStreamReader(upstreamResponse.body().byteStream(), StandardCharsets.UTF_8))) { String line; while ((line reader.readLine()) ! null) { if (downstreamResponse.getWriter().checkError()) { // 下游连接已断开立即终止 upstreamResponse.close(); break; } downstreamResponse.getWriter().write(line \n); downstreamResponse.getWriter().flush(); } } }这里有一个细节每一次 write 之后必须 flush否则下游客户端会一直等不到数据。而且用checkError()判断下游是否已经断开是一个性价比很高的做法比监听回调里的异常要可靠得多。4. 核心实现密钥管理、限流熔断与计量计费4.1 密钥安全存储与隔离密钥管理是整个系统的安全基石。上游厂商的 Key 如果明文存在数据库里一旦数据库泄露就是重大事故。我的方案是AES-GCM 加密后存储密钥从环境变量注入且应用配置文件里绝不出现明文 Key。Component public class SecretCipher { private static final String TRANSFORMATION AES/GCM/NoPadding; private final SecretKey secretKey; public SecretCipher(Value(${cipher.secret-key}) String base64Key) { byte[] keyBytes Base64.getDecoder().decode(base64Key); this.secretKey new SecretKeySpec(keyBytes, AES); } public String encrypt(String plainText) { try { Cipher cipher Cipher.getInstance(TRANSFORMATION); byte[] iv new byte[12]; SecureRandom random new SecureRandom(); random.nextBytes(iv); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, iv)); byte[] encrypted cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); // 把 iv 和密文拼接存储 ByteBuffer buffer ByteBuffer.allocate(iv.length encrypted.length); buffer.put(iv); buffer.put(encrypted); return Base64.getEncoder().encodeToString(buffer.array()); } catch (Exception e) { throw new RuntimeException(密钥加密失败, e); } } }网关发起上游调用时从数据库取出密文解密后再放入请求头。这里有一个性能优化点对解密结果做 10 分钟的本地缓存避免每一个请求都走一次 AES 解密因为解密本身还是有 CPU 开销的。密钥隔离也有讲究。我给每个上游供应商单独建一张密钥表每个供应商可以配置多个 Key网关发起请求时可以轮询使用。当一个 Key 因为余额不足或限流返回 401/429 时自动标记异常并切换到下一个 Key。4.2 限流策略与实现大模型 API 比普通 HTTP API 更需要限流因为一旦某个业务方代码出现死循环每分钟可能消耗上千元 token 费用。我的限流方案是双层限流第一层按 API Key 维度每个调用方每分钟最多 N 次请求第二层按模型维度每个上游模型全局每分钟最多 M 次请求实现用的 Redis 令牌桶。之所以用令牌桶而不是固定窗口是因为它可以允许一定程度的突发流量更贴近实际业务场景。Component public class RedisRateLimiter { Autowired private StringRedisTemplate redisTemplate; private static final String TOKEN_KEY_PREFIX rate:token:; private static final String TIME_KEY_PREFIX rate:time:; public boolean tryAcquire(String key, int capacity, int refillRate) { long now System.currentTimeMillis(); String tokenKey TOKEN_KEY_PREFIX key; String timeKey TIME_KEY_PREFIX key; // Lua 脚本保证原子性 String luaScript local token_key KEYS[1] local time_key KEYS[2] local now tonumber(ARGV[1]) local capacity tonumber(ARGV[2]) local refill_rate tonumber(ARGV[3]) local refill_interval tonumber(ARGV[4]) local current_tokens tonumber(redis.call(get, token_key) or capacity) local last_refill tonumber(redis.call(get, time_key) or now) local elapsed now - last_refill local refill_count math.floor(elapsed / refill_interval) if refill_count 0 then current_tokens math.min(capacity, current_tokens refill_count * refill_rate) redis.call(set, time_key, now) end if current_tokens 0 then redis.call(set, token_key, current_tokens - 1) return 1 else return 0 end ; Long result redisTemplate.execute( new DefaultRedisScript(luaScript, Long.class), Arrays.asList(tokenKey, timeKey), String.valueOf(now), String.valueOf(capacity), String.valueOf(refillRate), String.valueOf(1000) // 每秒补充一次 ); return Long.valueOf(1).equals(result); } }这个 Lua 脚本的妙处在于令牌补充逻辑和扣减逻辑在 Redis 端原子执行不会出现并发情况下多扣或少补的问题。4.3 熔断与重试策略上游大模型 API 有时候会突然不稳定返回 5xx 或响应超时。如果网关不做熔断保护所有请求都堆积在慢调用上很快整个系统都会被拖死。我的熔断器实现借鉴了 Hystrix 的三态模型关闭、打开、半开。public enum CircuitState { CLOSED, // 正常状态放行所有请求 OPEN, // 熔断状态直接拒绝请求 HALF_OPEN // 半开状态放行少量探测请求 }状态转换规则默认 CLOSED状态滑动窗口统计最近 60 秒内的失败率失败率超过阈值比如 50%且请求量超过最小请求数比如 20 次状态切换为 OPENOPEN 状态持续 30 秒期间所有请求快速失败直接返回 50330 秒后进入 HALF_OPEN放行 5 个探测请求全部成功则恢复 CLOSED否则回到 OPEN熔断器是每个上游供应商维度的代码里用ConcurrentHashMapString, CircuitBreaker保存避免一个模型故障拖累所有模型。重试策略我也做了很严格的约束只能对幂等请求重试且最多重试 1 次。对于流式请求如果已经向下游客户端输出了部分数据绝不能重试否则会产生内容错乱。4.4 计量计费的设计与实现计量计费开始时我本来想放在一个独立的日志消费模块里后来为了简化部署直接用了异步写库 定时汇总的方案。上游的响应里都会带 usage 字段里面包含prompt_tokens、completion_tokens、total_tokens三个值。网关把这个原始 JSON 透传给业务方的同时也同步解析并记录到数据库public class UsageRecord { private Long id; private String requestId; private String apiKeyId; // 哪个调用方 private String providerCode; // 哪个供应商 private String modelName; // 哪个模型 private Long promptTokens; private Long completionTokens; private Long totalTokens; private BigDecimal cost; // 计算出的费用 private LocalDateTime createTime; }费用计算是基于供应商配置的单价表。我建了一张provider_price表字段包括input_price_per_million、output_price_per_million单位为元/百万 token。计费时BigDecimal cost inputPrice.multiply(BigDecimal.valueOf(promptTokens)) .divide(BigDecimal.valueOf(1_000_000), 6, RoundingMode.HALF_UP) .add(outputPrice.multiply(BigDecimal.valueOf(completionTokens)) .divide(BigDecimal.valueOf(1_000_000), 6, RoundingMode.HALF_UP));这个方法虽然没有官方计价那么精确各家有时按缓存命中与否区分价格但对于按业务线做成本分摊完全够用。5. 控制台与可视化让 API 调用状态可观测一个管理系统的价值很大程度上取决于控制台做得是否好用。我没有把精力花在花哨的图表上而是优先保证“调用方能快速定位问题”。5.1 管理台功能设计控制台的核心页面有五个每个页面解决一类问题仪表盘展示今日总调用量、总 token 消耗、预估费用、成功率、P95 响应延迟。这些数据每 5 秒刷新一次方便运维盯大屏。调用日志按时间、调用方、模型、状态码筛选点开详情能看到完整的请求参数和响应内容支持一键复制 curl 命令复现问题。密钥管理创建/禁用/轮换业务方的 API Key支持设置 key 的预算上限和日调用次数上限。模型管理维护供应商、模型注册表、单价表配置模型开关。用量报表按天/按周/按月汇总每个调用方的费用和 token 消耗支持导出 Excel。5.2 数据看板的实现细节仪表盘的后端接口我用了两个手段保证性能调用日志和用量数据都做了预聚合每 5 分钟把明细记录汇总成一条call_stats_hourly记录大屏查询只查聚合表不直接扫明细表。仪表盘的接口都加了 Redis 缓存缓存时间 5 秒。对于大屏场景响应速度比实时性更重要。GetMapping(/api/dashboard/overview) public ResultDashboardOverviewVO overview() { String cacheKey dashboard:overview; DashboardOverviewVO vo redisTemplate.opsForValue().get(cacheKey); if (vo null) { vo buildOverview(); redisTemplate.opsForValue().set(cacheKey, vo, 5, TimeUnit.SECONDS); } return Result.success(vo); }另外一个比较重要的监控是上游供应商健康状态。我在系统里做了一套定时探测机制每 30 秒向各供应商发一个最小化的 chat 请求只请求 1 个 token如果连续失败 3 次就在控制台标红并发告警通知到群。6. 部署实践与踩坑记录系统开发完成之后部署到测试环境、压测、上生产这个过程中又踩了不少坑。我把一些非常有价值的经验整理出来。6.1 Docker Compose 一键部署项目的交付物里包含一套完整的docker-compose.yml启动之后就是一套可用的环境version: 3.8 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: llm_gateway volumes: - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql - mysql-data:/var/lib/mysql ports: - 3306:3306 redis: image: redis:7.0-alpine ports: - 6379:6379 volumes: - redis-data:/data backend: build: ./backend environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/llm_gateway?useUnicodetruecharacterEncodingutf8 SPRING_DATA_REDIS_HOST: redis CIPHER_SECRET_KEY: dGhpcy1pcy1hLXNlY3JldC1rZXktZm9yLWRlbW8 depends_on: - mysql - redis ports: - 8080:8080 frontend: build: ./frontend depends_on: - backend ports: - 80:80 volumes: mysql-data: redis-data:注意CIPHER_SECRET_KEY这个环境变量生产环境一定要用专门的密钥管理服务如 Vault来管理不能像 demo 环境这样硬编码。6.2 部署中遇到的经典问题问题一SSE 流式响应被 Nginx 缓冲前端调用流式接口时页面一直等不到数据几十秒后才一次性吐出全部内容。排查后发现是 Nginx 默认开启了 proxy_buffering把 SSE 流缓冲了。解决方法是在 Nginx 配置中关闭缓冲location /v1/ { proxy_pass http://backend:8080; proxy_buffering off; proxy_cache off; proxy_set_header Connection ; proxy_http_version 1.1; chunked_transfer_encoding on; proxy_read_timeout 300s; }问题二调用上游时连接池耗尽压测时发现 QPS 一高很多请求卡在获取连接上。原因是我直接用了 RestTemplate 默认连接池最大连接数只有 200。换成 OkHttp 连接池并调大配置后问题解决Bean public OkHttpClient okHttpClient() { Dispatcher dispatcher new Dispatcher(); dispatcher.setMaxRequests(500); dispatcher.setMaxRequestsPerHost(200); ConnectionPool pool new ConnectionPool(50, 30, TimeUnit.SECONDS); return new OkHttpClient.Builder() .dispatcher(dispatcher) .connectionPool(pool) .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(120, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build(); }这个 readTimeout 一定要设置得足够大因为大模型流式响应可能会持续几十秒甚至几分钟。问题三上游返回connection lost mid-response类错误我们调一些不稳定的上游接口时会出现响应已经发了一半突然断连的情况。这个问题的根因往往是上游的负载均衡超时配置太短或者上游在处理长请求时主动断开了连接。我在适配器层做了针对性的处理如果响应头已经写入但还没有完成捕获 IOException 后记录一条特殊的“半包日志”方便追查是哪家供应商在哪一段网络链路出的问题。6.3 压测数据与性能调优我拿了 4C8G 的单机部署做压测开启 200 并发压了 30 分钟结果如下指标数值峰值 QPS2100平均响应时间38msP99 响应时间92ms错误率0.02%CPU 平均值45%这个性能对于大部分中小型团队已经完全够用。性能瓶颈主要在于上游 API 的网络延迟网关自身转发的开销占比很小。7. 从源码到毕业论文的整理思路这套系统如果是用来做毕业设计的源码和论文的配套整理很关键。我建议论文按照“需求分析、系统设计、系统实现、系统测试”这四个大块组织跟源码模块一一对应评审老师读起来会很顺。7.1 论文整体架构建议我整理了论文技术部分的参考结构第一章 绪论写研究背景、国内外 API 网关和大模型应用的现状点出当前大模型 API 管理缺乏统一方案的痛点第二章 相关技术介绍介绍 LLM 基础概念、Spring Boot、Redis、Vue.js、适配器模式、令牌桶算法等让评委确认你技术选型有依据第三章 系统需求分析把功能性需求协议转换、密钥管理、计量计费、监控告警和非功能性需求性能、安全性、可用性分开描述第四章 系统设计给出架构图、功能模块图、数据库 ER 图、关键接口设计并用文字说明每个模块为什么这么设计第五章 系统实现按模块逐个展示关键代码片段配合截图展示实际运行效果第六章 系统测试包含功能测试用例设计、性能压测报告、结果分析7.2 从代码中提炼论文素材的技巧很多同学写完代码写论文的时候反而没素材。我的做法是每实现完一个功能模块就顺手写一篇开发笔记记录这个模块解决了什么问题、核心设计思想是什么、用了什么设计模式、测试数据如何。这样论文里的每一个实现章节都有真实内容和数据支撑而不是靠拼凑。比如协议适配这一章我就写了“为什么要用适配器模式而不是 if-else 判断”这个在论文答辩时也是很好的加分亮点。8. 系统测试与稳定性验证测试阶段我不仅写了单元测试还写了集成测试和端到端联调用例。这里说几个比较重要的测试方案。单元测试主要是对限流器、熔断器、加密工具类进行测试。熔断器状态流转的测试用例非常重要因为状态机逻辑很容易在边界情况出错Test void testCircuitBreakerOpenAndHalfOpen() { CircuitBreaker cb new CircuitBreaker(20, 0.5, 30000); // 模拟 20 个请求中 15 个失败 for (int i 0; i 20; i) { boolean success i 5; cb.recordResult(success); } assertTrue(cb.isOpen()); // 等待 30 秒进入半开状态 Thread.sleep(30000); assertTrue(cb.isHalfOpen()); // 连续 5 个探测请求成功熔断器关闭 for (int i 0; i 5; i) { cb.recordResult(true); } assertFalse(cb.isOpen()); }集成测试则是用 Testcontainers 起一个真实的 MySQL 和 Redis 容器验证整个请求链路是否通。这种方式比 Mock 更加真实能抓出很多环境依赖的坑。端到端联调时我在测试环境配了 3 家真实的大模型供应商把每个供应商的流式和非流式调用都跑了一遍。这个环节让我发现了很多只在真实网络环境下才会出现的问题比如某些供应商对stream_options参数的支持差异、不同供应商的 timeout 行为等。这套测试流程完整走下来系统的稳定性已经比较有保障。9. 改进方向与后续计划目前这套系统已经在我这边稳定运行了一段时间但离想象中的“完美”还有不少距离。我心里有几个后续改进的方向也分享给大家参考。一是引入语义缓存。对于相同或相似的请求可以复用之前的响应这个在典型的多轮客服场景里能省不少 token 费用。难点是缓存键的设计和相似度计算需要权衡命中率和内存消耗。二是增加A/B 测试和灰度发布capability。当上游厂商发布新模型时先让 5% 的流量走新模型观察效果后再全量切换。这样能在网关层实现模型迭代的平滑升级。三是引入动态路由策略。目前是根据模型名做静态路由未来可以做成基于价格、延迟、可用性的动态评分路由比如某厂商 API 延迟飙升时自动把流量切到其他厂商。四是完善多租户配额管理。给每个业务方设置独立的预算上限当消费金额超过阈值时自动告警甚至熔断防止预算超支。这些都还是设计思考阶段但方向已经比较明确。如果你也在做类似项目欢迎一起交流可以互相参考少走一些弯路。本文还有配套的精品资源点击获取