Prhub

#45383 [BugFix] Fix prompt_embeds for multimodal models

原始 PR 作者 mrn3088 合并时间 2026-06-14 16:44 文件变更 2 提交数 5 评论 6 代码增减 +53 / -7

执行摘要

修复多模态 prompt_embeds 被覆盖及异步调度兼容问题

关联 Issue #44842 报告了多模态模型设置 prompt_embeds 时崩溃。PR body 指明两种根因:

1) 多模态路径无条件重新 embed(覆盖用户输入);
2) 异步调度下 is_token_ids 标记问题,导致生成退化。

值得精读,尤其是 _preprocess 中巧妙使用 torch.where 避免覆盖用户 embedding 的设计,以及配置层兼容性阻断模式。可与后续 PR #45673 对照阅读,了解如何逐步启用异步调度支持。

讨论亮点

Reviewer @qthequartermasterman 提问:异步调度 + prompt_embeds + 多模态需要哪些额外支持才能工作?作者 @mrn3088 回答:需要另一套 fix 来处理异步调度下的标记问题,已有一个未充分测试的实现,后续以 PR #45673 跟进。

实现拆解

  1. 模型运行器多模态分支保护:在 vllm/v1/worker/gpu_model_runner.py_preprocess 中,当多模态条件成立且 enable_prompt_embeds 且当前 batch 有 prompt_embeds 请求时,对输入 id 做 torch.where 掩码:仅对 is_token_ids=True 的位置执行 embedding gather,并将 prompt_embeds 位置的 placeholder id 置零以防止越界;随后用 torch.where 将新生成的 embedding 写回 inputs_embeds,保留 prompt_embeds 位置原有值。
  2. 配置层兼容性阻断:在 vllm/config/vllm.py__post_init__ 中,如果用户显式启用了异步调度且同时满足 enable_prompt_embedsis_multimodal_model,则抛出 ValueError;如果异步调度为默认(None)且该组合满足,则自动禁用并 warning。
  3. 测试配套:没有新增自动化测试,但 PR 提供了可复现脚本;现有 test_models 文本-only prompt_embeds 测试不变。
文件 模块 状态 重要度
vllm/v1/worker/gpu_model_runner.py 模型运行器 modified 6.88
vllm/config/vllm.py 配置层 modified 6.43

关键符号

GpuModelRunner._preprocess SchedulerConfig.__post_init__

关键源码片段

vllm/v1/worker/gpu_model_runner.py core-logic

核心修复:多模态分支中保护 prompt_embeds 不被覆盖,使用掩码只对 token 位置做 embedding。

# vllm/v1/worker/gpu_model_runner.py ( 关键改动位置 )if self.enable_prompt_embeds and self.input_batch.req_prompt_embeds:
    # 部分位置携带预计算 prompt_embeds:它们已在 self.inputs_embeds 中,
    # 且标记 is_token_ids=False。此处仅对 token-id 位置做 embedding。
    # 先将 placeholder id 置零(防止越界),再通过 torch.where 写回。
    is_token_ids = self.is_token_ids.gpu[:num_scheduled_tokens]
    safe_input_ids = torch.where(
        is_token_ids,
        self.input_ids.gpu[:num_scheduled_tokens],
        0,
    )
    inputs_embeds_scheduled = self.model.embed_input_ids(
        safe_input_ids,
        multimodal_embeddings=mm_embeds,
        is_multimodal=is_mm_embed,
    )
    target = self.inputs_embeds.gpu[:num_scheduled_tokens]
    self.inputs_embeds.gpu[:num_scheduled_tokens] = torch.where(
        is_token_ids.unsqueeze(-1),
        inputs_embeds_scheduled,
        target,
    )
else:
    # 原始逻辑:无 prompt_embeds 时直接覆盖
    inputs_embeds_scheduled = self.model.embed_input_ids(
        self.input_ids.gpu[:num_scheduled_tokens],
        multimodal_embeddings=mm_embeds,
        is_multimodal=is_mm_embed,
    )
    self.inputs_embeds.gpu[:num_scheduled_tokens].copy_(
        inputs_embeds_scheduled
    )

评论区精华

异步调度与多模态 prompt_embeds 的兼容性 question

@qthequartermasterman 询问需要什么额外支持才能启用异步调度。@mrn3088 回复已有一个待测试的实现,将作为后续 PR 跟进。

结论:当前行为:禁用或报错;后续 PR #45673 将提供完整支持。 · 已解决

风险与影响

  1. 核心路径变更:修改了 _preprocess,可能影响其他多模态模型的 embedding 生成路径,但变更仅当 enable_prompt_embeds=True 且 batch 包含 prompt_embeds 请求时触发,风险可控。
  2. 功能默认降级:异步调度被自动禁用,可能降低吞吐量,但这是临时方案;用户若显式启用会硬错误,避免静默退化。
  3. 缺少测试覆盖:没有针对多模态 prompt_embeds 的自动化回归测试,依赖手动验证。

直接使用 prompt_embeds 的多模态用户从 EngineCore 崩溃或错误输出变为正确结果;文本-only prompt_embeds 用户不受影响;使用异步调度 + 多模态 prompt_embeds 的用户会收到警告或错误提示,之后可升级到后续 PR #45673 获得完整支持。

核心路径变更 功能默认降级(异步调度禁用) 缺少自动化测试覆盖

关联 Issue

#44842 [Bug]: Setting prompt_embeds does not work for vision-language models

完整报告

参与讨论