Prhub

#50624 docs: document `reasoning_content` output removal as a breaking client change

原始 PR 作者 fede-kamel 合并时间 2026-08-03 21:45 文件变更 1 提交数 5 评论 7 代码增减 +2 / -1

执行摘要

文档化 reasoning_content 输出移除的客户端破坏性变更

reasoning_content 先被重命名为 reasoning(RFC #27755、PR #27752),随后在 PR #33402 中从输出侧完全移除;但输入侧仍通过 PR #42664 接受 reasoning_content 并规范化为 reasoning。PR body 指出,现有文档的一行警告("To migrate, directly replace reasoning_content with reasoning")低估了影响:读取 delta.reasoning_content 的客户端会静默得到 None,思维链在无任何报错的情况下丢失。作者用实弹数据证明输出侧 0 个 chunk 携带 reasoning_content,并以 tulip-agents(开源 agent 框架)踩坑为例,说明需要把这种不对称性作为破坏性变更显性化。

值得快速阅读(约 5 分钟)。它展示了 API 演进中输入/输出不对称导致兼容性坑的真实案例,以及维护者对“文档该写多详细”的取舍——轻量合入、详细背景留 PR body。对负责 OpenAI 兼容层和维护推理输出的工程师,建议关注 getattr 替代 hasattr 的技术细节(pydantic extra field 陷阱),它在其他未声明字段的场景同样适用。

讨论亮点

hmellor 作为 maintainer 提出 4 条 suggestion,核心交锋围绕“这份 breaking change 提示应该写多详细”:

  • 用 getattr 而非 hasattr:hmellor 指出 OpenAI SDK 把 reasoning 存在 pydantic 的 extra-field storage 中,直接访问 delta.reasoning 在字段缺失的 chunk(如首个仅含 role 的 chunk)上会抛 AttributeError,建议用 getattr 并补充详细解释。该建议的核心技术细节被采纳,但最终合入的是简短措辞版本,AttributeError 场景的详细说明未进入最终文档。
  • 建议新增“Client compatibility”小节:hmellor 给出了完整的输入/输出不对称表格和双字段名读取示例文案,主张把静默破坏性变更写得更清楚;最终未合入最终 diff,仅以 warning 内一行提示形式呈现,说明维护者倾向轻量表达,详细背景留给 PR body。
  • warning 措辞补充:hmellor 建议在 warning 中明确“必须同时更新客户端代码,否则会静默读到空的 reasoning_content”,已被采纳并成为最终合并的新增行。

实现拆解

  1. 变更入口:唯一改动文件为 docs/features/reasoning_outputs.md,纯文档,无源码、测试、配置或部署配套改动(+2/-1)。
  2. warning 段落补充:在原有的 reasoning 命名迁移警告之后新增一行说明——必须同时更新客户端代码,否则客户端会在 reasoning 已填充的情况下从 reasoning_content 读到空值,思维链静默丢失。这一行直接回应 PR body 中“诊断的静默破坏性变更”问题。
  3. 流式示例修正:将 OpenAI Python SDK 流式读取示例从 hasattr 改为 getattr。原因是 reasoning 字段未被 SDK 声明,落在 pydantic 的 extra field 中,直接访问在字段缺失的 chunk 上会抛 AttributeErrorhasattr 同样不可靠。
  4. Review 演进:hmellor 提出 4 条 suggestion,其中“新增 Client compatibility 章节(含输入/输出不对称表格与双字段名防御性读取示例)”的较大篇幅建议最终未合入,合入版本保持轻量;提交历史中包含两次 merge main 和两次采纳 suggestion 的提交,保证与主干同步。
文件 模块 状态 重要度
docs/features/reasoning_outputs.md 功能文档 modified 1.99

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

hasattr 改为 getattr 及 pydantic extra field 陷阱 documentation

hmellor 指出 OpenAI Python SDK 未声明 `reasoning` 字段,字段落在 pydantic 的 extra-field storage 中;直接访问 `delta.reasoning` 在字段缺失的 chunk(如首个仅含 role 的 chunk)上会抛 `AttributeError`,`hasattr` 同样不可靠,建议改用 `getattr`。

结论:已采纳 getattr 建议并合入最终文档,但最终采用简短措辞,hmellor 提供的详细解释(AttributeError 场景)未进入最终 diff。 · 已解决

是否新增 Client compatibility 章节 设计

hmellor 建议新增独立小节,用表格呈现输入 / 输出不对称(输出只含 `reasoning`、输入仍接受 `reasoning_content` 并规范化为 `reasoning`),并配双字段名防御性读取示例,把静默破坏性变更写清楚。

结论:未合入最终 diff(最终仅 +2/-1),改为在 warning 内加一行提示,说明维护者倾向轻量表达。 · not merged(未合入)

warning 中提醒客户端必须更新 documentation

hmellor 建议在 warning 中补充说明:必须同时更新客户端代码,否则会在 `reasoning` 已填充的情况下从 `reasoning_content` 读到空值、思维链静默丢失。

结论:已采纳,成为最终合并的新增行。 · 已解决

风险与影响

本 PR 为纯文档变更(+2/-1),无代码、无测试、无 CI 影响,回归风险极低。主要风险是文档准确性维护:warning 中“客户端会静默读到空 reasoning_content”的描述基于 PR body 的实测(310 个流式 chunk 中 0 个携带 reasoning_content),若未来服务端恢复输出兼容,该提示会过时,需要持续跟 API 契约同步。另外,最终合入版本未包含防御性读取示例,对不熟悉 pydantic extra field 的开发者来说,仍可能踩 AttributeError 的坑;文档也未覆盖 Responses API 等其它入口的同类问题。

影响对象是所有通过 OpenAI 兼容接口消费 reasoning 输出的第三方客户端,尤其是 streaming 场景下读取 delta.reasoning_content 的 agent 框架(如 tulip-agents)。该 PR 把此前仅存在于代码行为中的隐性风险显性化为文档警告,能显著降低下游开发者的排障成本。对 vLLM 团队而言,这是一次低成本、高杠杆的契约治理动作,后续需要跟进 API 契约变化以保持文档准确。

纯文档变更 静默破坏性变更提示 文档需与 API 契约同步

关联 Issue

#51 feat: surface Qwen/vLLM chain-of-thought as reasoning
#27755 [RFC]: `reasoning_content` -> `reasoning`

完整报告

参与讨论