
簡介在大模型應用快速落地的今天企業普遍面臨多廠商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 延遲飆升時自動把流量切到其他廠商。四是完善多租戶配額管理。給每個業務方設置獨立的預算上限當消費金額超過閾值時自動告警甚至熔斷防止預算超支。這些都還是設計思考階段但方向已經比較明確。如果你也在做類似項目歡迎一起交流可以互相參考少走一些彎路。本文還有配套的精品資源點擊獲取