[Bug]: thinking_token_budget not enforced on re-entry after natural

用户在使用 vLLM 推理引擎时,启用了 thinking_token_budget 配置参数(用于限制模型在 块中的推理 token 数量),且模型在一个 completion 内可能输出多个 块。当模型在第一个 thinking 块自然结束时(主动输出 </thi

[Bug]: thinking_token_budget not enforced on re-entry after natural

[Bug]: thinking_token_budget not enforced on re-entry after natural

快速结论:当模型在同一个 completion 中自然结束一个 thinking 块(输出 </think>)后又开启第二个 <think> 块时,thinking_token_budget 不会生效,导致第二个 thinking 块可以无限推理。优先排查是否运行在 vLLM 最新 main 分支,并检查 PR #43757 是否已合入。

问题场景

用户在使用 vLLM 推理引擎时,启用了 thinking_token_budget 配置参数(用于限制模型在 <think> 块中的推理 token 数量),且模型在一个 completion 内可能输出多个 <think> 块。当模型在第一个 thinking 块自然结束时(主动输出 </think> 而非被预算强制截断),再开启第二个 thinking 块时,预算控制完全失效。

报错原文

Block 2 should be budget-enforced after 14 tokens (budget=10), but in_end=False

实际表现为:第二个 thinking 块可以输出任意数量的 token,thinking_token_budget 不会触发强制结束。

原因分析

确定原因:vLLM 的 ThinkingBudgetStateHolder 状态机在处理自然结束的 thinking 块时存在状态残留问题。具体来说:

  • 自然结束的 thinking 块不会更新 scan_offset(起始扫描位置),该值保持为 0。
  • 状态变量 start_thinkingend_thinking 也不会被重置,仍然指向第一个 thinking 块的位置。
  • 当第二个 <think> 出现时,_find_last_sequence_index 从位置 0 开始搜索,找到的是第一个 thinking 块的 start_thinking,且因为 start_thinking (0) < end_thinking (7),状态机误判为“正在退出 thinking 模式”,导致第二个 thinking 块永远不会被识别为进入 thinking 模式。

对比已修复的强制结束情况(#43757):强制截断后会更新 scan_offset 和重置状态变量,所以重新进入 thinking 块能被正确检测。

环境排查

  • vLLM 版本:确认是否在 vllm/vllm-openai:latest 或最新 main 分支上(问题仍存在)。
  • 确认启用了 thinking_token_budget 配置,且模型能够生成多个 thinking 块。
  • 检查 PR #43757 是否已合入(该 PR 修复了强制结束后的重新进入问题,但未覆盖自然结束的情况)。

解决步骤

以下修复方案来自 Issue 讨论,已经作者本地验证通过(Docker 环境测试:修复前 3/5 测试用例失败,修复后全部通过):

  1. 修改 _find_last_sequence_index 的搜索起点:将其搜索范围改为从 scan_offset 开始,而不是从 0 开始。
  2. 自然结束时的状态重置:当检测到自然结束(start_thinking < end_thinking 或仅找到 end_thinking)时,重置以下状态变量:start_thinking = -1end_thinking = -1continue_thinking = False,并将 scan_offset 更新为当前输出 token 数量。
  3. 强制结束时的状态重置:在强制结束路径(END_COMPLETE)中应用相同的重置逻辑(PR #43757 中已有,扩展其适用范围)。
  4. (可选)使用 had_forced_end 标志:另一种实现方案是在状态字典中新增布尔标志 had_forced_end,用于区分自然结束和强制结束,以决定强制结束后的新 thinking 块是否需要立即被截断。但作者认为直接用 scan_offset 足够,无需新增标志。

验证方法

运行 Issue 中提供的单元测试代码(test_natural_end_reentry.py),验证以下场景全部通过:

  • 自然结束 + 单 token 重新进入
  • 自然结束 + 多 token 重新进入
  • 强制结束场景(回归测试)
  • 两个无回归测试(确保原有逻辑未被破坏)

此外,可通过实际推理测试确认模型在第二个 thinking 块时确实被预算截断(输出 token 数不超过 thinking_token_budget)。

参考来源

vllm-project/vllm #45974

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 12505

发表回复

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