Spring AI工具已經(jīng)調(diào)用成功,為什么最終回答仍為空?返回值、循環(huán)與上下文完整排查
文章摘要有些Spring AI項(xiàng)目可以在日志中看到工具已經(jīng)被調(diào)用數(shù)據(jù)庫查詢或HTTP請求也成功執(zhí)行但客戶端最終收到空字符串、模型重復(fù)調(diào)用同一工具或者回答完全沒有使用工具結(jié)果。這類問題與“模型沒有選擇工具”不同通常發(fā)生在工具返回值序列化、異常處理、Tool Calling循環(huán)、流式事件拼接、結(jié)果過長、消息持久化和終止條件等環(huán)節(jié)。本文給出從工具執(zhí)行結(jié)果到最終Assistant回答的完整排查路徑。一、先把鏈路分成五個(gè)階段一個(gè)完整工具調(diào)用不是只有“方法執(zhí)行成功”模型選擇工具 → 參數(shù)解析 → 工具執(zhí)行 → 結(jié)果寫入Tool Response → 模型基于結(jié)果生成最終回答日志只顯示orderService.query()執(zhí)行成功只能證明第三階段完成。后面仍可能失敗返回對象無法序列化Tool Response為空結(jié)果沒有進(jìn)入下一輪模型請求模型再次調(diào)用工具流式客戶端漏掉最終事件上下文超限Advisor提前返回最終回答被安全策略攔截。二、工具不要返回null錯(cuò)誤實(shí)現(xiàn)Tool(description查詢訂單)publicOrderResultqueryOrder(StringorderId){returnrepository.find(orderId).orElse(null);}工具返回null時(shí)模型可能只看到一個(gè)空結(jié)果無法區(qū)分訂單不存在 系統(tǒng)異常 沒有權(quán)限 返回值丟失推薦結(jié)構(gòu)化返回publicrecordToolResultT(booleansuccess,Stringcode,Stringmessage,Tdata){publicstaticTToolResultTsuccess(Tdata){returnnewToolResult(true,OK,執(zhí)行成功,data);}publicstaticTToolResultTfailure(Stringcode,Stringmessage){returnnewToolResult(false,code,message,null);}}不存在時(shí)返回{success:false,code:ORDER_NOT_FOUND,message:訂單不存在,data:null}三、不要直接返回?cái)?shù)據(jù)庫Entity數(shù)據(jù)庫實(shí)體可能包含Hibernate代理懶加載集合雙向關(guān)系循環(huán)引用內(nèi)部字段敏感字段超大關(guān)聯(lián)對象。例如Order → Customer → Orders → Customer → ……序列化可能失敗或生成巨大結(jié)果。推薦返回專用DTOpublicrecordOrderSummary(StringorderId,Stringstatus,BigDecimalamount,Stringcurrency,InstantupdatedAt){}只返回模型完成任務(wù)真正需要的字段。四、返回值是否被異常轉(zhuǎn)換成字符串一些工具為了“方便”這樣寫catch(Exceptionexception){returnexception.getMessage();}模型會把錯(cuò)誤字符串當(dāng)成正常業(yè)務(wù)結(jié)果。更危險(xiǎn)的寫法return查詢完成;但沒有返回真實(shí)數(shù)據(jù)模型無法回答用戶問題。推薦區(qū)分業(yè)務(wù)成功 業(yè)務(wù)失敗 技術(shù)異常 權(quán)限拒絕 等待確認(rèn)每類都使用穩(wěn)定錯(cuò)誤碼。五、檢查工具結(jié)果的實(shí)際序列化內(nèi)容不要只打印Java對象log.info(result{},result);還應(yīng)在安全脫敏后檢查發(fā)送給模型的內(nèi)容tool_result_json result_size_bytes serialization_status可以在測試環(huán)境中顯式序列化StringjsonobjectMapper.writeValueAsString(result);檢查是否為合法JSON是否包含所需字段是否出現(xiàn)空對象{}是否被截?cái)嗍欠癜舾行畔⑹欠翊蟮綗o法進(jìn)入上下文。六、工具結(jié)果過長會發(fā)生什么如果工具返回5000條數(shù)據(jù)庫記錄 整個(gè)日志文件 完整網(wǎng)頁HTML 幾十萬字文檔下一輪模型請求可能超過上下文窗口被Provider拒絕成本驟增模型忽略關(guān)鍵信息最終回答變空流式連接超時(shí)。工具應(yīng)該返回摘要 分頁信息 少量關(guān)鍵記錄 可繼續(xù)查詢的游標(biāo)例如{total:2387,returned:20,nextCursor:eyJwYWdlIjoyfQ,items:[]}七、Tool Calling循環(huán)是否繼續(xù)進(jìn)入下一輪Spring AI 2.0通過ToolCallingAdvisor執(zhí)行循環(huán)模型請求工具 → 執(zhí)行工具 → 把結(jié)果加入對話 → 再次調(diào)用模型 → 得到最終回答如果自動Tool Advisor被關(guān)閉AdvisorParams.toolCallingAdvisorAutoRegister(false)應(yīng)用必須自己完成后續(xù)循環(huán)。否則你只能拿到工具調(diào)用請求或工具執(zhí)行結(jié)果卻沒有最終自然語言回答。八、是否錯(cuò)誤地注冊了多個(gè)ToolAdvisor一個(gè)調(diào)用鏈中不應(yīng)該同時(shí)存在多個(gè)負(fù)責(zé)工具執(zhí)行循環(huán)的Advisor。重復(fù)注冊可能造成工具執(zhí)行兩次對話歷史重復(fù)循環(huán)順序混亂最終消息被覆蓋冪等沖突。檢查ChatClient自動注冊的ToolCallingAdvisor 自定義ToolCallingAdvisor ToolSearchToolCallingAdvisor應(yīng)該只有一個(gè)工具循環(huán)策略。九、模型為什么重復(fù)調(diào)用同一個(gè)工具常見原因1. 結(jié)果不包含完成信號返回{status:PROCESSING}模型可能繼續(xù)查詢。2. 工具描述暗示需要再次確認(rèn)3. 返回值缺少用戶要求的字段用戶問物流單號工具只返回訂單狀態(tài)。4. Tool Response沒有進(jìn)入下一輪上下文5. Prompt要求“直到確認(rèn)成功為止”6. 工具調(diào)用失敗卻被包裝為成功建議在結(jié)果中加入terminal retryable nextAction例如{success:true,terminal:true,retryable:false,data:{trackingNo:SF123456}}十、必須為副作用工具設(shè)置冪等鍵如果重復(fù)調(diào)用的是創(chuàng)建訂單退款發(fā)郵件修改權(quán)限提交審批發(fā)布內(nèi)容后果可能很嚴(yán)重。冪等鍵建議由業(yè)務(wù)系統(tǒng)生成或驗(yàn)證tenant_id user_id conversation_id tool_name business_request_id示例StringidempotencyKeyString.join(:,tenantId,conversationId,cancel_order,orderId);數(shù)據(jù)庫建立唯一約束不能只依賴內(nèi)存緩存。十一、流式接口是否漏掉最終事件流式工具調(diào)用可能包含模型文本增量 工具參數(shù)增量 工具調(diào)用開始 工具結(jié)果 下一輪模型文本 完成事件如果前端只處理第一類文本事件工具執(zhí)行后生成的第二輪回答可能被忽略。檢查SSE事件類型是否在工具輪次后繼續(xù)訂閱是否過早調(diào)用takeUntil是否收到CompleteNginx是否斷開長連接客戶端是否因空Chunk判定結(jié)束取消信號是否傳播到上游。十二、Memory位置是否導(dǎo)致工具消息丟失MessageChatMemoryAdvisor放在Tool Calling循環(huán)外部時(shí)通常只持久化最終用戶消息和Assistant消息。如果業(yè)務(wù)需要完整工具軌跡必須確認(rèn)所用Memory Repository支持AI Tool Call RequestTool Response Message多輪工具消息。否則工具結(jié)果可能在當(dāng)前請求可用但下一輪對話無法恢復(fù)。不要為了保存工具消息盲目把Memory Advisor移入循環(huán)。還要同時(shí)處理重復(fù)寫入Repository序列化能力上下文膨脹敏感參數(shù)存儲。十三、最終回答是否被其他Advisor改變調(diào)用鏈可能還有內(nèi)容審核輸出過濾結(jié)構(gòu)化輸出驗(yàn)證緩存日志自定義響應(yīng)轉(zhuǎn)換。工具執(zhí)行成功后最終回答可能被安全策略阻斷Schema校驗(yàn)反復(fù)重試緩存返回舊空結(jié)果自定義Advisor提前替換響應(yīng)轉(zhuǎn)換器解析失敗。建議記錄每個(gè)Advisor的enter exit order duration response_present十四、最終回答為空時(shí)的最小實(shí)驗(yàn)第一步固定工具返回值Tool(description返回測試訂單)publicOrderSummarytestOrder(){returnnewOrderSummary(A1001,SHIPPED,newBigDecimal(99.00),CNY,Instant.now());}第二步要求模型必須復(fù)述字段調(diào)用testOrder并返回orderId和status。第三步關(guān)閉其他Advisor只保留Tool Calling。第四步分別測試call與stream如果同步正常、流式失敗重點(diǎn)檢查事件消費(fèi)。第五步查看第二輪模型請求確認(rèn)Tool Response是否真的進(jìn)入上下文。十五、建議記錄的觀測字段tool_call_id tool_name arguments_hash execution_status execution_duration_ms result_serialization_status result_size_bytes tool_result_hash loop_iteration model_after_tool_called final_response_present stream_completed advisor_chain高風(fēng)險(xiǎn)業(yè)務(wù)還應(yīng)記錄idempotency_key approval_id operator business_result_id十六、完整排查清單□ 工具沒有返回null □ 返回的是DTO而不是數(shù)據(jù)庫Entity □ 結(jié)果可以穩(wěn)定序列化 □ 錯(cuò)誤沒有被偽裝成成功字符串 □ 結(jié)果大小受到限制 □ ToolCallingAdvisor完成了第二輪模型調(diào)用 □ 沒有重復(fù)注冊ToolAdvisor □ 結(jié)果包含terminal與retryable語義 □ 副作用工具使用數(shù)據(jù)庫級冪等 □ 流式客戶端沒有漏掉工具后的回答 □ Memory與工具消息能力匹配 □ 其他Advisor沒有替換最終響應(yīng) □ Trace中可以看到工具結(jié)果進(jìn)入下一輪模型請求總結(jié)“工具調(diào)用成功但最終回答為空”說明問題已經(jīng)越過工具選擇階段應(yīng)該重點(diǎn)檢查返回值序列化 → Tool Response寫入 → Tool Calling下一輪 → 流式事件消費(fèi) → 最終Advisor處理只有把工具調(diào)用拆成完整階段并逐段觀測才能判斷結(jié)果究竟丟在了哪里。

