推理与思考模型
Open WebUI 对表现出“思考”或“推理”行为的模型(如 DeepSeek R1、OpenAI o1 等)提供了一流的原生支持。这些模型通常会在输出最终答案之前,在内部生成思维链(Chains of Thought)。
思考标签的工作原理
当模型生成推理内容时,它通常会将该内容包裹在特定的 XML 标签中(例如 <think>...</think> 或 <thought>...</thought>)。
Open WebUI 会自动:
- 检测模型输出流中的这些标签。
- 提取标签之间的内容。
- 渲染提取到的内容到一个可折叠的 UI 元素中,该元素被标记为“思考(Thought)”或“正在思考(Thinking)”。
这样既能保持主对话界面的整洁,同时又允许您查看模型的内部处理过程。
reasoning_tags 参数
您可以使用 reasoning_tags 参数自定义 Open WebUI 应该识别哪些标签。这可以在每次对话或每个模型的维度上进行设置。
默认标签
默认情况下,Open WebUI 会识别几种常见的推理标签对:
<think>,</think><thinking>,</thinking><reason>,</reason><reasoning>,</reasoning><thought>,</thought><|begin_of_thought|>,<|end_of_thought|>
自定义
如果您的模型使用不同的标签,您可以在 reasoning_tags 参数中提供一个标签对列表。每个标签对都是一个由开始标签和结束标签组成的元组或列表。
配置与 行为
- 从 Payload 中移除:
reasoning_tags参数本身是 Open WebUI 特有的控制项,在发送给 LLM 后端(OpenAI, Ollama 等)之前会从 Payload 中移除。这确保了与不识别此参数的提供商的兼容性。 - 对话历史:推理内容会保留在对话历史中,并在轮次之间发送回模型。在构建后续请求的消息时,Open WebUI 会使用其原始标签(如
<think>...</think>)对推理内容进行序列化,并将其包含在 assistant 消息的content字段中。这使模型能够在整个对话中“记住”其先前的推理步骤。 - UI 渲染:在内部,推理块使用专门的 UI 组件进行处理和渲染。在保存或导出时,它们可能会被表示为 HTML 的
<details type="reasoning">标签。
Open WebUI 设置
Open WebUI 提供了几个内置设置来配置推理模型的行为。这些设置可以在以下位置找到:
- 侧边栏的 对话控制(Chat Controls) → 高级参数(Advanced Parameters) —— 每次对话的设置
- 工作区(Workspace) → 模型(Models) → 编辑模型(Edit Model) → 高级参数(Advanced Parameters) —— 每个模型的设置(仅限管理员)
- 管理员面板(Admin Panel) → 设置(Settings) → 模型(Models) → 选择一个模型 → 高级参数(Advanced Parameters) —— 另一个每个模型设置的位置
推理标签设置
此设置控制 Open WebUI 如何解析和显示思考/推理块:
| 选项 | 描述 |
|---|---|
| 默认(Default) | 使用系统默认行为 |
| 已启用(Enabled) | 显式启用推理标签检测,使用默认的 <think>...</think> 标签 |
| 已禁用(Disabled) | 完全关闭推理标签检测 |
| 自定义(Custom) | 允许您指定自定义的开始和结束标签 |
使用自定义标签
如果您的模型使用非标准的推理标签(例如 <reasoning>...</reasoning> 或 [思考]...[/思考]),请选择 自定义(Custom) 并输入:
- 开始标签(Start Tag):开始标签(例如
<reasoning>) - 结束标签(End Tag):结束标签(例如
</reasoning>)
这适用于:
- 具有本地化思考标签的模型
- 具有独特标签格式的自定义微调模型
- 使用 XML 风格推理标记的模型
think (Ollama)
此 Ollama 特有的设置可以启用或禁用模型内置的推理功能:
| 选项 | 描述 |
|---|---|
| 默认(Default) | 使用 Ollama 的默认行为 |
| 开启(On) | 显式为模型启用思考模式 |
| 关闭(Off) | 禁用思考模式 |
此设置会将 think 参数直接发送给 Ollama。它与 Open WebUI 如何解析回复是分开的 —— 您可能同时需要此设置以及正确的推理标签配置才能获得完整体验。
推理力度(Reasoning Effort)
对于支持可变推理深度(如某些 API 提 供商)的模型,此设置控制模型在推理上付出的力度:
- 常见值:
low,medium,high - 某些提供商接受数字值
推理力度(Reasoning Effort)仅适用于来自支持此参数的特定提供商的模型。它对本地 Ollama 模型没有影响。
推理与工具调用的交织(Interleaved Thinking)
当模型在单轮对话中使用原生函数调用(工具使用)时,Open WebUI 会保留推理内容,并将其发送回 API,以便在该轮次的后续调用中使用。这实现了真正的“推理与工具调用交织”,其中:
- 模型生成推理 → 进行工具调用
- 工具执行并返回结果
- 模型接收到:原始消息 + 先前的推理 + 工具调用 + 工具结果
- 模型继续推理 → 可能会进行更多工具调用或提供最终答案
- 重复该过程直到该轮对话完成
工作原理
在多步骤工具调用轮次中,Open WebUI 会:
- 从模型的响应中捕获推理内容(通过 delta 中的
reasoning_content、reasoning或thinking字段) - 将其与工具调用一起存储在内容块中
- 在构建下一次 API 调用的消息时,使用其原始标签(例如
<think>...</think>)对推理进行序列化 - 将序列化后的内容包含在 assistant 消息的
content字段中
这确保了模型在同一轮次内决定后续操作时,能够访问其先前的思考过程。
推理内容如何被发送回去
存在两条并行的路径,适用哪一条取决于前一轮的推理内容是如何被捕获的 —— 而不取决于您发送到的提供商。
路径 1 —— 嵌入在 content 中的推理内容(大多数提供商的默认行为)
当模型在其内容中内联以 <think>…</think>(或任何其他配置的标签对)的形式流式传输推理时,Open WebUI 会将这些标签保留为 message.content 的一部分。在下一轮中,该消息会被逐字转发给 LLM,保留所有标签。没有任 何内容被丢弃,也不需要特定于提供商的处理。这可能是您已经在使用的路径 —— 它也是上面 推理与工具调用的交织 部分所描述的路径。
路径 2 —— 捕获到结构化 output 数组中的推理内容
如果上游流发出了 reasoning_content / reasoning / thinking 的 delta(而不是文本标签)—— 这对于 OpenAI o 系列、DeepSeek 官方 API、启用了推理的 llama.cpp 或带 --reasoning-parser 标志的 Ollama 来说非常典型 —— Open WebUI 会将这些 delta 捕获到 assistant 消息的 output 数组中的独立 reasoning 项中。显示的 content 仅包含一个用于 UI 的 <details type="reasoning"> 块;而结构化形式保留在 output 中。
当该消息被重放到 LLM(在工具调用循环中或在下一轮用户对话中)时,Open WebUI 会从 output 重建它,而不是转发渲染后的 content。用于重建推理的格式取决于连接的 Provider 设置(管理员设置 → 连接 → OpenAI → 提供商 下拉菜单 —— 选项有 Default、Azure OpenAI、llama.cpp;Ollama 连接会自动检测):
连接 Provider | 重建推理的格式 |
|---|---|
| Ollama(自动检测) | 包裹在 content 内的标签中:<think>…</think> |
llama.cpp | assistant 消息上的顶级 reasoning_content 字段 |
Default / Azure OpenAI | 推理内容在重建的消息中被忽略(Omitted) |
选择“在默认/严格模式下忽略”是深思熟虑的:OpenAI、Azure OpenAI、Vertex AI 和类似的 Chat Completions APIs 会拒绝包含未知字段的 assistant 消息,并且它们不希望在下一次调用时回传它们自己的推理内容(它们在 Responses API 中通过 previous_response_id 在状态端管理连贯性,或者根本不需要它)。Pipe 函数和过滤器可以在需要时以特定于提供商的形式重新注入推理。
对于 Ollama,重建后的消息类似于:
{
"role": "assistant",
"content": "<think>Let me search for the current weather data...</think>",
"tool_calls": [...]
}对于 llama.cpp 连接,它类似于:
{
"role": "assistant",
"content": "",
"reasoning_content": "Let me search for the current weather data...",
"tool_calls": [...]
}提供商兼容性
| 提供商类型 | 路径 1(content 中的标签) | 路径 2(结构化 output) |
|---|---|---|
内联发出 <think> 标签的 OpenAI 兼容 APIs(通过 Ollama 的 DeepSeek-R1、带推理解析器的 Qwen3 等) | ✅ 自动往返。 | 不适用 |
Ollama(连接自动标记为 ollama) | ✅ 往返。 | ✅ 在 content 中重建为 <think>…</think>。 |
llama.cpp(连接 Provider 设置为 llama.cpp) | ✅ 如果模型使用标签,支持往返。 | ✅ 重建为 reasoning_content 字段。 |
| OpenAI o 系列(Responses API) | 不适用 —— o 系列不暴露推理文本。 | ⚠️ 推理连贯性由 previous_response_id 处理,而不是通过重新发送内容。 |
OpenAI / Azure / Vertex AI (Chat Completions, Provider Default) | ✅ 标签以 文本形式通过 —— 大多数严格的提供商都容许它们。 | ⚠️ 重建时忽略结构化推理(如果需要,请使用 pipe/filter 重新注入)。 |
| Anthropic(extended thinking 深度思考) | ⚠️ 标签有效,但原生 API 期望 {"type": "thinking"} 块以实现真正的深度思考 —— 请使用 pipe function。 | ❌ 原生不支持。 |
重要注意事项
- 检测逻辑未改变。 从输入流中检测推理内容的方式与以往完全相同 —— 路径 1 使用
<think>样式的标签匹配,路径 2 使用reasoning_content/reasoning/thinkingdelta。这里添加的提供商感知行为仅控制在重放消息时如何重建路径 2 的推理内容。 - 轮内和轮际使用相同的逻辑。 无论 Open WebUI 是在多步骤工具调用循环中发送消息,还是为新的用户轮次构建 Payload,都适用相同的重建规则。
- 大多数用户处于路径 1。 内联发出
<think>标签的模型(Ollama 上的 DeepSeek-R1 系列、Qwen3、MiniMax M2.5 等)将其推理保留在content中,并继续在没有做任何提供商配置的情况下进行往返。
流式与非流式
流式模式(默认)
在流式模式下(stream: true),Open WebUI 会在 Token 到达时对其进行处理,并可以实时检测推理块。这通常在没有额外配置的情况下也能工作得很好。
非流式模式
在非流式模式下(stream: false),整个响应会一次性返回。这是大多数解析问题发生的地方,因为:
- 响应作为一个单一的文本块到达
- 没有推理解析器,就没有后处理来分离
<think>内容 - 原始响应会按原样显示
如果您使用非流式请求(通过 API 或某些特定配置),推理解析器对于正确分离思考块至关重要。
API 使用
在通过推理模型使用 Open WebUI API 时:
{
"model": "qwen3:32b",
"messages": [
{"role": "user", "content": "Solve: What is 234 * 567?"}
],
"stream": true
}建议: 使用 "stream": true 以获得最可靠的推理块解析。
问题排查
思考内容与最终答案合并
症状: 使用推理模型时,整个响应(包括 <think>...</think> 块)都作为最终答案显示,而不是被分离到隐藏/可折叠的思考部分。
错误显示的示例:
<think>
Okay, the user wants a code snippet for a sticky header using CSS and JavaScript.
Let me think about how to approach this.
...
I think that's a solid approach. Let me write the code now.
</think>
Here's a complete code snippet that demonstrates a sticky header using CSS and JavaScript...预期行为: 思考内容应该是隐藏或可折叠的,仅最终答案可见。
针对 Ollama 用户
最常见的原因是 Ollama 没有配置正确的推理解析器(reasoning parser)。运行 Ollama 时,您需要指定 --reasoning-parser 标志以启用对思考块的正确解析。
步骤 1:配置推理解析器
启动 Ollama 时,添加 --reasoning-parser 标志:
# 针对 DeepSeek-R1 风格的推理(推荐用于大多数模型)
ollama serve --reasoning-parser deepseek_r1
# 备用解析器(如果上述解析器对您的模型不起作用)
ollama serve --reasoning-parser qwen3
ollama serve --reasoning-parser deepseek_v3对于大多数推理模型,包括 Qwen3 和 DeepSeek 变体,请使用 --reasoning-parser deepseek_r1。此解析器处理大多数推理模型使用的标准 <think>...</think> 格式。
步骤 2:重启 Ollama
添加标志后,重启 Ollama 服务:
# 停止 Ollama
# 在 Linux/macOS 上:
pkill ollama
# 在 Windows 上 (PowerShell):
Stop-Process -Name ollama -Force
# 带着推理解析器启动
ollama serve --reasoning-parser deepseek_r1步骤 3:在 Open WebUI 中验证
- 前往 Open WebUI 并与您的推理模型开始新的对话
- 提出一个需要推理的问题(例如,数学题或逻辑谜题)
- 响应现在应该在一个可折叠的部分中显示思考内容
可用的推理解析器
| 解析器 | 描述 | 使用场景 |
|---|---|---|
deepseek_r1 | DeepSeek R1 格式 | 大多数推理模型,包括 Qwen3 |
deepseek_v3 | DeepSeek V3 格式 | 某些 DeepSeek 变体 |
qwen3 | Qwen3 特有格式 | 如果 deepseek_r1 对 Qwen 不起作用 |
问题排查清单
1. 验证 Ollama 是否带推理解析器运行
检查 Ollama 启动时是否带了正确的标志:
# 检查 Ollama 进程
ps aux | grep ollama
# 或在 Windows 上:
Get-Process -Name ollama | Format-List *在命 令行参数中寻找 --reasoning-parser。
2. 检查模型兼容性
并非所有模型都以相同的格式输出推理。请查看您的模型文档以验证:
- 它使用什么标签来包裹思考内容(例如
<think>、<reasoning>等) - 它是否需要特定的 Prompt 来启用思考模式
3. 测试启用流式传输
如果非流式传输不起作用,请尝试在您的对话中启用流式传输:
- 前往 对话控制(Chat Controls)(侧边栏)
- 确保已启用流式传输(这是默认设置)
- 再次测试模型
4. 检查 Open WebUI 版本
确保您运行的是最新版本的 Open WebUI,因为对推理模型的支持在不断改进:
docker pull ghcr.io/open-webui/open-webui:main5. 验证模型回复格式
直接使用 Ollama CLI 检查您的模型输出什么格式:
ollama run your-model:tag "Explain step by step: What is 15 + 27?"在输出中寻找 <think> 标签。如果它们不存在,模型可能需要特定的系统 Prompt 来启用思考模式。
工具调用之间推理丢失
症状: 工具调用完成后,模型似乎“忘记”了它之前在想什么。
可能的原因:
- 模型没有以被捕获的格式输出推理(
reasoning_content、reasoning或thinkingdelta 字段) - 模型使用基于文本的思考标签,这些标签没有被解析为推理块
解决方案: 检查您的模型是否通过以下方式输出推理:
- 结构化 delta 字段(
reasoning_content、reasoning、thinking) - Open WebUI 检测的基于文本的标签(确保启用了推理标签检测)
Anthropic Extended Thinking 无法与工具调用配合使用
症状: 在启用了 extended thinking 的情况下使用 Anthropic 的 Claude 模型,但工具调用失败并报错:
Expected `thinking` or `redacted_thinking`, but found `text`. When `thinking` is enabled,
a final `assistant` message must start with a thinking block.
原因: 这是一个根本性的架构差异。Open WebUI 遵循 OpenAI Chat Completions API 标准,原生不支持 Anthropic 的专有 API 格式。Anthropic 的 extended thinking 需要包含 {"type": "thinking"} 或 {"type": "redacted_thinking"} 的结构化内容块,这些是 Anthropic 特有的格式,在 OpenAI 标准中并不存在。
Open WebUI 在消息内容字段内将推理序列化为被标签包裹的文本(例如 <think>...</think>)。这适用于 OpenAI 兼容的 API,但不满足 Anthropic 对结构化思考块的要求。
为什么 Open WebUI 不原生支持此格式:
在不同的提供商之间,没有标准的方法来将推理内容存储为 API Payload 的一部分。如果 Open WebUI 实现了对某个提供商格式的支持,它可能会破坏许多其他推理提供商的现有部署。鉴于 Open WebUI 支持广泛的后端,我们遵循 OpenAI Completions API 作为通用标准。有关此架构决定的更多详细信息,请参阅我们的 关于协议支持的 FAQ。
权宜之计:
-
使用 Pipe 函数:创建一个自定义的 pipe function,在向 Anthropic API 发送请求之前,将 Open WebUI 基于文本的思考格式转换为 Anthropic 的结构化思考块。
-
禁用 Extended Thinking:如果您在工具调用工作流中不需要思考过程,请将其禁用以避免格式不匹配。
此限制专门适用于将 Anthropic 的 extended thinking 与工具调用结合使用。Extended thinking 在没有工具调用时可以工作,工具调用在没有 extended thinking 时也可以工作 —— 只有在通过 Anthropic API 同时使用这两个功能时才会发生此问题。
有状态推理模型(GPT-5.2 等)
症状: 使用隐藏其推理的模型(有状态/内部推理),且推理内容未被保留。
原因: 一些较新的模型(如 GPT-5.2)将推理保留在内部,并不在 API 响应中暴露。Open WebUI 只能保留模型实际返回的推理内容。
行为: 如果模型返回的是推理摘要而不是完整的推理内容,那么被保留并发送回去的将是该摘要。
常见问题解答
为什么思考块显示为原始文本?
如果模型使用的标签不在默认列表中,并且未在 reasoning_tags 中进行配置,Open WebUI 将把它们视为普通文本。您可以通过在“模型设置”或“对话控制”中将正确的标签添加到 reasoning_tags 参数来解决此问题。
模型能看到它自己的思考吗?
是的。 推理内容会在以下两种场景中被保留并发送回模型:
-
在同一轮对话中(工具调用期间):是的。当模型进行工具调用时,Open WebUI 会保留推理内容并将其作为 assistant 消息的一部分发送回 API。这使模型能够保持关于它在进行工具调用时在想什么的上下文。
-
跨不同轮次:是的。在构建后续请求的消息时,Open WebUI 会使用其原始标签(例如
<think>...</think>)对前几轮的推理内容进行序列化,并将其包含在 assistant 消息的content字段中。这允许模型在整个对话中引用其先前的推理。
在工具调用期间推理内容是如何发送的?
当涉及工具调用时,推理会被序列化为带原始标签的文本,并包含在 assistant 消息的 content 字段中。例如:
<think>Let me search for the current weather...</think>
这种基于文本的格式适用于大多数 OpenAI 兼容的提供商。然而,某些提供商(如 Anthropic)可能期望特定格式的结构化思考内容块 —— Open WebUI 目前使用基于文本的序列化,而不是特定于提供商的结构化格式。