news 2026/9/8 21:51:36

LocalAI 交错思考(Interleaved Thinking):让推理与工具调用在多轮对话中不断链

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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/LocalAI

LocalAI 将推理模型(reasoning model)的思考链与工具调用封装为同一个 assistant 轮次中的两个字段:reasoningtool_calls。本篇围绕 LocalAI 文档中的Interleaved Thinking特性展开:先讲清"思考-工具-思考"的往返契约与字段命名规则,再给出 llama.cpp、vLLM、SGLang 三种后端的推理开关配置,最后附一个可直接复制的 curl 实操示例与已知限制。读完本文,你能在 LocalAI 上完整跑通"模型先推理、再调用工具、再基于工具结果继续推理"的多轮循环,并理解 LocalAI 源码中reasoning字段的入站别名解析与 vLLM 解析器自动配置的实现细节。

为什么工具调用循环需要"交错思考"

推理模型在回答前会"思考"。当这样的模型同时调用工具时,理想行为是:思考与工具调用同轮返回,且思考内容在工具结果回传后不丢失。LocalAI 把这个能力称为interleaved thinking:一个 assistant 轮次同时携带reasoningtool_calls,客户端在下一轮把reasoning原样传回,模型就不会在追加工具结果后丢失已有的思维链。

这一点之所以关键,是因为工具调用循环天然是多轮的:模型推理 → 请求工具 → 客户端执行工具 → 携带工具结果再次调用模型。若没有交错思考,第一轮产生的推理会被丢弃,模型必须从零重建计划;有了交错思考,推理被回显到上下文中,模型从"断点处"继续。

往返契约(Round-trip contract)

一个既推理又调用工具的 assistant 轮次,两个字段并列返回:

  • reasoning:模型思考内容;
  • tool_calls:结构化工具调用;
  • finish_reasontool_calls

客户端执行完工具后,把会话再传回来,需要带上两部分:

  1. 原始 assistant 消息(包含它的reasoningtool_calls,不能省略);
  2. 一条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_content,LocalAI 接受该别名并映射到同一个内部字段;当两个字段同时出现时,规范的reasoning胜出:

if m.Reasoning == nil && aux.ReasoningContent != nil { m.Reasoning = aux.ReasoningContent }

在跨进程透传上,Messages.ToProto 会把reasoning写进 gRPC 消息的ReasoningContent字段,使核心服务与后端 worker 之间完整携带思考内容。

字段命名规则

OpenAI chat completions(/v1/chat/completions

响应中reasoningtool_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?" } ] }

从源码结构看,请求侧的开关字段是 AnthropicThinkingParam(thinking字段),而响应侧的thinkingblock 带有ThinkingSignature两个字段(见 Anthropic 内容块定义),与文档描述的"合成 signature、不校验"行为对应。

按后端启用推理

交错思考要求后端能把模型的"思考"与"最终回答"分离开。如何开启取决于后端。

llama.cpp

设置模型选项reasoning_format,可选值:noneautodeepseekdeepseek-legacy。其中auto让后端根据模型的 chat template 自行选择;deepseekdeepseek-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:auto

vLLM

将模型选项reasoning_parser设为该模型族对应的 vLLM 原生推理解析器。此外,LocalAI 自带一个自动配置钩子 hooks_vllm.go:它加载嵌入式表 parser_defaults.json,在模型加载时按模型 ID 匹配模型族,为已知模型族同时设置推理解析器与工具调用解析器——因此对从 gallery 导入的 vLLM 模型,这两项通常已经自动配置好了。

自动配置的逻辑见 applyParserDefaults:只有当用户在options中没有显式设置tool_parser:/reasoning_parser:时才注入默认值,用户显式配置永远优先。模型族到解析器的映射关系收录在 parser_defaults.json 中,例如:

模型族(匹配模式)tool_parserreasoning_parser
qwen3hermesqwen3
qwen2.5hermes
deepseek-r1deepseek_v3deepseek_r1
deepseek-v3deepseek_v3deepseek_v3
mistral-nemo / small / large、magistralmistralmistral
llama-3.1 / 3.2 / 3.3llama3_json
llama-4llama4_pythonic
gemma-4gemma4gemma4
gpt-ossopenaiopenai_gptoss
kimi-k2kimi_k2kimi_k2
nemotronnemotron_v3
olmoolmo3olmo3
name: my-vllm-model backend: vllm options: - reasoning_parser:deepseek_r1 - tool_parser:hermes

SGLang

同时设置reasoning_parsertool_call_parser两个模型选项:

name: my-sglang-model backend: sglang options: - reasoning_parser:deepseek-r1 - tool_call_parser:qwen25

实操示例:一轮"推理 + 工具调用"

定义一个工具,并用一个需要先推理才能行动的提示词请求 chat completion:

curl 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_reasontool_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 消息(保留其reasoningtool_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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 21:45:50

opencode 实战指南:从安装配置到模型路由与 LSP 集成

1. opencode到底是什么&#xff0c;为什么值得我把主力工作流迁过去 先聊一个结论放在前面&#xff1a;如果你日常重度使用 Claude Code、Codex 或者 Copilot 这类 AI 编程工具&#xff0c;那 opencode 很可能是目前最值得切换到终端 Agent 之一。我第一次接触它的时候&#xf…

作者头像 李华
网站建设 2026/9/8 21:40:58

Omarchy 镜像加速:3 步让 Arch Linux 更新快起来的完整指南

Omarchy 镜像加速&#xff1a;3 步让 Arch Linux 更新快起来的完整指南 【免费下载链接】omarchy Beautiful, Modern & Opinionated Linux 项目地址: https://gitcode.com/GitHub_Trending/om/omarchy 凌晨跑一次系统更新&#xff0c;下载速度掉到百 KB 级别&#x…

作者头像 李华