OpenAI-Compatible Thinking 方言设计
OpenAI-Compatible Thinking 方言调研
1. 结论
四家虽然都提供 OpenAI-compatible API,但 thinking 不能作为未经区分的 extra_fields 处理。正确的识别维度至少是:
adapter + dialect + model family
adapter决定基础协议,例如openai-completions或openai-responses;dialect决定扩展字段如何映射,例如minimax、deepseek、qwen、kimi;model family决定某个能力是否可关闭、支持哪些 effort、是否强制保留历史 reasoning。
同一厂商也可能因 endpoint 或模型族而使用不同配置。最明显的例子是:Qwen Chat Completions 使用 enable_thinking,Qwen Responses 使用 reasoning.effort;Kimi K3 使用 reasoning_effort,Kimi K2.6 使用 thinking.type/keep。
因此,公共层可以提供统一的语义配置,但 adapter 必须通过 dialect/model capability 做严格映射和拒绝,不能把同一 JSON 原样发给所有兼容服务。
2. 总览
| 厂商/入口 | 模型族 | 开关 | 力度/预算 | 历史保留 | thinking 输出 |
|---|---|---|---|---|---|
| MiniMax Chat | MiniMax-M3 | thinking.type=adaptive/disabled;默认开启 |
未声明 effort/budget | 工具循环需保留完整 assistant | reasoning_split=true 时为 reasoning_content + reasoning_details;否则在 content 的 <think> 中 |
| MiniMax Chat | M2.x | 始终开启,无法关闭 | 未声明 | 工具循环需保留完整 assistant | 同上 |
| DeepSeek Chat | 当前 thinking 模型 | thinking.type=enabled/disabled;默认开启 |
reasoning_effort=high/max |
tool call 后必须完整回传 reasoning_content |
reasoning_content |
| Qwen Chat | 混合思考模型 | enable_thinking=true/false |
部分模型支持 thinking_budget |
部分模型支持 preserve_thinking=true |
reasoning_content |
| Qwen Chat | 仅思考模型 | 始终开启,无法关闭 | 依模型能力 | 依模型能力 | reasoning_content |
| Qwen Responses | 支持 Responses 的 Qwen | reasoning.effort=none 关闭 |
none/minimal/low/medium/high;默认 medium |
Responses Items/previous_response_id 语义 |
reasoning output Item + reasoning token usage |
| Kimi Chat | kimi-k3 | 始终思考 | reasoning_effort=low/high/max;默认 max |
Preserved Thinking 始终开启 | reasoning_content,可能为空 |
| Kimi Chat | kimi-k2.7-code | 始终思考;官方建议不传 thinking |
无 effort | Preserved Thinking 始终开启 | reasoning_content |
| Kimi Chat | kimi-k2.6 | thinking.type=enabled/disabled;默认开启 |
无 effort | thinking.keep=null/all |
reasoning_content |
| Kimi Chat | kimi-k2.5 | thinking.type=enabled/disabled;默认开启 |
无 effort | 不支持 thinking.keep |
reasoning_content |
注意:表中的“历史保留”与工具循环中的正确性不是同一概念。即使用户选择不跨用户轮次保留 reasoning,只要当前 assistant turn 尚处于 tool loop,adapter 仍必须按照厂商要求回放对应 reasoning 数据。
3. MiniMax
官方 OpenAI SDK 文档当前以 MiniMax-M3 为主,同时列出 M2.x 系列。
3.1 开关
MiniMax-M3:
{"thinking": {"type": "adaptive"}}
adaptive:显式开启;当前对 M3 等同于开启 thinking;disabled:关闭 thinking;- 省略:默认开启。
{"thinking": {"type": "disabled"}}
M2.x:thinking 无法关闭。即使传入 disabled,仍保持开启。adapter 应在本地拒绝不可能兑现的 disabled,而不是让用户误以为已经关闭。
3.2 返回格式
reasoning_split 不控制 thinking 开关,只控制返回格式:
{"reasoning_split": true}
true:thinking 分离到reasoning_content和reasoning_details;false或省略:原生 Chat Completions 响应将 thinking 放在content的<think>...</think>标签中。
为避免 thinking 被 Agent 当成回答送入 TTS,Orion-X 应对 MiniMax 默认设置 reasoning_split=true。
官方流式示例把 reasoning_details[].text 当作可能的累计快照,通过已见长度计算增量。dialect extractor 不能无条件把每次 text 都当成 delta 追加,否则可能重复输出。
3.3 工具调用
多轮 function call 中要把完整 assistant message 加回 history。启用分离格式时,reasoning_content/reasoning_details 与 tool_calls 都属于需要保留的原生上下文。
3.4 SDK 映射
请求扩展通过 openai-go/v3 参数的 SetExtraFields 注入:
{
"thinking": {"type": "adaptive"},
"reasoning_split": true
}
响应扩展从 SDK response/chunk 的 JSON.ExtraFields 或 RawJSON() 读取,不自行解析 SSE。
4. DeepSeek
DeepSeek 当前 Thinking Mode 文档同时定义了 OpenAI Format 和 Anthropic Format。本节只讨论 OpenAI Chat Completions 方言。
4.1 开关与力度
{
"thinking": {"type": "enabled"},
"reasoning_effort": "high"
}
thinking.type:enabled或disabled,默认enabled;- OpenAI SDK 需要把
thinking放进额外 body; reasoning_effort:有效语义为high或max;- thinking 模式普通请求默认
high,部分复杂 agent 请求会自动使用max; low、medium会映射成high,xhigh会映射成max。
adapter 应只对外声明 DeepSeek 实际区分的 high/max,不要把兼容映射误报为四档真实能力。
4.2 参数冲突
thinking 模式不支持以下采样参数:
temperaturetop_ppresence_penaltyfrequency_penalty
官方行为是兼容性忽略,而不是报错。Orion-X 应在 validation 阶段报告这些字段不会生效;严格模式下直接拒绝,避免静默配置失效。
4.3 返回与工具调用
thinking 通过与 content 同级的 reasoning_content 返回。
- 没有 tool call 的普通历史 assistant reasoning,后续传入也会被忽略;
- 一旦 assistant 产生 tool call,本次及工具循环所需的
reasoning_content必须完整回传; - 缺失时 API 会返回 HTTP 400;
- 官方建议直接把完整 SDK assistant message append 回 history。
这说明 DeepSeek ProviderContext 不是展示增强,而是 tool loop 正确性数据。
5. Qwen
Qwen 同时提供 OpenAI-compatible Chat Completions 与 Responses,两者的推荐 thinking 配置不同。
5.1 Chat Completions
混合思考模型使用:
{
"enable_thinking": true,
"thinking_budget": 4096,
"preserve_thinking": true
}
enable_thinking=true/false:开启或关闭混合思考模型的 thinking;- Python OpenAI SDK 通过 extra body 传入;Go adapter 通过
SetExtraFields; - 仅思考模型始终思考,不设置
enable_thinking,也无法关闭; - thinking 通过
reasoning_content返回; - 部分开源思考模型只支持 streaming。
thinking_budget:
- 限制 reasoning 最大 token 数;
- 默认是该模型允许的最大思维链长度;
- 官方当前明确列为 Qwen3 thinking mode 等部分模型支持,不能对所有 Qwen 模型发送。
preserve_thinking=true:
- 让模型读取历史 assistant message 中的
reasoning_content; - 默认情况下 Qwen 会忽略历史 reasoning;
- 只支持官方列出的部分新模型;
- 开启后历史 reasoning 计入输入 token 和计费。
另有 prompt 控制方式:部分 Qwen3 开源混合思考模型及 qwen-plus-2025-04-28 在 enable_thinking=true 时可通过最新 prompt 中的 /think、/no_think 动态切换。它属于 prompt dialect,不应替代 API 参数,也不建议作为 Orion-X 的默认实现。
5.2 Responses
Qwen Responses 的推荐配置已经转向 OpenAI Responses 语义:
{
"reasoning": {
"effort": "medium"
}
}
支持:
none:关闭;minimal;low;medium:默认;high。
重要差异:
- Responses 不支持
thinking_budget; reasoning.effort优先于enable_thinking;- 官方建议优先使用
reasoning.effort,并说明 Responses 的enable_thinking后续将不再支持; - thinking 作为
reasoningoutput Item 返回,token 数在usage.output_tokens_details.reasoning_tokens; - 多轮可使用
previous_response_id,官方当前说明该 ID 有效期为 7 天。
所以 qwen + openai-completions 与 qwen + openai-responses 必须使用两套 mapper,不能共享 wire options。
6. Kimi
Kimi 当前官方 thinking 文档覆盖 kimi-k3、kimi-k2.7-code、kimi-k2.6、kimi-k2.5。它们虽然共用 Chat Completions endpoint,但配置差异显著。
6.1 kimi-k3
- 始终思考,不能关闭;
- 不使用
thinking.type; - 顶层
reasoning_effort支持low/high/max,默认max; - Preserved Thinking 始终开启;
- 可能返回
reasoning_content;历史 assistant message 必须原样保留。
6.2 kimi-k2.7-code
- 始终思考;
disabled会报错; - 官方正文建议调用时无需且不应传
thinking,只切换 model; - Preserved Thinking 始终开启;
thinking.keep不传或传合法值all都按all处理,其他值报错;- 必须把历史 assistant
reasoning_content原样保留。
实现上应把它建模成固定 capability,不需要为了表达固定行为而主动发送冗余参数。
6.3 kimi-k2.6
{
"thinking": {
"type": "enabled",
"keep": "all"
}
}
type=enabled/disabled,默认 enabled;keep=null或不传:不读取历史轮次 reasoning;keep=all:开启 Preserved Thinking;keep只影响历史 reasoning,不决定当前轮是否思考。
6.4 kimi-k2.5
thinking.type=enabled/disabled,默认 enabled;- 不支持
thinking.keep,没有 Preserved Thinking。
6.5 通用返回与工具约束
- thinking 在
reasoning_content,流式时先于content; reasoning_content + content都受max_tokens限制;- K2.6/K2.7-code 多步工具调用建议
max_tokens >= 16000; - K2.6/K2.7-code 的 temperature 不可修改,官方建议不要显式发送;
- 当前工具循环中的 reasoning 必须回传;跨用户轮次是否保留再由 fixed capability 或
thinking.keep决定。
7. 公共语义配置
建议公共层提供语义配置,而不是直接暴露某一家 JSON:
type ThinkingConfig struct {
Mode ThinkingMode
Effort ThinkingEffort
BudgetTokens *int
PreserveHistory PreserveMode
ExposeSummary bool
}
建议枚举:
ThinkingMode: default | enabled | disabled
ThinkingEffort: default | minimal | low | medium | high | xhigh | max
PreserveMode: default | none | all
映射规则:
default表示省略字段,保留 provider/model 默认行为;- dialect mapper 只映射目标确实支持的组合;
- 无法兑现的配置返回
UnsupportedOptionError,例如 M2.x/Kimi K3 关闭 thinking; - vendor 的兼容降级不应伪装成真实档位,例如 DeepSeek
medium -> high; BudgetTokens只发给明确支持的 Qwen Chat 模型;- tool loop continuity 是 adapter 的强制正确性行为,不受
PreserveHistory=none影响; - provider 原始扩展仍可通过受控 typed dialect options 表达,例如 MiniMax
reasoning_split。
8. openai-go/v3 实现边界
三个 OpenAI-compatible Chat dialect 都继续使用 github.com/openai/openai-go/v3。
8.1 请求
标准字段直接填写 SDK params。非标准字段只在 dialect mapper 最内层调用 SetExtraFields:
params.SetExtraFields(map[string]any{
"thinking": thinking,
})
禁止扩展字段覆盖 model、messages、tools、stream 等 adapter 已拥有的标准字段。
8.2 响应
openai-go/v3 的 Chat response 和 chunk 类型保留:
RawJSON();JSON.ExtraFields map[string]respjson.Field;respjson.Field.Raw()。
因此 dialect extractor 可以从 SDK 对象读取 reasoning_content、reasoning_details,无需自行实现 HTTP/SSE。
需要注意:SDK 的 ChatCompletionAccumulator 聚合标准字段,但不会自动把未知扩展字段变成完成态 typed 字段。正确流程是:
- SDK stream 产生 chunk;
- 标准内容交给 SDK accumulator;
- 同一个 chunk 在进入 accumulator 前交给 dialect extractor,读取 SDK 保存的 extra fields;
- dialect extractor 按该厂商的 delta/cumulative 语义聚合 reasoning;
- 最终公共
Response合并标准结果与 dialect state; - 完整原生 reasoning 写入
ProviderContext,不混入可播报 text。
这仍然是 SDK-first:网络、SSE framing、JSON 到 SDK struct 的解码全部由官方 SDK 完成,Orion-X 只解释 SDK 明确保留的扩展字段。
9. 推荐配置模型
Provider 配置应区分 adapter 与 dialect:
{
"adapter": "openai-completions",
"dialect": "deepseek",
"model": "deepseek-v4-pro",
"thinking": {
"mode": "enabled",
"effort": "high",
"preserve_history": "default"
}
}
Qwen Responses 示例:
{
"adapter": "openai-responses",
"dialect": "qwen",
"model": "qwen3.7-plus",
"thinking": {
"mode": "enabled",
"effort": "medium"
}
}
MiniMax 返回格式属于 dialect option:
{
"adapter": "openai-completions",
"dialect": "minimax",
"model": "MiniMax-M3",
"thinking": {
"mode": "enabled"
},
"dialect_options": {
"reasoning_split": true
}
}
10. 官方资料
- MiniMax, OpenAI SDK
- DeepSeek, Thinking Mode
- Alibaba Cloud Model Studio, 深度思考(Chat Completions)
- Alibaba Cloud Model Studio, OpenAI Responses 接口兼容
- Kimi, 思考模式
这些配置随模型发布变化较快。实现时要用 fixture 固化已支持模型族的行为,并把未知模型默认视为 capabilities unknown,不要根据模型名前缀静默猜测。
浙公网安备 33010602011771号