Prhub

#38545 [Bugfix] Use dedicated MM processor cache in /tokenize to prevent sender-cache pollution

原始 PR 作者 sergey-zinchenko 合并时间 2026-04-02 12:14 文件变更 4 提交数 12 评论 16 代码增减 +187 / -19

执行摘要

修复 /tokenize 端点多模态缓存污染导致后续聊天请求失败的 bug。

修复 issue #38543 中报告的 bug:在多模态场景下,调用 /tokenize 后立即调用 /v1/chat/completions 会因多模态特征缓存污染导致内部服务器错误。PR body 明确指出该问题影响 Qwen/Qwen2.5-VL-3B-Instruct 等模型,并旨在通过隔离缓存来避免 stale sender-cache entries。

建议精读此 PR,关注其如何通过隔离缓存解决多模态状态污染问题,以及参数传递方式的设计权衡(字典标志 vs. 显式参数)值得学习。适合前端服务和多模态开发工程师参考,以理解缓存管理和 API 端点交互。

讨论亮点

DarkLight1337 建议使用单独的处理器而非修改缓存行为,认为原方案 'feels too hacky'。Sergey-zinchenko 对比了两种参数传递方式:通过字典标志(diff 小但 hacky)或显式参数(类型安全但 boilerplate 多),最终采纳显式参数方案,DarkLight1337 同意以避免污染提示格式。其他讨论包括移除冗余测试和简化代码,如撤销对 cache_read_only 参数的修改。

实现拆解

vllm/renderers/base.pyBaseRenderer 初始化时,使用 mm_registry.processor_only_cache_from_config(config) 创建第二个多模态处理器 _readonly_mm_processor,拥有独立的只读缓存。在 _process_multimodal_process_tokens 等方法中添加 skip_mm_cache 参数,当为 True 时使用只读处理器。在 vllm/entrypoints/serve/render/serving.pypreprocess_completionpreprocess_chat 中添加并传递该参数;在 vllm/entrypoints/serve/tokenize/serving.pycreate_tokenize 中调用时传入 skip_mm_cache=True,确保 tokenize 请求路由到只读处理器。

文件 模块 状态 重要度
tests/entrypoints/serve/tokenize/test_tokenize_then_chat_vlm.py testing added 5.0
vllm/renderers/base.py renderers modified 8.0
vllm/entrypoints/serve/render/serving.py serve/render modified 6.0
vllm/entrypoints/serve/tokenize/serving.py serve/tokenize modified 6.0

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

关键符号

BaseRenderer.__init__ BaseRenderer._process_multimodal BaseRenderer._process_tokens BaseRenderer._process_tokens_async preprocess_completion preprocess_cmpl preprocess_chat create_tokenize

评论区精华

缓存隔离方案选择 设计

DarkLight1337 认为原方案使用 ContextVar 绕过缓存太 hacky,建议创建单独处理器;Sergey-zinchenko 讨论并实施创建只读处理器的方案。

结论:采纳创建只读处理器实现缓存隔离,避免修改现有缓存行为。 · 已解决

参数传递方式权衡 设计

Sergey-zinchenko 比较了通过字典标志(如 prompt_extras)或显式参数传递 skip_mm_cache 的优缺点,后者类型安全但需更多 boilerplate。

结论:使用显式参数传递,避免污染提示格式,保持代码清晰。 · 已解决

测试冗余性处理 测试

DarkLight1337 建议移除测试中的冗余客户端代码,保持测试简洁。

结论:移除冗余测试部分,保留核心回归测试逻辑。 · 已解决

风险与影响

主要风险:新增只读处理器可能略微增加内存开销,尤其在加载多模态模型时;缓存隔离的彻底性需确保 tokenize 端点永不写入主发送器缓存,否则污染可能复发。性能影响微小,因只读处理器共享相同逻辑但使用独立缓存,但参数传递链的扩展可能引入维护复杂性。

对用户影响:修复了一个关键 bug,使用多模态模型时 tokenize 和聊天请求序列能正常工作,提升用户体验和可靠性。对系统影响:引入额外处理器实例,但缓存隔离避免状态污染,增强系统鲁棒性;新增测试覆盖了该场景,防止回归。对团队影响:展示了通过隔离缓存解决状态污染的设计模式,为类似问题提供参考。

