![[Bug]: GPT-OSS Harmony: vLLM silently returns `content: null` with `finish_reason="stop"` when its parser ends in a non-terminal state](https://www.chat-gpts.plus/wp-content/uploads/2026/07/45736-079cc018.jpg)
[Bug]: GPT-OSS Harmony: vLLM silently returns `content: null` with `finish_reason=”stop”` when its parser ends in a non-terminal state
快速结论:当 GPT-OSS Harmony 模型生成的消息流缺少 “ 分隔符时,vLLM 不抛出异常、不记录日志,直接返回 HTTP 200,且 `content: null`、`finish_reason=”stop”`,完整丢弃已生成的 tokens。优先排查 HarmonyParser 是否在生成结束前调用了 `process_eos()` 并检查 parser 最终状态。
问题场景
用户在 vLLM 中部署 GPT-OSS Harmony 模型(基于 HarmonyEncodingName.HARMONY_GPT_OSS 编码),通过 OpenAI 兼容的 API 发送请求。当模型采样输出格式错误的 assistant turn(例如省略了 “ 标记)时,vLLM 未能检测到 parser 处于非终态(non-terminal state),静默返回空内容。
报错原文
HTTP 200 with content: null, non-empty reasoning, finish_reason="stop", and completion_tokens > 0
原因分析
核心问题:vLLM 的 HarmonyParser 在单次 token 处理(`process()`)结束后,未调用 `process_eos()` 也未检查 parser 的最终状态(`StreamState`)。当模型输出缺少 “ 分隔符(例如 `…final {“answer”: “hi”}`),parser 停留在 `HEADER` 状态(非终态),但 vLLM 仍将此视为正常生成终止,返回 `finish_reason=”stop”`。
触发条件:GPT-OSS 模型在约 1% 的请求中省略了 “ 标记(id 200008)。典型格式对比:
- 格式正确:`…final{body}` → parser 进入 `EXPECT_START`(终态)
- 格式错误:`…final {body}` → parser 停留在 `HEADER`(非终态)
衍生讨论:Issue 中进一步探讨了更通用的 parser 错误处理方案(将 `finish_reason` 设为 `”error”` 或返回恢复后的文本),但尚未形成最终决策。当前修复应优先确保 HarmonyParser 检测并上报非终态。
环境排查
- vLLM 版本:0.1.dev1+g477587cd7(git SHA: 477587cd7)
- PyTorch 版本:2.11.0+cu130
- CUDA 版本:13.0.88,驱动版本 595.71.05
- GPU 配置:8x NVIDIA H100 80GB HBM3
- 依赖库:openai-harmony(`HarmonyEncodingName`, `StreamableParser`),transformers==5.10.2
- 系统:Ubuntu 22.04.5 LTS,Python 3.12.13
解决步骤
- 确认 parser 状态检查缺失:检查 `vllm/parser/harmony.py` 中 `HarmonyParser.process_chunk()` 方法,确认在生成序列结束后是否调用 `process_eos()` 或主动检查 `parser.state` 是否为终态(如 `StreamState.EXPECT_START`)。
- 添加终态校验(Issue #45796 方案):在 parser 层暴露非终态检测:
- 在 `process_eos()` 中检查状态,若非终态则抛出 `ValueError` 或返回特殊标记。
- 不要同时在 parser 和服务层记录日志——日志应统一在服务层处理。
- 服务层捕获并处理(端到端修复):
- 在 `parse()` 和 `parse_delta()` 方法中捕获 parser 异常。
- 设置 `finish_reason=”error”`(或待定的 `”parser_error”`),并返回恢复后的文本(如从 recipient 字段提取)。
- 注意:当前 OpenAI 标准 `finish_reason` 集合中不包含 `”error”`,兼容性需社区对齐。
- 编写回归测试:使用 Issue 中提供的 reproducer 验证两种场景:
- 格式完整(`final…`)→ 正常返回
- 格式错误(省略 “)→ 不返回 `content: null` 和 `finish_reason=”stop”`
- 可优先尝试的临时方案:如果暂时无法修改 vLLM 核心逻辑,可在上层应用中对返回结果为 `content: null` 但 `completion_tokens > 0` 的情况进行二次校验。
验证方法
- 单元测试:运行 Issue 中提供的 `end_state()` 函数,确认格式错误输入下 parser 状态为 `StreamState.HEADER`,而非 `StreamState.EXPECT_START`。
- 集成测试:通过 vLLM 的 OpenAI 兼容 API 发送触发 malformed 输入的请求(使用特定 sampling 参数复现约 1% 概率),检查响应中是否不再出现 `content: null` 且 `finish_reason` 被正确设为 `”error”`(或抛出异常)。
- 日志检查:确认在服务层有且仅有一次针对 parser 非终态的错误日志记录。
参考来源
vllm-project/vllm #45736 — 原始 Issue 讨论,包含完整的环境信息、复现代码、原因分析和社区讨论。



