LocalAI 交错思考(Interleaved Thinking):让推理与工具调用在多轮对话中不断链
LocalAI 交错思考Interleaved Thinking让推理与工具调用在多轮对话中不断链【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAILocalAI 将推理模型reasoning model的思考链与工具调用封装为同一个 assistant 轮次中的两个字段reasoning与tool_calls。本篇围绕 LocalAI 文档中的Interleaved Thinking特性展开先讲清思考-工具-思考的往返契约与字段命名规则再给出 llama.cpp、vLLM、SGLang 三种后端的推理开关配置最后附一个可直接复制的 curl 实操示例与已知限制。读完本文你能在 LocalAI 上完整跑通模型先推理、再调用工具、再基于工具结果继续推理的多轮循环并理解 LocalAI 源码中reasoning字段的入站别名解析与 vLLM 解析器自动配置的实现细节。为什么工具调用循环需要交错思考推理模型在回答前会思考。当这样的模型同时调用工具时理想行为是思考与工具调用同轮返回且思考内容在工具结果回传后不丢失。LocalAI 把这个能力称为interleaved thinking一个 assistant 轮次同时携带reasoning和tool_calls客户端在下一轮把reasoning原样传回模型就不会在追加工具结果后丢失已有的思维链。这一点之所以关键是因为工具调用循环天然是多轮的模型推理 → 请求工具 → 客户端执行工具 → 携带工具结果再次调用模型。若没有交错思考第一轮产生的推理会被丢弃模型必须从零重建计划有了交错思考推理被回显到上下文中模型从断点处继续。往返契约Round-trip contract一个既推理又调用工具的 assistant 轮次两个字段并列返回reasoning模型思考内容tool_calls结构化工具调用finish_reason为tool_calls。客户端执行完工具后把会话再传回来需要带上两部分原始 assistant 消息包含它的reasoning和tool_calls不能省略一条toolrole 消息携带工具执行结果。LocalAI 会把传回的reasoning读回模型上下文使思维链保持连续。源码印证reasoning 字段如何解析与透传从源码结构看这一契约的落点在消息 schema 层。Message 结构体 中reasoning是一个*string指针字段注释标明它来自thinking.../thinking标签的提取// Reasoning content extracted from thinking.../thinking tags Reasoning *string json:reasoning,omitempty yaml:reasoning,omitempty而 Message.UnmarshalJSON 专门处理了入站别名vLLM、DeepSeek 风格的客户端在 assistant 轮次上发的是reasoning_contentLocalAI 接受该别名并映射到同一个内部字段当两个字段同时出现时规范的reasoning胜出if m.Reasoning nil aux.ReasoningContent ! nil { m.Reasoning aux.ReasoningContent }在跨进程透传上Messages.ToProto 会把reasoning写进 gRPC 消息的ReasoningContent字段使核心服务与后端 worker 之间完整携带思考内容。字段命名规则OpenAI chat completions/v1/chat/completions响应中reasoning与tool_calls并列出现。入站 assistant 消息同时接受reasoning_content作为reasoning的别名——该别名存在的原因正是一些客户端vLLM、DeepSeek、cogito用reasoning_content这个名字输出该字段两种命名都会被接受并映射到同一内部字段即上文 UnmarshalJSON 的实现。Anthropic Messages/v1/messages在 Anthropic 协议下推理以thinkingcontent block 的形式携带。本地路径中LocalAI 在tool_useblock 之前先发出一个thinkingblock并把入站的thinkingblock 读回 reasoning。由于本地模型不产生加密签名LocalAI 会为发出的 block 附加一个合成的不透明signature且不会验证入站 block 的签名。thinkingblock 只在请求显式通过thinking参数开启时才发出{ model: your-reasoning-model, max_tokens: 1024, thinking: { type: enabled }, messages: [ { role: user, content: What is the weather in Rome? } ] }从源码结构看请求侧的开关字段是 AnthropicThinkingParamthinking字段而响应侧的thinkingblock 带有Thinking与Signature两个字段见 Anthropic 内容块定义与文档描述的合成 signature、不校验行为对应。按后端启用推理交错思考要求后端能把模型的思考与最终回答分离开。如何开启取决于后端。llama.cpp设置模型选项reasoning_format可选值none、auto、deepseek、deepseek-legacy。其中auto让后端根据模型的 chat template 自行选择deepseek与deepseek-legacy强制使用 DeepSeek 风格的...提取。在 llama.cpp C 后端中该选项在 grpc-server.cpp 中被解析并映射到 llama.cpp 的COMMON_REASONING_FORMAT_*枚举NONE / AUTO / DEEPSEEK / DEEPSEEK_LEGACY。name: my-reasoning-model backend: llama-cpp parameters: model: my-reasoning-model.gguf options: - reasoning_format:autovLLM将模型选项reasoning_parser设为该模型族对应的 vLLM 原生推理解析器。此外LocalAI 自带一个自动配置钩子 hooks_vllm.go它加载嵌入式表 parser_defaults.json在模型加载时按模型 ID 匹配模型族为已知模型族同时设置推理解析器与工具调用解析器——因此对从 gallery 导入的 vLLM 模型这两项通常已经自动配置好了。自动配置的逻辑见 applyParserDefaults只有当用户在options中没有显式设置tool_parser:/reasoning_parser:时才注入默认值用户显式配置永远优先。模型族到解析器的映射关系收录在 parser_defaults.json 中例如模型族匹配模式tool_parserreasoning_parserqwen3hermesqwen3qwen2.5hermes—deepseek-r1deepseek_v3deepseek_r1deepseek-v3deepseek_v3deepseek_v3mistral-nemo / small / large、magistralmistralmistralllama-3.1 / 3.2 / 3.3llama3_json—llama-4llama4_pythonic—gemma-4gemma4gemma4gpt-ossopenaiopenai_gptosskimi-k2kimi_k2kimi_k2nemotron—nemotron_v3olmoolmo3olmo3name: my-vllm-model backend: vllm options: - reasoning_parser:deepseek_r1 - tool_parser:hermesSGLang同时设置reasoning_parser与tool_call_parser两个模型选项name: my-sglang-model backend: sglang options: - reasoning_parser:deepseek-r1 - tool_call_parser:qwen25实操示例一轮推理 工具调用定义一个工具并用一个需要先推理才能行动的提示词请求 chat completioncurl http://localhost:8080/v1/chat/completions -H Content-Type: application/json -d { model: your-reasoning-model, messages: [ { role: user, content: What is the weather in Rome? } ], tools: [ { type: function, function: { name: get_weather, description: Get the current weather for a city, parameters: { type: object, properties: { city: { type: string } }, required: [city] } } } ] }响应消息同时携带推理与工具调用且finish_reason为tool_calls{ choices: [ { finish_reason: tool_calls, message: { role: assistant, content: , reasoning: Okay, the user is asking about the weather in Rome... I need to call get_weather with city Rome., tool_calls: [ { id: call_abc123, type: function, function: { name: get_weather, arguments: {\city\:\Rome\} } } ] } } ] }继续对话的方式执行get_weather然后把会话发回去——先放 assistant 消息保留其reasoning与tool_calls再放一条携带工具结果的tool消息。LocalAI 会把传回的 reasoning 喂回上下文模型即可从中断的思维链处继续。已知限制流式模式下的 Anthropicthinkingblock。流式模式下thinkingblock 目前只在经过 llama.cpp C autoparser 的工具调用路径上发出。普通的纯文本流式轮次或走 inline token 路径解析的工具轮次都不会流式输出thinkingblock等价的非流式请求则会返回。即非流式在所有分支上都输出 thinking只有流式路径存在这一缺口。上游 llama.cpp 在最新混合推理模型上的泄漏。在最新的混合推理模型Qwen3.5 / Qwen3.6上存在一个上游 llama.cpp bug工具调用可能泄漏进reasoning_content而不是被解析进tool_calls。该问题已在 ggml-org/llama.cpp 上游讨论 #23351 中跟踪外部链接从略。推理预算与工具调用的竞争。如果推理模型在输出完工具调用之前就耗尽了输出预算max_tokens则不会产生任何工具调用。需要给模型足够的max_tokens来同时覆盖推理与调用本身耗尽预算时 LocalAI 会报告finish_reason: length。延伸阅读本文的机制与 OpenAI Functions and Tools 中各后端的工具调用提取方式、Text Generation (GPT) 的 chat completions 基础以及 Advanced model configuration 中所述的模型options机制配合阅读本特性的原始文档见 interleaved-thinking.md。【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考