缓存隔离风险 内存开销增加 参数传递复杂性

关联 Issue

#38543 [Bug]: Failed to call /chat/completions after /tokenize for same multimodal query

完整报告

PR 38545 分析报告

执行摘要

本 PR 修复了 vLLM 中一个关键 bug:当用户使用相同多模态输入(如图片)先后调用 /tokenize/v1/chat/completions 端点时,后者会因多模态缓存污染而失败。通过为 tokenize 端点创建专用的只读多模态处理器,实现缓存状态隔离,彻底解决问题,并新增回归测试确保修复可靠。

功能与动机

此变更旨在解决 issue #38543 中报告的 bug:在多模态场景下(例如使用 Qwen/Qwen2.5-VL-3B-Instruct 模型),调用 /tokenize 端点执行多模态预处理后,残留的发送器缓存条目导致后续 /v1/chat/completions 请求失败。PR body 明确说明需“创建第二个 BaseMultiModalProcessor 拥有自己的 processor_only_cache”,以实现完整隔离,避免共享可变状态。

实现拆解

实现方案围绕缓存隔离展开,关键改动点如下:

  • vllm/renderers/base.py:在 BaseRenderer__init__ 方法中,使用 mm_registry.processor_only_cache_from_config(config) 创建 _readonly_mm_processor,拥有独立只读缓存;在 _process_multimodal_process_tokens 等方法中添加 skip_mm_cache 参数,控制使用主处理器或只读处理器。
  • vllm/entrypoints/serve/render/serving.py:在 preprocess_completionpreprocess_chat 函数中添加 skip_mm_cache 参数,并通过调用链传递到渲染器。
  • vllm/entrypoints/serve/tokenize/serving.py:在 create_tokenize 函数中调用预处理时传入 skip_mm_cache=True,确保 tokenize 请求使用只读处理器。
  • 新增测试文件tests/entrypoints/serve/tokenize/test_tokenize_then_chat_vlm.py 提供回归测试,验证修复效果。

关键代码示例(来自 base.py):

if skip_mm_cache and self._readonly_mm_processor is not None:
    mm_processor = self._readonly_mm_processor
else:
    mm_processor = self.get_mm_processor()

评论区精华

Review 讨论中聚焦于设计权衡:

  • 缓存隔离方案:DarkLight1337 指出原方案“feels too hacky”,建议使用单独处理器;Sergey-zinchenko 实施后采纳此建议。
  • 参数传递方式:Sergey-zinchenko 比较了通过字典标志(如 prompt_extras)与显式参数的优劣,最终选择显式参数,因“type-safe and explicit”,避免污染引擎核心不需要的参数。DarkLight1337 支持此决策:“I don't want to overload the prompt format”。
  • 测试简化:DarkLight1337 建议移除冗余测试代码,Sergey-zinchenko 相应调整,保持测试聚焦。

风险与影响

技术风险

  • 缓存隔离不彻底可能导致污染复发,需确保只读处理器永不写入主缓存。
  • 新增处理器实例增加内存开销,尤其在多模态模型加载时。
  • 参数传递链扩展引入维护复杂性,但通过显式参数降低错误风险。

影响评估

  • 用户:修复 bug 后,多模态 tokenize 和聊天请求序列能正常工作,提升体验可靠性。
  • 系统:轻微性能开销,但缓存隔离增强鲁棒性,避免状态污染导致的服务器错误。
  • 团队:新增测试覆盖关键场景,防止回归;设计决策为类似缓存问题提供参考模式。

关联脉络

本 PR 直接关联 issue #38543,是针对性修复。从同仓库近期历史 PR 分析中,未发现直接相关 PR(如相同文件或功能线),但可观察到多模态和前端标签的 PR(如 #38714)表明 vLLM 在多模态支持上的持续演进。此修复强化了前端服务中缓存管理的健壮性,符合系统对可靠性和隔离性的要求。

参与讨论