相關(guān)新聞

麒麟Linux系統(tǒng)安裝配置MongoDB 6.0全攻略:從倉庫適配到安全部署

麒麟Linux系統(tǒng)安裝配置MongoDB 6.0全攻略:從倉庫適配到安全部署

1. 項(xiàng)目緣起:為什么要在麒麟Linux上折騰MongoDB?最近接手了一個(gè)新項(xiàng)目,后端數(shù)據(jù)模型變動頻繁,傳統(tǒng)的關(guān)系型數(shù)據(jù)庫在頻繁修改表結(jié)構(gòu)時(shí)顯得有點(diǎn)力不從心。團(tuán)隊(duì)討論后,決定引入文檔型數(shù)據(jù)庫MongoDB來應(yīng)對這種靈活多變的場…

2026/7/29 13:56:45 閱讀更多
春節(jié)遷徙背后的經(jīng)濟(jì)學(xué)邏輯與城鄉(xiāng)決策分析

春節(jié)遷徙背后的經(jīng)濟(jì)學(xué)邏輯與城鄉(xiāng)決策分析

1. 春節(jié)遷徙現(xiàn)象的經(jīng)濟(jì)學(xué)觀察 每年春節(jié)前后,中國大地上都會上演一場規(guī)模空前的"人類大遷徙"。作為一名長期關(guān)注城鄉(xiāng)經(jīng)濟(jì)的研究者,我注意到這個(gè)現(xiàn)象背后蘊(yùn)含著深刻的經(jīng)濟(jì)邏輯。2023年春運(yùn)期間,全國鐵路發(fā)送旅客達(dá)3.48億人次&#xf…

