師的 AI 工程化落地(一):當(dāng) Java 微服務(wù)開始「思考」——把大模型裝進 Spring Cloud 的第一堂課)
這是一個寫給 Java 架構(gòu)師的連載專欄。我們不談煉丹、不講 Transformer 原理只回答一個問題手上這套跑了多年的 Spring Cloud怎么穩(wěn)穩(wěn)當(dāng)當(dāng)?shù)匕汛竽P陀闷饋怼⒂玫缴a(chǎn)里。全篇按順序推進今天是第一堂課給微服務(wù)裝上「大腦」的最小閉環(huán)。〇、先說清楚這個系列要帶你做什么過去兩年我見過太多團隊把 AI 用成了「高級玩具」某個后端同學(xué)在 Controller 里偷偷塞了一段 HTTP 調(diào)用大模型的代碼Demo 效果驚艷然后呢API Key 散落在三四個服務(wù)里、高峰期一次調(diào)用 40 秒拖垮線程池、賬單月底超支三倍、模型偶爾胡說八道還被客戶截圖投訴。問題不在大模型而在沒有人用架構(gòu)師的方式對待它。這個系列一共十篇路線是這樣的服務(wù)接入(本篇) → RAG 知識庫 → Function Calling 工具調(diào)用 → 多模型路由與成本 → 穩(wěn)定性治理 → 可觀測性 → 智能體編排 → 安全 → 企業(yè)級 AI 中臺全景跟著走完你會得到一套能直接搬進公司項目的工程化方案。準(zhǔn)備好的話上課。一、心智轉(zhuǎn)換大模型是一個「又貴、又慢、還會犯錯」的服務(wù)架構(gòu)師的第一課永遠不是寫代碼而是給新東西定性。請先把對大模型的三個錯誤幻想扔掉幻覺現(xiàn)實它是無所不知的大腦它是一個按 token 計費的外部 HTTP 服務(wù)它很快像查 Redis同步調(diào)用秒級起步長文本 10s必須按高延遲依賴設(shè)計它說的都對它會一本正經(jīng)地編造幻覺輸出只能當(dāng)「建議」不能當(dāng)「事實」定性之后結(jié)論就清晰了大模型在你的架構(gòu)圖里和 MySQL、Redis、支付接口一樣是一個被依賴的下游資源——只不過它貴、慢、不穩(wěn)定且返回的是自然語言。你過去積累的所有微服務(wù)治理經(jīng)驗超時、熔斷、隔離、降級、監(jiān)控、成本核算對它全部適用只是參數(shù)要重新標(biāo)定。這是整個系列的基石后面每一篇都是在這張「定性表」上做展開。二、架構(gòu)定位AI 能力必須收斂成一個獨立服務(wù)最忌諱的做法是讓訂單、客服、內(nèi)容三個微服務(wù)各自直連大模型。三周后你一定會收獲三套 Key、三套超時配置、三份無法合并的 token 賬單以及一次「模型供應(yīng)商漲價全團隊加班改代碼」的慘痛經(jīng)歷。正確姿勢是新增一個基礎(chǔ)設(shè)施類服務(wù)ai-service┌─────────┐ ┌─────────┐ ┌─────────┐ │order-svc│ │ticket-svc│ │content-svc│ 業(yè)務(wù)服務(wù)保持純粹 └────┬────┘ └────┬────┘ └────┬────┘ └───────────┼───────────┘ Feign / HTTP ▼ ┌─────────────────┐ │ ai-service │ 統(tǒng)一密鑰/限流/路由/記賬/降級 │ (Spring AI) │ └────────┬────────┘ ▼ ┌──────────┬──────────┐ LLM 廠商 向量庫 內(nèi)部工具(Function Calling)它的職責(zé)邊界也很明確只做五件事統(tǒng)一持有各家大模型的密鑰與配置對內(nèi)暴露領(lǐng)域化接口總結(jié)、抽取、問答、分類而不是裸的/chat統(tǒng)一做超時、熔斷、限流與成本統(tǒng)計屏蔽底層模型差異——今天用 A 廠明天換 B 廠業(yè)務(wù)方零感知后續(xù)承載 RAG 知識庫與工具調(diào)用本系列第 2~4 篇會逐步往里加。技術(shù)選型上Java 生態(tài)目前就兩個主流選擇Spring AI 與 LangChain4j。我們整個系列統(tǒng)一用Spring AI1.0 GA 版本理由很簡單你團隊已經(jīng)會 Spring Boot自動裝配、yaml 配置、Micrometer 監(jiān)控全是現(xiàn)成的學(xué)習(xí)成本最低這對要在團隊里推動落地的架構(gòu)師來說是決定性因素。三、最小閉環(huán)30 分鐘跑通第一個對話接口環(huán)境要求JDK 17、Spring Boot 3.2、Spring AI 1.0.x。注意這是硬性門檻Spring AI 不支持 JDK 8還在 JDK 8 的團隊需要先規(guī)劃升級路徑這也是架構(gòu)師要提前向團隊說明的成本。3.1 引入依賴與配置dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency國內(nèi)團隊不想折騰網(wǎng)絡(luò)可以直接用兼容 OpenAI 協(xié)議的國產(chǎn)模型只改地址即可spring: ai: openai: api-key: ${LLM_API_KEY} # 密鑰走環(huán)境變量嚴禁提交到 Git base-url: ${LLM_BASE_URL:https://api.openai.com} chat: options: model: deepseek-chat temperature: 0.3 # 業(yè)務(wù)場景默認壓低減少胡言亂語3.2 用 ChatClient 而不是 ChatModelSpring AI 有兩套 API。ChatModel是底層原語ChatClient是帶 System 預(yù)設(shè)、支持流式的 fluent API——業(yè)務(wù)代碼一律用后者Service public class AiChatService { private final ChatClient chatClient; // 構(gòu)造時設(shè)定「人設(shè)」所有對話共享統(tǒng)一的系統(tǒng)提示詞 public AiChatService(ChatClient.Builder builder) { this.chatClient builder .defaultSystem( 你是企業(yè)內(nèi)部技術(shù)助手回答必須 1. 基于用戶提供的信息不確定就明說禁止編造 2. 先給結(jié)論再給不超過三點理由 3. 涉及操作步驟時給出可執(zhí)行命令。 ) .build(); } /** 同步問答適合后臺批處理類場景 */ public String ask(String question) { return chatClient.prompt() .user(question) .call() .content(); } /** 流式問答面向前端交互token 逐個返回首字延遲從 10s 降到 1s 內(nèi) */ public FluxString askStream(String question) { return chatClient.prompt() .user(question) .stream() .content(); } }3.3 暴露 SSE 接口并扛住網(wǎng)關(guān)這一關(guān)流式是 AI 應(yīng)用體驗的分水嶺用 WebFlux 輸出 SSERestController RequestMapping(/api/ai) public class AiChatController { private final AiChatService aiChatService; public AiChatController(AiChatService aiChatService) { this.aiChatService aiChatService; } GetMapping(value /chat, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString chat(RequestParam String q) { return aiChatService.askStream(q); } }到這里代碼能跑了但架構(gòu)師的工作才剛開始——這個接口一旦經(jīng)過 Nginx/Spring Cloud Gateway大概率會出現(xiàn)「轉(zhuǎn)圈十秒答案瞬間全部吐出」的詭異現(xiàn)象。原因是響應(yīng)緩沖。兩處必須改Nginx 層關(guān)閉緩沖location /api/ai/ { proxy_pass http://ai-service/; proxy_buffering off; proxy_read_timeout 120s; add_header X-Accel-Buffering no; }GatewayWebFlux 版本身是響應(yīng)式透傳不會緩沖但要記得把全局超時調(diào)到大于模型最長響應(yīng)時間并對 SSE 路徑關(guān)閉重試——重試一個流式接口用戶會收到兩遍答案token 也扣兩遍錢。用 curl 驗證curl -N http://localhost:8080/api/ai/chat?q微服務(wù)里如何設(shè)計超時看到文字逐字蹦出來最小閉環(huán)就完成了業(yè)務(wù)服務(wù) → ai-service → 大模型 → SSE 回前端。四、第一堂課的作業(yè)兩個必須現(xiàn)在就想清楚的問題我不給玩具代碼當(dāng)終點留兩個生產(chǎn)環(huán)境必答題你可以在評論區(qū)寫下你的方案第 5、6 篇我會給出完整實現(xiàn)線程池怎么隔離ai-service 里一個 40 秒不返回的模型調(diào)用會不會把 Tomcat 工作線程占滿拖垮同進程的其他接口提示信號量隔離、響應(yīng)式棧、超時預(yù)算三選一或組合。用戶看到「服務(wù)繁忙」時怎么辦模型超時或限流后前端不能一直轉(zhuǎn)圈。降級策略是返回固定話術(shù)、轉(zhuǎn)人工還是切換到更小更快的備用模型這兩個問題想不明白AI 功能就只能停在內(nèi)網(wǎng) Demo 階段——它們正是本系列中段穩(wěn)定性治理篇的核心內(nèi)容。五、本講小結(jié)與下講預(yù)告今天我們只做了一件事但它是后面所有內(nèi)容的地基把大模型定性為一個貴、慢、會犯錯的外部服務(wù)并用一個獨立的 ai-service 把它收斂進 Spring Cloud 體系最后跑通了同步與流式兩個接口。下一篇我們進入真正讓 AI「懂業(yè)務(wù)」的關(guān)鍵技術(shù)——RAG檢索增強生成為什么把公司文檔直接塞給大模型是死路文檔怎么切片、怎么生成 Embedding、Redis 和 Milvus 到底怎么選我們下周四晚同一時間動手搭一個能回答內(nèi)部知識庫問題的問答服務(wù)。系列導(dǎo)航一服務(wù)接入 · 本篇 下一篇二RAG 落地上——文檔切片、Embedding 與向量庫選型如果這個系列對你有幫助點個關(guān)注每周更新不掉隊。運行環(huán)境說明本文代碼基于 JDK 17 Spring Boot 3.3 Spring AI 1.0.x 實測國產(chǎn)兼容模型可直接運行。