Prhub

#6998 [Optimization]Streaming requests return complete special tokens.

PaddlePaddle/FastDeploy · 作者 luukunn · 合并时间 2026-03-26 09:49

分析状态 已生成
文件变更 4提交数 8 · 评论 10
代码增减 +36 / -33
Optimization APIServer test

执行摘要

优化 streaming 请求,在 skipped 时仍返回完整 token ids 以支持特殊 tokens。

根据 review 评论,动机是优化 streaming 响应,使特殊 token 或完整 token 流在 skipped 场景下不丢失。具体表述为:'优化 OpenAI 兼容的 streaming 响应:当引擎输出被标记为 skipped 时,如果客户端开启 return_token_ids,仍然返回对应的 token ids(从而让“特殊 token/完整 token 流”在 streaming 场景下不丢失)。'

建议技术管理者关注此 PR,因为它涉及核心 streaming 逻辑的优化,对 token ids 完整性有重要意义。工程师可以精读 serving_chat.py 和 serving_completion.py 的改动,学习如何在 skipped 场景下处理 token ids,并注意测试用例的更新以避免回归。

讨论亮点

Review 中,Copilot 指出了几个关键点:1) 多模态内容结构问题:当 skipped 为 True 且启用 multimodal 输出时,delta_message.multimodal_content 应返回结构一致的占位项(如 [{"type": "text", "text": ""}]),避免破坏客户端解析;2) 测试覆盖不足:现有测试未覆盖 skipped=True 的场景,建议补充以确保回归;3) PR 描述和标题格式不完整,影响回溯。最终,reviewer LiqinruiG 批准了变更,但部分建议未明确采纳。

实现拆解

实现主要涉及两个核心文件:fastdeploy/entrypoints/openai/serving_chat.py 和 serving_completion.py。在 chat_completion_stream_generator 和 completion_stream_generator 函数中,添加条件判断 if output["skipped"] and not request.return_token_ids: continue,确保仅当 skipped 为 True 且 return_token_ids 为 False 时才跳过输出;否则设置 delta_message 的内容为空字符串(如 text="" 或 multimodal_content 占位项)但保留 completion_token_ids。此外,将 tool_calls 的检测逻辑提前,以便正确影响 finish_reason。测试文件同步更新了 token 计数逻辑,以匹配变更后的行为。

文件 模块 状态 重要度
fastdeploy/entrypoints/openai/serving_chat.py entrypoints/openai modified 5.0
fastdeploy/entrypoints/openai/serving_completion.py entrypoints/openai modified 5.0
tests/e2e/test_EB_VL_Lite_serving.py tests/e2e modified 3.0
tests/e2e/test_EB_VL_Lite_sot_serving.py tests/e2e modified 3.0

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

关键符号

chat_completion_stream_generator completion_stream_generator

评论区精华

多模态内容结构一致性 设计

Copilot 指出当 skipped 为 True 且启用 multimodal 输出时,delta_message.multimodal_content 应返回结构一致的占位项,建议使用 [{"type": "text", "text": ""}] 以避免破坏客户端解析。

结论:建议给出,但 PR 中未明确采纳或讨论,后续需验证是否修复。 · suggested

测试覆盖不足 测试

Copilot 建议补充 skipped=True 的测试场景,以覆盖 return_token_ids=True/False 的情况,避免回归,但现有测试更新可能未完全覆盖。

结论:测试文件已部分更新,但建议未在 PR 中明确回应,状态为部分处理。 · partially_addressed

PR 描述和标题格式 documentation

Copilot 指出 PR 描述未填写,标题格式不规范(缺少空格),影响回溯和验证。

结论:未在 PR 中修复,PR 已合并,状态为忽略。 · ignored

风险与影响

技术风险包括:1) 响应格式变更风险:修改了核心 streaming 逻辑,可能导致客户端解析错误,特别是在多模态内容结构不一致时(如 serving_chat.py 中 skipped 时的 multimodal_content 可能缺少必要字段);2) 测试覆盖风险:新增逻辑未在单元测试中充分覆盖 skipped=True 场景,可能引入回归;3) 兼容性风险:如果现有客户端依赖 skipped 时跳过输出的行为,改变后可能需调整。

对用户的影响:使用 streaming 并开启 return_token_ids 的客户端现在能获得更完整的 token 流,便于处理特殊 tokens,提升调试和监控能力。系统影响:优化了 OpenAI 兼容的响应生成,但需确保所有 endpoint 行为一致,避免格式错误。团队影响:代码变更较小,但需关注测试更新和维护,以及潜在的多模态结构问题。

核心路径变更 缺少测试覆盖 多模态结构风险

关联 Issue

未识别关联 Issue

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