2026/7/29 13:56:45 閱讀更多
多孔介質(zhì)模型在催化器仿真中的應(yīng)用:從達(dá)西定律到化學(xué)反應(yīng)耦合

多孔介質(zhì)模型在催化器仿真中的應(yīng)用:從達(dá)西定律到化學(xué)反應(yīng)耦合

1. 項(xiàng)目概述:當(dāng)流體穿過催化器時(shí)發(fā)生了什么?催化器,無論是汽車尾氣凈化用的三元催化器,還是化工生產(chǎn)中的固定床反應(yīng)器,其內(nèi)部都不是空蕩蕩的管道。里面填滿了密密麻麻、布滿微小孔道的陶瓷或金屬載體,這些載…

2026/7/29 13:56:45 閱讀更多
從C語言文件管理系統(tǒng)到Linux裝NAS:開發(fā)者的自建存儲之路

從C語言文件管理系統(tǒng)到Linux裝NAS:開發(fā)者的自建存儲之路

開發(fā)者論壇里的一次討論 “用易語言寫個(gè)內(nèi)網(wǎng)穿透軟件難不難?”這是某開發(fā)者社區(qū)里一個(gè)常見問題?;卮饏^(qū)里的思路大致分兩派:一派認(rèn)為易語言上手快,做個(gè)簡單的端口映射工具并不復(fù)雜;另一派則提醒,穩(wěn)定的內(nèi)網(wǎng)穿透涉及NAT…

