級AI應(yīng)用底座實戰(zhàn):微服務(wù)架構(gòu)與Spring Cloud選型指南)
1. 從一個真實困境說起為什么能跑起來的AI Demo和能上線的AI應(yīng)用之間隔著一道鴻溝過去一年多我參與過好幾個企業(yè)內(nèi)部的AI落地項目從智能客服、文檔問答到工單自動分類幾乎每一個項目都經(jīng)歷過同樣的劇本第一周搭出一個Demo效果驚艷老板拍板就按這個方向做第二周開始接入真實業(yè)務(wù)系統(tǒng)問題像潮水一樣涌出來——模型調(diào)用超時怎么重試、多租戶的密鑰怎么隔離、對話上下文存在哪里、限流怎么做、灰度怎么發(fā)、日志怎么追、成本怎么核算。原本以為是個調(diào)個API的活兒最后變成了一個標準的分布式系統(tǒng)工程。這就是AI 應(yīng)用底座這個概念出現(xiàn)的現(xiàn)實土壤。QuickBlue 正是圍繞這個痛點在做的事情它不是一個模型也不是一個聊天界面而是一層位于業(yè)務(wù)應(yīng)用和大模型能力之間的基礎(chǔ)設(shè)施。你可以把它理解成AI 應(yīng)用的操作系統(tǒng)底座——業(yè)務(wù)方只管寫提示詞和業(yè)務(wù)邏輯剩下的模型路由、會話管理、權(quán)限隔離、流量治理、可觀測性全部由底座兜住。這篇文章我想聊清楚三件事QuickBlue 這類 AI 應(yīng)用底座到底解決了什么問題它背后的技術(shù)選型為什么大概率會落在微服務(wù)、Spring Cloud、JDK 21 這條線上以及如果你要自己搭一個類似的底座哪些坑是必須提前知道的。文章會涉及不少微服務(wù)架構(gòu)、服務(wù)治理、配置管理的內(nèi)容適合有一定后端基礎(chǔ)、正在做或準備做企業(yè)級 AI 應(yīng)用的工程師和架構(gòu)師參考。如果你只是想知道QuickBlue 是什么看完第一節(jié)和第二節(jié)基本就夠了如果你想動手復(fù)現(xiàn)后面幾節(jié)的選型和踩坑經(jīng)驗會更值錢。2. QuickBlue 到底是個什么東西拆開AI 應(yīng)用底座這層殼2.1 底座不是中間件而是能力收斂層很多人第一次聽到AI 應(yīng)用底座會下意識地把它歸類成某種中間件比如消息隊列或者網(wǎng)關(guān)。這個理解不算錯但不夠準確。中間件通常解決的是單一維度的通用問題而 AI 應(yīng)用底座解決的是AI 應(yīng)用這一類系統(tǒng)共有的、跨維度的重復(fù)建設(shè)問題。我習(xí)慣用一個類比蓋住宅樓的時候地基、承重墻、水電管網(wǎng)是每一棟樓都要有的但你不會每蓋一棟樓就重新發(fā)明一次混凝土。AI 應(yīng)用底座就是AI應(yīng)用領(lǐng)域的地基管網(wǎng)——它把模型接入、會話狀態(tài)、鑒權(quán)限流、審計計費這些每家公司都要做一遍的事情做成一套可復(fù)用的標準能力。QuickBlue 的定位就在這兒。它向上給業(yè)務(wù)應(yīng)用提供統(tǒng)一的 SDK 和 API向下屏蔽不同模型供應(yīng)商的差異。業(yè)務(wù)方調(diào)用的是發(fā)一條消息給某個智能體而不是調(diào)用某廠商的某個版本的某個接口。這個抽象層看起來簡單但它帶來的價值是巨大的換模型不用改業(yè)務(wù)代碼加限流不用每個應(yīng)用自己寫做審計不用每個團隊各自埋點。2.2 一個 AI 應(yīng)用底座至少要收斂哪幾類能力我把這類底座的核心能力拆成五層從下往上說模型接入層統(tǒng)一封裝多家模型服務(wù)的調(diào)用協(xié)議處理鑒權(quán)、重試、超時、降級、流式響應(yīng)。這一層的關(guān)鍵是適配器模式每家供應(yīng)商一個 adapter上層只認統(tǒng)一接口。會話與上下文層管理多輪對話的上下文包括短期記憶當前會話窗口和長期記憶向量檢索。這一層要解決上下文裁剪、token 預(yù)算、會話隔離的問題。治理層限流、熔斷、灰度、路由。AI 應(yīng)用的流量特征和傳統(tǒng) Web 差別很大——單次請求耗時長、token 消耗是核心成本指標、突發(fā)流量容易打爆下游模型配額所以治理策略要專門設(shè)計??捎^測層鏈路追蹤、token 計量、成本歸因、效果評估。沒有這一層你根本不知道錢花在哪、哪個智能體在拖后腿。應(yīng)用編排層把提示詞、工具調(diào)用、知識庫檢索編排成可配置的工作流讓業(yè)務(wù)方不寫代碼也能調(diào)整 AI 行為。QuickBlue 這類產(chǎn)品的競爭力本質(zhì)上就是這五層收斂得夠不夠干凈、擴展點留得夠不夠合理。收斂得太死業(yè)務(wù)方覺得束手束腳收斂得太松又退化成什么都得自己寫底座就失去意義了。2.3 為什么企業(yè)需要這四個字是關(guān)鍵詞個人開發(fā)者做 AI 應(yīng)用一個腳本、一個 API Key 就夠了根本不需要底座。底座的價值只有在企業(yè)這個語境下才成立原因有三個第一是規(guī)模。當你有幾十個業(yè)務(wù)線、上百個智能體、每天百萬級調(diào)用的時候散落各處的 API Key、各自實現(xiàn)的限流、五花八門的日志格式會變成運維噩夢。底座的價值在于把復(fù)雜度集中到一處管理。第二是合規(guī)與安全。企業(yè)里數(shù)據(jù)不能隨便出域調(diào)用要留痕權(quán)限要分級敏感內(nèi)容要過濾。這些要求如果讓每個業(yè)務(wù)團隊自己實現(xiàn)幾乎不可能保證一致性。底座是唯一能統(tǒng)一落實這些策略的地方。第三是成本。大模型調(diào)用是真金白銀token 就是錢。沒有統(tǒng)一的計量和歸因你連哪個部門這個月花了多少都說不清。底座把成本可視化做出來才能談優(yōu)化。所以企業(yè)需要一個 AI 應(yīng)用底座這句話翻譯過來就是當 AI 應(yīng)用從個人玩具變成企業(yè)生產(chǎn)系統(tǒng)的時候重復(fù)建設(shè)、安全合規(guī)、成本失控這三個問題會同時爆發(fā)而底座是應(yīng)對它們的系統(tǒng)性答案。3. 技術(shù)選型背后的邏輯為什么是微服務(wù)、Spring Cloud 和 JDK 213.1 微服務(wù)不是趕時髦而是被 AI 負載的異構(gòu)性逼出來的有人會問一個 AI 底座用單體架構(gòu)不行嗎早期確實可以但很快會撞墻。原因在于 AI 應(yīng)用底座內(nèi)部各模塊的負載特征差異極大。模型接入層是 IO 密集型大量時間在等下游響應(yīng)需要高并發(fā)連接會話層是有狀態(tài)服務(wù)涉及會話粘性和存儲訪問治理層是計算密集型限流熔斷的判定要低延遲可觀測層是寫密集型海量埋點數(shù)據(jù)要吞吐。把這四種特征完全不同的模塊塞進一個進程資源配比會非常別扭——你給 IO 密集的模塊配的線程池對計算密集的模塊就是浪費。微服務(wù)化之后每個模塊可以獨立擴縮容、獨立選型、獨立發(fā)布。模型接入層可以橫向擴到幾十個實例扛并發(fā)治理層保持少量實例保證低延遲可觀測層單獨用高吞吐的存儲。這就是微服務(wù)拆分在 AI 底座場景下的真實動機——不是為了架構(gòu)圖好看而是因為負載異構(gòu)。3.2 Spring Cloud 生態(tài)的取舍停更傳聞下的現(xiàn)實選擇聊到 Spring Cloud繞不開一個熱搜詞spring cloud alibaba 停更了。這個說法其實需要澄清——準確地說是部分組件的維護節(jié)奏發(fā)生了變化社區(qū)活躍度有起伏但整個 Spring Cloud 生態(tài)并沒有死。企業(yè)選型時真正要做的是把哪些組件可以放心用、哪些要準備替代方案想清楚。我的經(jīng)驗是分三類處理組件類別典型組件選型建議核心穩(wěn)定類Spring Cloud Gateway、OpenFeign、LoadBalancer放心用社區(qū)成熟替代成本高治理增強類Sentinel、Nacos可用但關(guān)注維護狀態(tài)做好版本鎖定易變類各類配置中心、注冊中心的具體實現(xiàn)抽象接口保留替換空間關(guān)鍵原則是在底座里對治理組件做一層薄封裝業(yè)務(wù)代碼只依賴自己定義的接口底層用 Sentinel 還是別的實現(xiàn)通過配置切換。這樣即使某個組件真的停更替換成本也被限制在封裝層內(nèi)部不會波及業(yè)務(wù)。3.3 JDK 21 帶來的實打?qū)嵤找嫣摂M線程改變了 IO 密集服務(wù)的寫法JDK 21 是 LTS 版本對 AI 應(yīng)用底座來說最大的禮物是虛擬線程Virtual Threads。前面說過模型接入層是典型的 IO 密集型——一個請求大部分時間在等模型返回。傳統(tǒng)寫法要么用大量平臺線程內(nèi)存吃不消要么用響應(yīng)式編程心智負擔重、調(diào)試困難。虛擬線程把這個問題基本解決了。你可以用最樸素的一個請求一個線程的同步寫法卻能支撐極高的并發(fā)因為虛擬線程在阻塞時會讓出底層載體線程。實測下來同樣的模型接入服務(wù)從平臺線程池切到虛擬線程在保持相同吞吐的前提下代碼復(fù)雜度大幅下降線程池調(diào)優(yōu)那套東西基本可以扔掉了。// JDK 21 虛擬線程執(zhí)行器用于模型調(diào)用這類 IO 密集任務(wù) try (var executor Executors.newVirtualThreadPerTaskExecutor()) { FutureModelResponse future executor.submit(() - modelClient.invoke(request)); // 同步等待寫法簡單但底層不會阻塞平臺線程 return future.get(30, TimeUnit.SECONDS); }這段代碼的價值在于它看起來像十年前的同步代碼但并發(fā)能力接近響應(yīng)式。對于團隊里大部分工程師來說可維護性比炫技重要得多。3.4 一個務(wù)實的底座技術(shù)棧組合綜合下來如果要落地一個 QuickBlue 這樣的底座我會推薦這樣一套組合運行時JDK 21充分利用虛擬線程和記錄類Record簡化 DTO??蚣躍pring Boot 3.x Spring Cloud網(wǎng)關(guān)用 Gateway服務(wù)調(diào)用用 OpenFeign。注冊與配置Nacos 或 Consul接口層做抽象。治理Sentinel 做限流熔斷注意數(shù)據(jù)源可以接 Redis 集群做集群限流。存儲會話用 Redis向量用專用向量庫計量數(shù)據(jù)用時序庫或列存??捎^測OpenTelemetry 統(tǒng)一埋點鏈路追蹤 指標 日志三件套。這套組合不是唯一解但它的每個選擇都有明確的理由而不是別人都用所以我也用。4. 自己動手搭一個最小可用底座從拆分到跑通的關(guān)鍵步驟4.1 服務(wù)拆分先想清楚邊界再動手寫代碼微服務(wù)拆分最容易犯的錯是按技術(shù)分層拆——把 Controller 拆一個服務(wù)、Service 拆一個服務(wù)。這是災(zāi)難。正確的拆法是按業(yè)務(wù)能力和數(shù)據(jù)所有權(quán)拆。對 AI 應(yīng)用底座我建議的最小拆分是這樣的gateway-service統(tǒng)一入口負責鑒權(quán)、路由、基礎(chǔ)限流。model-adapter-service模型接入封裝各家模型調(diào)用。session-service會話與上下文管理。governance-service治理策略的配置與下發(fā)。observability-service埋點收集、計量、成本歸因。拆分的判斷標準是如果兩個模塊的數(shù)據(jù)生命周期和擴縮容需求高度一致就不要拆。比如治理策略的配置和下發(fā)如果量不大完全可以并進 gateway。拆分不是越細越好每多一個服務(wù)就多一份運維成本和網(wǎng)絡(luò)開銷。4.2 用 Nacos 做配置中心時最容易忽略的命名空間隔離配置管理這塊我踩過最深的坑是命名空間namespace的使用。很多團隊上手就把所有配置堆在 public 命名空間開發(fā)、測試、生產(chǎn)環(huán)境靠 dataId 后綴區(qū)分。短期沒問題一旦服務(wù)多起來配置就徹底亂了。正確做法是按環(huán)境劃分命名空間按服務(wù)劃分 group按功能劃分 dataId。三層結(jié)構(gòu)各司其職# Nacos 配置定位示例 namespace: prod-env # 環(huán)境隔離 group: model-adapter # 服務(wù)/模塊隔離 dataId: model-adapter.yaml # 具體配置文件這樣做的直接好處是切換環(huán)境只需要改一個 namespace 參數(shù)權(quán)限控制可以按 namespace 授予不同環(huán)境的配置物理隔離不會出現(xiàn)測試環(huán)境誤讀生產(chǎn)配置的事故。這個細節(jié)看起來小但在多環(huán)境多團隊協(xié)作時能省掉大量溝通成本。4.3 模型接入層的適配器設(shè)計把變化關(guān)進籠子模型接入層是整個底座里變化最頻繁的部分——供應(yīng)商接口在變、模型版本在變、計費方式在變。設(shè)計這一層的核心思想是依賴倒置上層依賴抽象底層實現(xiàn)可插拔。public interface ModelProvider { String name(); ModelResponse invoke(ModelRequest request); FluxString stream(ModelRequest request); // 流式響應(yīng) } // 每個供應(yīng)商一個實現(xiàn)通過 SPI 或 Spring 的 ConditionalOnProperty 裝配 Component ConditionalOnProperty(name provider.type, havingValue vendorA) public class VendorAProvider implements ModelProvider { // 具體實現(xiàn) }這樣設(shè)計之后新增一個供應(yīng)商只需要加一個實現(xiàn)類不改任何上層代碼。更重要的是重試、超時、降級這些橫切邏輯可以統(tǒng)一放在適配器外層用裝飾器模式包一層所有供應(yīng)商共享同一套容錯策略。4.4 會話上下文管理token 預(yù)算才是真正的約束會話管理看起來簡單——存?zhèn)€對話歷史而已。但真正做起來核心約束是token 預(yù)算。模型的上下文窗口是有限的對話輪次一多歷史就會超限。你需要一套裁剪策略。我的實踐是三級策略滑動窗口保留最近 N 輪完整對話這是最基礎(chǔ)的。摘要壓縮超出窗口的早期對話用模型壓縮成摘要保留關(guān)鍵信息。關(guān)鍵信息抽取把用戶明確表達的偏好、約束比如我用中文預(yù)算不超過X抽成結(jié)構(gòu)化字段永久保留。這三級的優(yōu)先級從低到高token 緊張時先砍滑動窗口再砍摘要最后才動關(guān)鍵信息。實測下來這套策略能把長對話的 token 消耗壓到原來的三分之一左右同時基本不損失體驗。4.5 用 Sentinel 做集群限流時 Redis 數(shù)據(jù)源的配置要點單機限流用 Sentinel 很簡單但 AI 底座通常需要集群限流——因為模型配額是全公司共享的單機限流會導(dǎo)致總量失控。集群限流需要把統(tǒng)計信息集中存儲Redis 是常見選擇。配置時有兩個點必須注意。第一是Redis 集群模式下 Sentinel 數(shù)據(jù)源的 key 前綴要統(tǒng)一規(guī)劃避免和其他業(yè)務(wù)沖突第二是限流規(guī)則的推送要走配置中心不能硬編碼在代碼里否則調(diào)整閾值要重新發(fā)版。// 集群限流數(shù)據(jù)源配置示意 Bean public SentinelRedisDataSource redisDataSource(RedisConnectionFactory factory) { SentinelRedisDataSource ds new SentinelRedisDataSource(); ds.setRedisConnectionFactory(factory); ds.setKeyPrefix(quickblue:sentinel:); // 統(tǒng)一前綴避免沖突 return ds; }注意集群限流的 Redis 一旦不可用限流會退化成單機模式甚至失效所以 Redis 本身要做高可用并且要有降級預(yù)案——比如 Redis 掛掉時切換到本地限流兜底寧可限得不準也不能完全不限。5. 上線之后才會暴露的問題幾個真實踩坑記錄5.1 流式響應(yīng)和網(wǎng)關(guān)超時的沖突第一個坑來自流式響應(yīng)。模型返回是流式的SSE但網(wǎng)關(guān)默認有超時時間。如果網(wǎng)關(guān)超時設(shè)得短長回答會被截斷設(shè)得長又會占用連接資源。更麻煩的是很多網(wǎng)關(guān)的限流是基于請求數(shù)的而流式請求的一個請求可能持續(xù)幾十秒實際資源占用遠超普通請求。解決辦法是對流式接口單獨配置路由和超時策略并且限流維度從請求數(shù)改成并發(fā)連接數(shù)。這個調(diào)整不做高峰期會出現(xiàn)大量流式請求把連接池占滿、普通請求被餓死的情況。5.2 上下文串號一個隱蔽但致命的問題第二個坑更隱蔽。會話隔離如果只靠 sessionId在異步、重試、多實例場景下很容易串號。我遇到過的情況是用戶 A 的對話歷史被拼進了用戶 B 的請求里原因是重試時用了錯誤的上下文引用。根因在于上下文對象的傳遞沒有做到不可變和顯式傳遞。修復(fù)方案是把上下文封裝成不可變對象隨請求一路顯式傳遞禁止用 ThreadLocal 存會話狀態(tài)——虛擬線程場景下 ThreadLocal 的行為和平臺線程不同更容易出問題。5.3 成本歸因做晚了等于沒做第三個坑是成本。我們一開始沒做細粒度的 token 計量等到月底賬單出來才發(fā)現(xiàn)某個智能體的調(diào)用量是預(yù)期的十倍?;仡^去查日志里只有請求量沒有 token 量根本定位不到問題。教訓(xùn)是計量埋點必須和功能一起上線不能等。每個模型調(diào)用都要記錄輸入 token、輸出 token、耗時、調(diào)用方標識。這些數(shù)據(jù)攢起來才能做成本歸因和優(yōu)化。晚做一個月就少一個月的數(shù)據(jù)優(yōu)化就無從談起。5.4 灰度發(fā)布在 AI 場景下的特殊性傳統(tǒng)灰度是按流量比例切。但 AI 應(yīng)用的效果不是二元的新版本提示詞可能在某些輸入上更好、某些更差。所以灰度不能只看流量比例還要對比效果指標——比如人工評分、用戶反饋、任務(wù)完成率。我的做法是給灰度流量打標把效果指標按版本維度聚合達到統(tǒng)計顯著性再決定是否全量。這套東西比傳統(tǒng)灰度復(fù)雜但AI應(yīng)用不做效果對比的灰度本質(zhì)上是在賭博。6. 如果你要選型或自建我的幾條實在建議聊了這么多技術(shù)和踩坑最后說幾條選型層面的實在話。第一先想清楚你是用底座還是造底座。如果公司只有一兩個 AI 應(yīng)用直接用現(xiàn)成的云服務(wù)或者輕量框架就夠了自建底座是過度工程。只有當 AI 應(yīng)用數(shù)量上到一定規(guī)模、且對安全合規(guī)成本有硬要求時自建才劃算。QuickBlue 這類產(chǎn)品的目標客戶是后者。第二底座的擴展點比功能列表更重要。選型時別只看它現(xiàn)在支持多少家模型、多少種功能要看它的擴展機制是否清晰——加一個模型供應(yīng)商要改多少代碼加一個治理策略要不要動核心。擴展點設(shè)計得好的底座能陪你走三年設(shè)計得差的半年就得推倒重來。第三把可觀測性當成一等公民。一個沒有完善計量和追蹤的 AI 底座等于一個沒有儀表盤的飛機。功能可以慢慢加但可觀測性必須從第一天就有。第四技術(shù)棧選穩(wěn)定的別追新。JDK 21 是 LTSSpring Cloud 是成熟生態(tài)這些選擇的價值在于出問題時有大量資料和社區(qū)支持。AI 領(lǐng)域本身變化已經(jīng)夠快了底座這層要盡量穩(wěn)。我個人在實際操作中的體會是AI 應(yīng)用底座這件事技術(shù)難度其實沒有想象中高難的是克制——克制住把所有東西都塞進去的沖動克制住追新技術(shù)的沖動克制住過早優(yōu)化的沖動。把模型接入、會話管理、治理、可觀測這四件事做扎實一個底座就已經(jīng)能撐起企業(yè)大部分 AI 應(yīng)用場景了。剩下的交給業(yè)務(wù)方去發(fā)揮。