Skip to content

统一 Thinking / Reasoning

网关将所有 provider 的 thinking 和 reasoning 统一为单一的请求规范和单一的响应格式。

请求:reasoning 参数

在任何 OpenAI 格式的请求体中发送顶层 reasoning 对象:

json
{
  "model": "deepseek-reasoner",
  "reasoning": {
    "effort": "medium",
    "max_tokens": 8000
  },
  "messages": [{ "role": "user", "content": "..." }]
}

字段说明

字段类型说明
enabledbooleanfalse 关闭 thinking,等效于 effort: "none"
effortstring"none" | "low" | "medium" | "high" | "xhigh",透传给支持 effort 的模型
max_tokensnumber模型可用于推理的最大 token 数(thinking budget)
excludebooleantrue 时,告知 provider 不在响应中包含 thinking 内容(Google 专用)

所有字段均可选。reasoning: {} 空对象即以 provider 默认值启用 thinking。

关闭 thinking

json
{ "reasoning": { "enabled": false } }

或:

json
{ "reasoning": { "effort": "none" } }

Provider 原生 thinking 参数(Anthropic / Google)

Anthropic 读取统一的 reasoning 字段,需直接传 Anthropic 原生 thinking 参数:

json
{
  "thinking": { "type": "enabled", "budget_tokens": 8000 }
}
json
{
  "thinking": { "type": "disabled" }
}

Google 同时支持 reasoningthinking,两者会合并写入 generationConfig.thinking_config


网关的 reasoning 参数映射规则

Providerreasoning.effortreasoning.enabled / effort: "none"reasoning.max_tokens
OpenAIreasoning_effort(字符串)不发送不发送
DeepSeekreasoning_effort + thinking.typethinking.type: "disabled"不发送
GooglegenerationConfig.thinkingConfig.thinkingLevel不发送generationConfig.thinking_config.thinking_budget
Coherethinking.type: "enabled"thinking.type: "disabled"thinking.budget_tokens + token_budget
Ollama"low"/"medium"/"high"think: <effort>think: false不发送
DashScope不发送enable_thinking: false不发送
Anthropic(不映射,请直接用 thinking 参数)(不映射)(不映射)

响应:统一输出格式

无论使用哪个 provider,所有推理文本均返回在:

choices[n].message.reasoning   (非流式)
choices[n].delta.reasoning     (流式)

两者均为纯 string。当模型没有产生 thinking 输出时,该字段省略(不设为 null"")。

非流式

json
{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": "答案是 42。",
      "reasoning": "让我一步步分析..."
    },
    "finish_reason": "stop"
  }]
}

流式

data: {"choices":[{"delta":{"reasoning":"让我一步"},"index":0}]}
data: {"choices":[{"delta":{"reasoning":"步分析"},"index":0}]}
data: {"choices":[{"delta":{"content":"答案是 42。"},"index":0}]}
data: {"choices":[{"delta":{},"finish_reason":"stop","index":0}]}

reasoning delta 和 content delta 在不同 chunk 中发送,每个 chunk 最多包含 delta.reasoningdelta.content 之一。


响应归一化流程

所有 provider 返回的 thinking 内容,在离开网关前均经过 normalizeOpenAIReasoningMessage 处理,按顺序从以下位置收集推理文本并拼接为一个 reasoning 字符串:

  1. message.reasoning — 已是 OpenAI 兼容格式,直接使用。
  2. message.reasoning_content — DeepSeek 字段名,提取后删除。
  3. message.thinking — 部分 provider 的字段,提取后删除。
  4. message.content_blocks[] — 部分 provider 的数组格式,逐块提取 reasoning 字段。
  5. message.content[]type: "thinking" / type: "redacted_thinking" 的 part — Anthropic 流式 content part,提取后从数组中移除。
  6. message.content 字符串中的 <think>...</think> 标签 — 开源模型(Qwen 等)的内联标签,提取后从 content 中删除。

归一化后:

  • message.reasoning_content 被删除。
  • message.thinking 被删除。
  • message.content_blocks 被删除。
  • message.content 中的 <think> 标签和 thinking-type content part 被去除。
  • 若没有找到任何 reasoning,reasoning 字段完全省略(不设为 null"")。

流式响应的每个 delta 经过 normalizeOpenAIReasoningDelta 处理,在此基础上额外删除空字符串的 delta.content(避免发送 "content": "")。

Anthropic 的处理方式

Anthropic 将 thinking 以带 type 的 content block 数组返回。Anthropic 响应转换器在归一化前先遍历 response.content[]

  • type: "text" block → 拼入 message.content
  • type: "thinking" block → block.thinking 追加到 reasoning
  • type: "redacted_thinking" block → block.data 追加到 reasoning

流式场景中,delta.type === "thinking_delta" 的 chunk 将 delta.thinking 映射为 delta.reasoning

Google 的处理方式

Google 在 content parts[] 中通过 thought: true 标记返回推理内容。Google 响应转换器将这些 part 收集到 message.reasoning,并从 message.content 中排除。


Provider 支持情况

Providerreasoning 参数thinking 参数响应已归一化
OpenAI / Azure OpenAI✅ effort
Anthropic❌ 请用 thinking
Google AI / Vertex AI
DeepSeek✅ effort + enabled
Cohere
Ollama
DashScope✅ 仅 enabled
OpenRouter✅(透传后归一化)
Novita AI✅(透传后归一化)

"响应已归一化"表示无论 upstream provider 返回何种格式,reasoning 内容都会被整合到 choices[n].message.reasoning 中。

面向多模型、多 Provider 和 Coding Plan 场景的统一 AI Gateway 文档。