完整报告

执行摘要

本 PR 优化了 FastDeploy 中 OpenAI 兼容的 streaming 请求处理,确保在引擎输出被跳过(skipped)时,如果客户端开启 return_token_ids,仍能返回完整的 token ids,从而支持特殊 tokens 的处理。变更涉及核心响应生成逻辑和测试更新,提升 token 流的完整性。

功能与动机

动机源于提升 streaming 场景下 token ids 的完整性。当引擎输出被标记为 skipped 时,默认会跳过该帧,但若客户端开启 return_token_ids,仍需返回对应的 token ids 以避免丢失特殊 tokens。review 中 Copilot 指出:"优化 OpenAI 兼容的 streaming 响应:当引擎输出被标记为 skipped 时,如果客户端开启 return_token_ids,仍然返回对应的 token ids(从而让‘特殊 token/完整 token 流’在 streaming 场景下不丢失)。" PR body 未填写具体动机,但代码变更和 review 讨论明确了这一目标。

实现拆解

主要改动集中在两个文件:

  • fastdeploy/entrypoints/openai/serving_chat.py:修改 chat_completion_stream_generator 函数,添加条件判断 if output["skipped"] and not request.return_token_ids: continue,并调整 delta_message 内容,例如设置 content="" if output["skipped"] else (output["text"] or "")multimodal_content 占位项。
  • fastdeploy/entrypoints/openai/serving_completion.py:类似修改 completion_stream_generator 函数,确保在 skipped 时返回空 text 但保留 token_ids。
    关键代码逻辑示例:
if output["skipped"] and not request.return_token_ids:
    continue
delta_message = DeltaMessage(
    content="" if output["skipped"] else (output["text"] or ""),
    completion_token_ids=output.get("token_ids") if request.return_token_ids else None
)

此外,将 tool_calls 检测提前,以正确影响 finish_reason。测试文件(如 tests/e2e/test_EB_VL_Lite_serving.py)同步更新了 token 计数逻辑,从固定值调整为动态计算,以匹配变更后的行为。

评论区精华

Review 讨论中,Copilot 提出了重要建议:

  • 多模态结构问题:"当启用 multimodal 输出且 output['skipped'] 为 True 时,这里把 delta_message.multimodal_content 设为 [{}] 会导致返回的 multipart item 缺少上游约定的字段...建议在 skipped 时也返回一个结构一致的占位项(例如 type/text 为空字符串)。" 这凸显了设计权衡,需确保客户端兼容性。
  • 测试覆盖:"现有 tests/entrypoints/openai/test_serving_completion.py 的 streaming 用例只覆盖 skipped=False,建议补充 skipped=True 的场景(分别覆盖 return_token_ids=True/False),以避免后续回归。" 表明测试需跟进以保障代码质量。
  • 文档规范:"PR 标题建议严格遵循模板要求的 [标签] Title 格式...本 PR 描述仍是模板占位,缺少 Motivation/Modifications/Usage 等关键信息。" 最终,reviewer LiqinruiG 以 "LGTM" 批准,但部分建议未明确解决。

风险与影响

风险

  • 响应格式变更风险:修改了核心 streaming 逻辑,可能导致客户端解析错误,特别是在多模态内容结构不一致时(serving_chat.py 中 skipped 时的 multimodal_content 可能缺少 typetext 字段)。
  • 测试覆盖风险:新增逻辑未在单元测试中充分覆盖 skipped=True 场景,Codecov 报告显示有 2 行缺失覆盖,可能引入回归。
  • 兼容性风险:如果现有客户端依赖 skipped 时完全跳过输出的行为,改变后可能需要调整处理逻辑。
    影响

  • 用户影响:使用 streaming 并开启 return_token_ids 的客户端能获得更完整的 token 流,便于调试、监控和处理特殊 tokens,提升用户体验。

  • 系统影响:优化了 OpenAI 兼容的响应生成,但需确保所有 endpoint(chat 和 completion)行为一致,避免格式错误导致下游问题。
  • 团队影响:代码变更较小,但需关注测试更新和维护,以及潜在的多模态结构问题,建议在后续 PR 中补充测试。

关联脉络

从历史 PR 分析中,近期有其他优化和 bugfix 涉及 streaming 或 OpenAI endpoint(如 PR 6680 优化调度,PR 7042 更新 API server 配置),但未发现直接关联本 PR 的修改文件或功能线。本 PR 专注于 streaming token ids 的完整性,是 OpenAI 兼容性优化的一部分,可能为后续相关特性(如特殊 tokens 处理)奠定基础。关联的 cherry-pick PR(7040、7041)表明此变更已反向移植到 release 分支,影响范围扩展至稳定版本。

参与讨论