
Mistral 3 系列多模型路由Spring Boot 后端按請求復雜度動態選型的踩坑實錄項目背景我們團隊在 2026 年 6 月對核心 NLP 服務做了模型升級從原先單一接入 Mistral 7B 切換到了 Mistral 3 系列。業務場景是電商平臺的商品問答與智能客服日均調用量約 12 萬次。技術棧為 Spring Boot 3.2.5 JDK 17.0.12 OkHttp 4.12.0。團隊 6 人其中 2 人負責 AI 服務層。升級的初衷很直接Mistral 3 系列提供了多個尺寸的模型理論上簡單請求用輕量模型、復雜請求用大模型能顯著降低 API 調用成本。但實際落地后第一個月我們踩了一個很大的坑——成本不降反升。選型決策接入前我們對 Mistral 3 系列的可用模型做了調研。| 模型 | 參數量 | 適用場景 | 單次調用成本相對值 | 中文表現 ||------|--------|----------|----------------------|----------|| Mistral Small 3 | 24B | 文本分類、信息抽取、簡單問答 | 1x | 良好 || Mistral Medium 3 | 約 60B | 中等推理、代碼理解、多輪對話 | 3x | 優秀 || Mistral Large 3 | 未公開 | 復雜推理、長文本分析、多步任務 | 8x | 頂級 || Mistral 7B舊 | 7B | 基礎 NLP | 0.5x | 一般 |最初方案很簡單按輸入文本字符長度做路由——少于 100 字符走 Small 3100-500 走 Medium 3超過 500 走 Large 3。這個方案雖然官方推薦文檔里也提到了類似思路但在我們場景下反而更糟。上線兩周后我們發現客服對話中有大量「短輸入高復雜度」的查詢比如「這個商品和上一個有什么區別」——只有十幾個字但需要模型理解上下文并做對比推理。用 Small 3 處理這類請求回答準確率從 94% 掉到了 71%。實現過程問題定位我們從日志里拉了 5 天的調用數據做分析。核心發現60% 的請求是簡單的商品屬性查詢「多少錢」「有沒有貨」用 Small 3 完全夠用25% 是中等復雜度對比、推薦、解釋需要 Medium 315% 是復雜推理多步分析、代碼相關、長文本總結必須用 Large 3但按字符長度路由時這 25% 的中等請求里有近一半被錯誤地路由到了 Small 3導致回答質量下降用戶投訴率上升了 3 個百分點。真正的根因是輸入長度和任務復雜度之間沒有強相關性。一個 10 字的「為什么這個不能用」和一個 200 字的「請幫我列出這個商品的所有參數」前者反而需要更強的推理能力。解決方案兩階段路由我們改用了兩階段路由策略第一階段所有請求先經過一個輕量級的分類器用 Small 3 本身做判斷任務復雜度等級。第二階段根據分類結果路由到對應尺寸的模型。核心實現如下javaServicepublic class MistralRouterService {Autowiredprivate MistralClient mistralClient;Value(${mistral.models.small:open-mistral-small-3})private String smallModel;Value(${mistral.models.medium:open-mistral-medium-3})private String mediumModel;Value(${mistral.models.large:open-mistral-large-3})private String largeModel;public MistralResponse routeRequest(UserQuery query) {// 第一階段用 Small 3 做復雜度分類ComplexityLevel level classifyComplexity(query);// 第二階段根據分類結果選擇模型String targetModel resolveModel(level);return mistralClient.chat(query.getPrompt(), targetModel, buildConfig(level));}private ComplexityLevel classifyComplexity(UserQuery query) {String classifyPrompt String.format(判斷以下用戶查詢的復雜度等級只返回 SIMPLE、MEDIUM 或 COMPLEX\n\n%s,query.getContent());try {MistralResponse response mistralClient.chat(classifyPrompt, smallModel, ClassificationConfig.builder().temperature(0.1).maxTokens(10).build());String result response.getContent().trim().toUpperCase();return ComplexityLevel.valueOf(result);} catch (Exception e) {// 分類失敗時降級為 MEDIUM避免影響主流程log.warn(Complexity classification failed, fallback to MEDIUM, e);return ComplexityLevel.MEDIUM;}}private String resolveModel(ComplexityLevel level) {return switch (level) {case SIMPLE - smallModel;case MEDIUM - mediumModel;case COMPLEX - largeModel;};}}分類器的 System Prompt 我們也專門調過最初讓模型輸出 JSON 格式但發現約 2% 的請求會返回帶 markdown 代碼塊的 JSON導致解析失敗。后來改成只要求輸出一個純文本標簽反而更穩定。路由層還加了一個兜底機制如果目標模型調用超時或返回錯誤自動降級到下一檔模型重試一次。yamlmistral:routing:classification-timeout-ms: 3000fallback-enabled: truemax-fallback-levels: 1circuit-breaker:failure-threshold: 5recovery-timeout-seconds: 30這里有個值得注意的點熔斷器的閾值我們設了 5 次失敗才觸發而不是常見的 3 次。原因是分類階段本身就可能因為網絡波動偶爾失敗閾值設太低會導致不必要的熔斷反而增加 Large 3 的調用量。效果數據兩階段路由上線后運行 3 周的數據對比API 調用總成本下降 58%從日均約 2400 元降到 1008 元用戶滿意度評分從 4.2 回升到 4.55 分制P99 響應時間從 4.8s 降到 3.1s因為大量簡單請求走 Small 3推理更快分類器額外引入的延遲約 200-400ms但整體 P99 仍然改善因為省去了 Large 3 的排隊等待從模型調用分布看路由后的實際比例是 Small 3 占 62%、Medium 3 占 28%、Large 3 占 10%和我們的預期基本吻合。感悟如果重來一次會在兩個地方做得更好。第一分類器不應該和主請求串行執行。理想方案是異步預分類——用戶消息到達時立即啟動分類同時準備 Small 3 的默認響應。分類結果回來后如果判定為 COMPLEX 才切換到 Large 3否則直接用 Small 3 的結果。這樣可以把分類開銷完全隱藏掉。第二分類的準確率需要持續監控。我們上線后發現分類器對「否定句」的識別偏弱比如「這個商品有什么不好」容易被判為 SIMPLE但實際用戶期望的是分析缺點屬于 MEDIUM 甚至 COMPLEX。后來我們在分類 prompt 里加了一條針對否定句的顯式規則準確率才回到可接受水平。大模型路由不是做一次就完事的它需要和業務數據持續對齊。#后端 #Java #SpringBoot #Mistral #大模型路由你在實際項目中有遇到類似問題嗎歡迎在評論區分享你的經驗和解決方案。