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