[Bug]: `–reasoning-parser gemma4` silently disables structured output (xgrammar) when `enable_thinking=false`

用户在使用 vLLM 启动 Gemma 4 系列模型(如 google/gemma-4-E4B-it 、 google/gemma-4-26B-A4B-it 、 google/gemma-4-31B-it )时,同时指定了:

[Bug]: `--reasoning-parser gemma4` silently disables structured output (xgrammar) when `enable_thinking=false`

[Bug]: `–reasoning-parser gemma4` silently disables structured output (xgrammar) when `enable_thinking=false`

快速结论:当使用 --reasoning-parser gemma4 并设置 enable_thinking=false 时,结构化输出后端(xgrammar/llguidance)会被完全绕过,语法约束不再生效。优先排查是否使用了 Gemma 4 E4B 等小模型(其 chat template 不会自动插入空 Reasoning 块),或改用 reasoning_effort: "none" 参数。

问题场景

用户在使用 vLLM 启动 Gemma 4 系列模型(如 google/gemma-4-E4B-itgoogle/gemma-4-26B-A4B-itgoogle/gemma-4-31B-it)时,同时指定了:

  • --reasoning-parser gemma4
  • --enable-auto-tool-choice
  • --default-chat-template-kwargs '{"enable_thinking": false}'
  • --structured-outputs-config '{"backend":"xgrammar"}'

结果发现 JSON Schema、BNF 等结构化输出约束被完全忽略,模型返回不受限制的自由文本。在 vLLM v0.19.0 及更早期版本中均可复现。

报错原文

# 无明显错误日志,但结构化输出不再生效。
# 可以通过性能差异间接发现:相同模型下,启用 parser 后 TPS 显著高于未启用 parser 的情况。

# 例如 E4B FP8 单卡数据,max_parallel=16:
#    with parser: TPS = 65.4, TTFT = 0.302s
#    without parser: TPS = 14.6, TTFT = 0.532s
# 说明 xgrammar 的 bitmask 计算和 FSM 推进被静默跳过了。

原因分析

根因在 vllm/v1/structured_output/__init__.pyshould_fill_bitmask()should_advance() 与 reasoning parser 的交互逻辑。

  1. 触发条件:当 enable_thinking=false 时,输入 prompt 中不包含 <|channel>(start token 100)或 <channel|>(end token 101)任意一个 Thinking 标记。
  2. 判定失效Gemma4ReasoningParser.is_reasoning_end() 在未找到任何标记时返回 False,即认为“推理尚未结束”。
  3. 决策链:结构化输出引擎检查 reasoning_ended = False → 跳过 bitmask 填充和 FSM 推进 → 整个请求不再受语法约束。
  4. 影响范围:xgrammar 和 llguidance 两个后端均受影响。
  5. 模型差异:Gemma 4 的 26B/31B 等大模型的 chat template 会在 enable_thinking=false 时自动插入空 Thinking 块,因此问题不明显。但 E4B(以及 E2B)等小模型不会插入空块,因此问题暴露。

环境排查

  • vLLM 版本:v0.19.0(CI 环境为 vllm/vllm-openai:v0.19.0-x86_64-cu130-ubuntu2404
  • GPU:NVIDIA RTX PRO 6000 Blackwell Server Edition(SM 12.0)
  • OS:Linux 5.15.0-171-generic
  • CUDA:13.0
  • Python:3.12
  • 模型:google/gemma-4-E4B-it(FP8 量化),其它 Gemma 4 变体同理
  • 结构化输出后端:xgrammar(也可选 llguidance)
  • 注意:使用 --speculative-config 时可能引入独立 bug(参见 #34650

解决步骤

  1. 方案一(推荐,当前已知可用):不通过 chat_template_kwargs 禁用 Thinking,而是改用 reasoning_effort API 参数。
    extra_body.update({"reasoning_effort": "none"})
    此方案会触发正确的 Reasoning 状态判断,结构化输出得以生效。
  2. 方案二(适用于 E4B / E2B 小模型):在 Chat Template 层面修改,确保 prompt 中包含空 Thinking 标记。例如可以在调用时通过 chat_template_kwargs 注入 "enable_thinking": false 的同时,手动在模板中添加 <|channel>thought\n<channel|> 前缀。但该方案需要自定义 Template 或模型配置,不是 vLLM 原生行为。
  3. 方案三(vLLM 0.22.0+ 验证):如果启用 Thinking(enable_thinking: True),结构化输出在推理结束后仍无法正确约束最终输出。有用户反馈将 --structured-outputs-config 分别设为 xgrammarguidance 均无法解决。社区认为该问题在 #45588 修复中可能已被解决(需进一步验证)。
  4. 备注:对于启用 Speculative Decoding 时出现的结构化输出失效,可能关联 #34650,建议分开提报。

验证方法

  • 使用 curl 或客户端发送结构化输出请求(如 response_format: { type: "json_object" }),检查返回的内容是否严格遵循 JSON 格式(例如 content 字段是否为合法 JSON)。
  • 对比设置 --reasoning-parser 前后的 TPS(吞吐量)和 TTFT(首 Token 延迟)。如果启用 parser 后 TPS 异常升高(如从 14.6 飙升到 65.4),说明结构化输出被绕过。
  • 检查 vLLM 日志中是否出现 “xgrammar” 相关的 backend 应用记录。
  • 使用 reasoning_effort="none" 后,再次执行相同的结构化输出请求,确认 JSON Schema 被正确校验。

参考来源

vllm-project/vllm #39130

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

celebrityanime
celebrityanime
文章: 8059

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注