Prhub

#23951 fix(openai): map reasoning.enabled to thinking AND enable_thinking

原始 PR 作者 JustinTong0323 合并时间 2026-05-08 05:01 文件变更 2 提交数 1 评论 3 代码增减 +8 / -1

执行摘要

统一 reasoning.enabled 映射两种 chat_template key

PR body 指出,此前 reasoning.enabled=true 仅在 chat_template_kwargs 中设置 thinking=True,该 key 仅被 deepseek-v3/kimi_k2 识别,而 qwen3/glm45/nemotron_3/interns1/mimo 检查的是 enable_thinking,导致功能对后者静默失效。

建议合并。该 PR 是来自 #22254 的 9 行独立 bugfix,无外部依赖,解决模型间 thinking key 不一致问题。可后续跟进修复 review 指出的 enabled 与 effort='none' 同时设置时的优先级问题。

讨论亮点

Review 中 gemini-code-assist[bot] 指出一个高严重度逻辑漏洞:当 reasoning.enabled=truereasoning_effort='none' 时,setdefault 会使 thinking 和 enable_thinking 保持 True,而 'none' 预期应禁用思考。但该 PR 未修复此问题,仅做映射补充。该问题在 reasoning_effort='none' 分支中已使用 setdefault 将两 key 设为 False,但由于 enabled 分支先执行,若两分支先后触发,『none』分支的 setdefault 不会覆盖已存在的 True 值。不过实际场景中同一请求通常不会同时设置 enabled=true 且 effort='none',故问题影响有限。

实现拆解

  1. python/sglang/srt/entrypoints/openai/protocol.pynormalize_reasoning_inputs 方法中,当 reasoning.enabled 为 true 时,除原有 ctk.setdefault("thinking", True) 之外,增加一行 ctk.setdefault("enable_thinking", True),并添加注释说明不同模型检查不同键。
  2. test/registered/unit/entrypoints/openai/test_protocol.pytest_chat_completion_reasoning_effort 测试中,将预期结果从 {"thinking": True} 更新为 {"thinking": True, "enable_thinking": True},以覆盖双 key 均被设置的情况。
文件 模块 状态 重要度
python/sglang/srt/entrypoints/openai/protocol.py 协议解析 modified 5.3
test/registered/unit/entrypoints/openai/test_protocol.py 协议测试 modified 3.89

关键符号

normalize_reasoning_inputs test_chat_completion_reasoning_effort

关键源码片段

python/sglang/srt/entrypoints/openai/protocol.py core-logic

核心逻辑变更:在 normalize_reasoning_inputs 中为 enable_thinking 添加 setdefault 映射。

# 位于 python/sglang/srt/entrypoints/openai/protocol.py,normalize_reasoning_inputs 方法中
if enabled:
    ctk = values.get("chat_template_kwargs")
    if not isinstance(ctk, dict):
        ctk = {}
    # 不同模型检查不同的 chat template key:
    # - "thinking" 用于 deepseek-v3, kimi_k2
    # - "enable_thinking" 用于 qwen3, glm45, nemotron_3, interns1, mimo
    ctk.setdefault("thinking", True)
    ctk.setdefault("enable_thinking", True) # 新增行,覆盖更多模型
    values["chat_template_kwargs"] = ctk
test/registered/unit/entrypoints/openai/test_protocol.py test-coverage

单元测试同步更新,验证双 key 均被设置。

# 位于 test/registered/unit/entrypoints/openai/test_protocol.py
# test_chat_completion_reasoning_effort 方法中
request = ChatCompletionRequest(
    model="test-model",
    messages=messages,
    reasoning={
        "enabled": True,
        "reasoning_effort": "high",
    },
)
self.assertEqual(request.reasoning_effort, "high")
# 验证两个 thinking key 均被设置
self.assertEqual(
    request.chat_template_kwargs,
    {"thinking": True, "enable_thinking": True},
)

评论区精华

reasoning.enabled 与 reasoning_effort='none' 同时设置时 setdefault 逻辑缺陷 正确性

gemini-code-assist[bot] 指出当 reasoning.enabled=true 且 reasoning_effort='none' 同时出现时,enabled 分支用 setdefault 设置 thinking 和 enable_thinking 为 True,而后 reasoning_effort='none' 分支用 setdefault 设置为 False 无法覆盖已存在的 True,导致用户期望 disable 但实际 enable。

结论:未解决。该 PR 专注于映射修复,未调整优先级逻辑。实际场景中同时设置 enabled=true 和 effort='none' 的可能性较低,但仍属潜在 bug。 · 待处理

风险与影响

低风险。PR 仅新增一行 setdefault 并更新测试断言,逻辑简单。但遗留的『enabled 与 effort='none' 同时设置时的优先级』问题在极端场景下可能导致用户期望 disable 但实际 enable。此外,当用户显式传入 chat_template_kwargs 时,setdefault 保留用户指定值,符合预期。

对用户:修复使用 reasoning.enabled=true 时 Qwen3/GLM45 等模型无思考输出的问题。对系统:变更范围极小(2 文件,9 行),无性能影响。对团队:统一不同模型家族的 thinking 映射方式,降低未来新增模型的认知成本。

缺少边界值覆盖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论