2026/7/29 14:57:16 閱讀更多
Matlab實(shí)現(xiàn)電動車充電負(fù)荷優(yōu)化與削峰填谷策略

Matlab實(shí)現(xiàn)電動車充電負(fù)荷優(yōu)化與削峰填谷策略

1. 項(xiàng)目背景與核心價(jià)值 去年參與某充電站運(yùn)營項(xiàng)目時(shí),我親眼目睹了晚高峰時(shí)段變壓器過載跳閘的窘境。當(dāng)30輛電動車同時(shí)開啟快充,630kVA的配電設(shè)備在持續(xù)報(bào)警15分鐘后徹底罷工。這個(gè)價(jià)值47萬的教訓(xùn)讓我意識到:無序充電就像沒有交通燈的十字路口…

2026/7/29 14:57:16 閱讀更多
Design Token 單一真源:從 Figma 變量到代碼的工程化同步

Design Token 單一真源:從 Figma 變量到代碼的工程化同步

Design Token 單一真源:從 Figma 變量到代碼的工程化同步 一、設(shè)計(jì)稿與代碼的漂移:Token 治理的工程痛點(diǎn) 在多人協(xié)作的前端工程中,"設(shè)計(jì)稿與代碼不一致"是高頻出現(xiàn)的協(xié)作債務(wù)。設(shè)計(jì)師在 Figma 中定義了一組顏色變量(如 …

2026/7/29 14:57:16 閱讀更多
[具身智能-683]:系統(tǒng)建模的兩大手段:流程(Agent) + 算法(大模型、神經(jīng)網(wǎng)絡(luò))

[具身智能-683]:系統(tǒng)建模的兩大手段:流程(Agent) + 算法(大模型、神經(jīng)網(wǎng)絡(luò))

核心立論基于可觀測的系統(tǒng)輸入、輸出現(xiàn)象,挖掘系統(tǒng)內(nèi)在運(yùn)行規(guī)律,系統(tǒng)建模分為兩大基礎(chǔ)維度: 流程建模 Agent 主體交互、時(shí)序行為、任務(wù)流轉(zhuǎn)框架 算法建模 單元內(nèi)部輸入輸出映射規(guī)則,載體包含傳統(tǒng)機(jī)理算法、神經(jīng)網(wǎng)絡(luò)、大語言 / 多…

2026/7/29 14:57:16 閱讀更多
基于掌控板與Mind+的感應(yīng)垃圾桶項(xiàng)目:從超聲波測距到舵機(jī)控制的智能硬件入門實(shí)踐

基于掌控板與Mind+的感應(yīng)垃圾桶項(xiàng)目:從超聲波測距到舵機(jī)控制的智能硬件入門實(shí)踐

1. 項(xiàng)目概述:從“揮手”到“開蓋”的智能交互 你有沒有想過,讓家里的垃圾桶變得“聰明”一點(diǎn)?不是那種需要你喊它名字、跟它對話的“聰明”,而是能感知你的動作,在你靠近時(shí)自動開蓋,離開后靜靜合上的那種體…

2026/7/29 14:57:16 閱讀更多
Pokémon Showdown企業(yè)級對戰(zhàn)平臺:從零構(gòu)建可擴(kuò)展的寶可夢對戰(zhàn)系統(tǒng)

Pokémon Showdown企業(yè)級對戰(zhàn)平臺:從零構(gòu)建可擴(kuò)展的寶可夢對戰(zhàn)系統(tǒng)

Pokmon Showdown企業(yè)級對戰(zhàn)平臺:從零構(gòu)建可擴(kuò)展的寶可夢對戰(zhàn)系統(tǒng) 【免費(fèi)下載鏈接】pokemon-showdown Pokmon battle simulator. 項(xiàng)目地址: https://gitcode.com/gh_mirrors/po/pokemon-showdown Pokmon Showdown是一個(gè)專業(yè)級的開源寶可夢對戰(zhàn)模擬平臺&#x…

2026/7/29 14:47:16 閱讀更多
面試官大笑:“一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,不比 1 個(gè)快 5 倍?“我搖頭:“快不了,還可能更慢“

面試官大笑:“一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,不比 1 個(gè)快 5 倍?“我搖頭:“快不了,還可能更慢“

前兩個(gè)月,我在重構(gòu) AlgoMooc 網(wǎng)站過程中,發(fā)現(xiàn)一個(gè)問題:在 Claude Code 里把一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,結(jié)果可能比 1 個(gè) agent 從頭干到尾還慢? 大多數(shù)人的第一反應(yīng)是反過來的:活是并行干的&#…

2026/7/29 0:15:24 閱讀更多
# 鴻蒙 HarmonyOS 應(yīng)用開發(fā)實(shí)戰(zhàn)(第25期)|骰子(Dice Roller)— Unicode 符號與動畫渲染精講

# 鴻蒙 HarmonyOS 應(yīng)用開發(fā)實(shí)戰(zhàn)(第25期)|骰子(Dice Roller)— Unicode 符號與動畫渲染精講

一、應(yīng)用概述 骰子(Dice Roller) 是一款經(jīng)典的休閑娛樂應(yīng)用,模擬了真實(shí)擲骰子的過程。應(yīng)用投擲兩個(gè)骰子(六面標(biāo)準(zhǔn)骰),使用 Unicode 骰面符號直觀展示每個(gè)骰子的點(diǎn)數(shù),并伴有快速滾動的動畫效果?!?/p>

2026/7/29 0:15:24 閱讀更多