思考(Interleaved Thinking)實(shí)戰(zhàn):在工具調(diào)用之間讓模型“邊想邊調(diào)“)
vLLM 交錯(cuò)思考Interleaved Thinking實(shí)戰(zhàn)在工具調(diào)用之間讓模型邊想邊調(diào)【免費(fèi)下載鏈接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs項(xiàng)目地址: https://gitcode.com/GitHub_Trending/vl/vllm本篇基于 vLLM 倉(cāng)庫(kù)中的 Interleaved Thinking 特性文檔系統(tǒng)講解交錯(cuò)思考在工具調(diào)用之間穿插推理在 vLLM 中的工作原理、啟用方式與完整調(diào)用鏈讀者將掌握如何用--reasoning-parser與--tool-call-parser組合啟用該特性如何在多輪對(duì)話中把推理過(guò)程reasoning原樣回傳給模型以及背后 Kimi-K2 / MiniMax-M2 兩類推理解析器ReasoningParser的源碼實(shí)現(xiàn)與流式行為。什么是交錯(cuò)思考Interleaved Thinking交錯(cuò)思考允許模型在多次工具調(diào)用之間進(jìn)行推理模型發(fā)起一次工具調(diào)用、拿到工具結(jié)果后不是直接生成最終回答而是先對(duì)結(jié)果進(jìn)行一段推理thinking再?zèng)Q定下一步動(dòng)作。由此可以實(shí)現(xiàn)在決定下一步之前先對(duì)工具調(diào)用的結(jié)果進(jìn)行推理在多個(gè)工具調(diào)用之間穿插推理步驟形成調(diào)用 → 推理 → 再調(diào)用的鏈條基于中間結(jié)果做出更細(xì)致的判斷對(duì)外暴露其選擇工具的透明推理過(guò)程。文檔同時(shí)給出重要提示交錯(cuò)思考會(huì)增加 token 消耗和響應(yīng)延遲每多一輪推理就多一段思考 token。啟用前應(yīng)權(quán)衡預(yù)算與性能要求——如果你的 Agent 場(chǎng)景以少量、確定性強(qiáng)的工具調(diào)用為主未必需要開(kāi)啟。與普通思考模型的區(qū)別普通思考模型如 DeepSeek-R1 類只在最終回答前輸出一段think推理交錯(cuò)思考則把推理步驟插入到工具調(diào)用循環(huán)內(nèi)部用戶消息 → 推理 1 → 工具調(diào)用 1 → 工具結(jié)果 1 → 推理 2 → 工具調(diào)用 2 → 工具結(jié)果 2 → 推理 3 → 最終回答因此對(duì)服務(wù)端的兩個(gè)核心要求是能正確切分模型輸出中的推理部分與正文部分reasoning parser能正確識(shí)別與解析工具調(diào)用tool call parser并支持客戶端在下一輪把上一次的 reasoning 作為 assistant 消息的一部分回傳保證多輪上下文完整。vLLM 中支持交錯(cuò)思考的模型根據(jù) docs/features/interleaved_thinking.mdvLLM 當(dāng)前支持的交錯(cuò)思考模型及其對(duì)應(yīng)的 Reasoning Parser 名稱如下模型系列Reasoning Parser 名稱moonshotai/Kimi-K2-Thinkingkimi_k2MiniMaxAI/MiniMax-M2minimax_m2這兩個(gè)名稱是--reasoning-parser命令行參數(shù)的取值。它們并非獨(dú)立的 Python 手寫(xiě)解析器而是注冊(cè)到 vLLM 統(tǒng)一解析引擎Parser Engine中的適配器kimi_k2在 vllm/reasoning/kimi_k2_reasoning_parser.py 中直接別名到vllm.parser.engine.registered_adapters里的KimiK2ParserReasoningAdapter解析邏輯統(tǒng)一由vllm/parser/下的解析器如 vllm/parser/kimi_k2.py驅(qū)動(dòng)minimax_m2在 vllm/reasoning/minimax_m2_reasoning_parser.py 中定義了MiniMaxM2ReasoningParser與MiniMaxM2AppendThinkReasoningParser兩個(gè)實(shí)現(xiàn)。所有可用的 parser 名稱在 vllm/reasoning/init.py 的_REASONING_PARSERS_TO_REGISTER注冊(cè)表中統(tǒng)一定義kimi_k2指向kimi_k2_reasoning_parser.KimiK2ReasoningParserminimax_m2指向MiniMaxM2ReasoningParser另有minimax_m2_append_think變體并通過(guò)ReasoningParserManager懶加載注冊(cè)——--reasoning-parser傳的名稱必須能在此注冊(cè)表中找到。MiniMax-M2 解析器的實(shí)現(xiàn)細(xì)節(jié)MiniMax-M2 的推理格式有一個(gè)特殊之處見(jiàn)源碼注釋模型不生成think起始 token只生成/think結(jié)束 token/think之前的所有內(nèi)容都是推理之后是正式回答。vllm/reasoning/minimax_m2_reasoning_parser.py 中的核心方法體現(xiàn)這一語(yǔ)義is_reasoning_end(input_ids)從后向前掃描 token找到最后一個(gè)/thinkend token或thinkstart token只有當(dāng)它是 end token 時(shí)返回 True。這使得服務(wù)端能判斷推理階段是否已結(jié)束從而在流式輸出時(shí)決定 delta 進(jìn)入reasoning還是content字段extract_content_ids(input_ids)直接返回全部 token id內(nèi)容邊界由 token 位置確定而非標(biāo)記切分。倉(cāng)庫(kù)內(nèi)對(duì)應(yīng)的單元測(cè)試 tests/reasoning/test_minimax_m2_reasoning_parser.py 覆蓋了多種邊界場(chǎng)景均可作為行為依據(jù)測(cè)試用例模型輸出期望 reasoning期望 contentsimple_reasoningThis is a reasoning section/thinkThis is the restThis is a reasoning sectionThis is the restno_end_token流式中This is reasoning in progress同左None推理未結(jié)束全部算 reasoningmultiple_lines多行推理 多行回答多行推理部分多行回答部分code_in_reasoning推理中含代碼塊含代碼塊的推理Here is the code.empty_streaming空輸出NoneNone這些用例驗(yàn)證了只要/think尚未出現(xiàn)流式輸出期間所有 delta 都?xì)w入 reasoning出現(xiàn)/think后 delta 才切換到 content。這正是交錯(cuò)思考在工具結(jié)果 → 模型再次思考階段的關(guān)鍵行為——工具結(jié)果回傳后模型先吐出的新 token 會(huì)先進(jìn)入 reasoning 流。啟用方式服務(wù)端啟動(dòng)與請(qǐng)求參數(shù)服務(wù)端啟動(dòng)以 MiniMax-M2 為例需要同時(shí)啟用 tool call parser 與 reasoning parser并打開(kāi)自動(dòng)工具選擇vllm serve MiniMaxAI/MiniMax-M2 \ --tensor-parallel-size 4 \ --tool-call-parser minimax_m2 \ --reasoning-parser minimax_m2 \ --enable-auto-tool-choice各參數(shù)含義結(jié)合 vllm/engine/arg_utils.py 中的參數(shù)定義--tool-call-parser minimax_m2注冊(cè)工具調(diào)用解析器負(fù)責(zé)把模型輸出中的工具調(diào)用標(biāo)記解析為 OpenAI 格式的tool_calls結(jié)構(gòu)--reasoning-parser minimax_m2注冊(cè)推理解析器。源碼中該參數(shù)屬于StructuredOutputsConfig.reasoning_parserarg_utils.py 中reasoning_parser字段默認(rèn)取StructuredOutputsConfig.reasoning_parser隨后寫(xiě)入self.reasoning_config.reasoning_parser即推理切分能力掛在結(jié)構(gòu)化輸出/推理配置體系下--enable-auto-tool-choice允許模型自行決定是否調(diào)用工具對(duì)應(yīng)請(qǐng)求中的tool_choiceauto。對(duì) Kimi-K2-Thinking 服務(wù)同樣思路將兩處 parser 名換成kimi_k2vllm serve moonshotai/Kimi-K2-Thinking \ --tool-call-parser kimi_k2 \ --reasoning-parser kimi_k2 \ --enable-auto-tool-choice客戶端帶推理回傳的兩輪工具調(diào)用下面是原文檔給出的完整可運(yùn)行示例天氣查詢工具其要點(diǎn)是第二輪回傳 assistant 消息時(shí)必須帶上reasoning字段否則模型丟失上一輪的思考上下文交錯(cuò)推理鏈會(huì)斷裂。 vllm serve MiniMaxAI/MiniMax-M2 \ --tensor-parallel-size 4 \ --tool-call-parser minimax_m2 \ --reasoning-parser minimax_m2 \ --enable-auto-tool-choice import json from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keydummy) def get_current_weather(location: str, unit: str): Get the current weather in a given location if unit celsius: return fThe current temperature in {location} is 22°C. else: return fThe current temperature in {location} is 72°F. tools [ { type: function, function: { name: get_weather, description: Get the current weather in a given location, parameters: { type: object, properties: { location: { type: string, description: City and state, e.g., San Francisco, CA, }, unit: {type: string, enum: [celsius, fahrenheit]}, }, required: [location, unit], }, } } ] messages [{role: user, content: Whats the weather in Fahrenheit like in San Francisco?}] response client.chat.completions.create( modelclient.models.list().data[0].id, messagesmessages, toolstools, tool_choiceauto, ) tool_call response.choices[0].message.tool_calls[0].function messages.append( { role: assistant, tool_calls: response.choices[0].message.tool_calls, reasoning: response.choices[0].message.reasoning, # append reasoning } ) # Simulate tool execution available_tools {get_weather: get_current_weather} completion_tool_calls response.choices[0].message.tool_calls for call in completion_tool_calls: tool_to_call available_tools[call.function.name] args json.loads(call.function.arguments) result tool_to_call(**args) messages.append( { role: tool, content: result, tool_call_id: call.id, name: call.function.name, } ) response_2 client.chat.completions.create( modelclient.models.list().data[0].id, messagesmessages, toolstools, tool_choiceauto, ) print(response_2.choices[0].message.content)這段示例完整演示了交錯(cuò)思考的三步閉環(huán)第一輪用戶提問(wèn) → 模型輸出推理 工具調(diào)用tool_calls[0]此時(shí)message.reasoning攜帶本次工具調(diào)用前的思考內(nèi)容上下文拼接把 assistant 消息含tool_calls與reasoning和role: tool的工具結(jié)果追加進(jìn)messages第二輪模型收到工具結(jié)果后會(huì)先推理再回答——response_2的message.reasoning即為對(duì)工具結(jié)果的思考message.content為最終回答。推理字段的協(xié)議層支持回傳 reasoning 才能維持推理鏈之所以成立是因?yàn)?vLLM 的 Chat Completions 協(xié)議把推理內(nèi)容做成了一等字段請(qǐng)求側(cè)assistant 歷史消息支持reasoning鍵vllm/entrypoints/openai/chat_completion/protocol.py 中存在對(duì)msg.get(reasoning)的處理邏輯將客戶端回傳的推理內(nèi)容并入渲染后的提示詞響應(yīng)側(cè)消息體定義了reasoning: str | None字段同文件第 72 行附近流式與非流式都會(huì)填充另有include_reasoning: bool True的默認(rèn)值該文件兩處出現(xiàn)控制是否默認(rèn)包含推理輸出以及reasoning_effort參數(shù)用于支持按推理強(qiáng)度檔位請(qǐng)求對(duì)支持該參數(shù)的模型會(huì)轉(zhuǎn)成enable_thinking等用戶側(cè)開(kāi)關(guān)。也就是說(shuō)交錯(cuò)思考在協(xié)議層面的閉環(huán)是reasoning parser 把輸出切分成 reasoning/content → API 返回message.reasoning→ 客戶端回傳 → chat template 將其重新注入提示詞 → 模型基于完整推理歷史繼續(xù)思考。缺任何一環(huán)模型看到的歷史都會(huì)丟失思考內(nèi)容。實(shí)現(xiàn)鏈路總覽結(jié)合源碼結(jié)構(gòu)一次交錯(cuò)思考請(qǐng)求在 vLLM 內(nèi)部的處理鏈路如下從源碼結(jié)構(gòu)看各組件職責(zé)分離清晰解析引擎層vllm/parser/engine/parser_engine.py、streaming_parser_engine.py、incremental_lexer.py、token_id_scanner.py構(gòu)成增量式流式解析框架。reasoning 與 tool call 兩類事件由events.py定義registered_adapters.py將具體模型的解析規(guī)則適配到該引擎ReasoningParser 抽象層vllm/reasoning/abs_reasoning_parsers.py定義ReasoningParser基類與ReasoningParserManager各模型解析器通過(guò) vllm/reasoning/init.py 中的注冊(cè)表懶加載工具解析層vllm/tool_parsers/kimi_k2_tool_parser.py、minimax_m2_tool_parser.py等分別解析兩種模型的 【免費(fèi)下載鏈接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs項(xiàng)目地址: https://gitcode.com/GitHub_Trending/vl/vllm創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考