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