# PR #50777 完整报告

- 仓库：`vllm-project/vllm`
- 标题：[Bugfix] Default Gemma3 Model intermediate_tensors to None
- 合并时间：2026-08-04 03:07
- 原文链接：http://prhub.com.cn/vllm-project/vllm/pull/50777

---

# 执行摘要

- 一句话：Gemma3 模型 intermediate_tensors 补默认值，修复 pooling 启动失败
- 推荐动作：值得快速阅读：单行改动修复了模型签名契约不一致，展示了默认值约定对 compiled forward 绑定路径的重要性；关联 #48290 的 Model Runner V2 迁移脉络，可作为理解 V2 编译绑定的入门案例。

# 功能与动机

PR body 指出 Gemma3Model.forward 将 intermediate_tensors 声明为必填位置参数，而其他可 pooling 模型（如 BertModel）均默认其为 None；pooling 路径等从不产生 intermediate tensors 的调用方会省略该参数，V2 Model Runner 编译 forward 绑定时报 TypeError: missing a required argument: 'intermediate_tensors'。该问题由 #48290 的 CI 暴露：embeddinggemma-300m 解析为 attn_type=encoder_only 后进入 Model Runner V2 路径，在 Language Models Test (MTEB) 的引擎初始化阶段失败。因此本修复是 landing #48290 的前置条件。

# 实现拆解

1. 根因定位：对比 Gemma3Model.forward 与 BertModel 等模型的签名，确认唯一差异是 intermediate_tensors 没有默认值，导致 compiled forward 在 bind_locals 阶段无法匹配参数。
2. 签名修正：在 vllm/model_executor/models/gemma3.py 中为该参数补上 = None，使签名变为 intermediate_tensors: IntermediateTensors | None = None，与仓库内 pooling 模型的约定一致。内部 assert intermediate_tensors is not None 的逻辑保持不变，非首 PP rank 仍强制要求显式传入，未改变流水线并行语义。
3. 验证方式：手动用 VLLM_USE_V2_MODEL_RUNNER=1 加载 google/embeddinggemma-300m 进行 pooling，输出 ENGINE_STARTED_OK 且 embedding 维度为 768；并运行 tests/models/language/generation/test_gemma.py 确认生成路径无回归（其中 test_dummy_loader 的失败在改动前后均存在，属既有问题）。pre-commit 检查通过。未新增自动化测试文件，属于单行签名契约修复。

关键文件：
- `vllm/model_executor/models/gemma3.py`（模块 模型层；类别 source；类型 data-contract；符号 Gemma3Model.forward）: 唯一变更文件，修复 Gemma3Model.forward 签名契约，使 intermediate_tensors 可省略，解除 pooling + V2 路径的启动失败。

关键符号：Gemma3Model.forward

## 关键源码片段

### `vllm/model_executor/models/gemma3.py`

唯一变更文件，修复 Gemma3Model.forward 签名契约，使 intermediate_tensors 可省略，解除 pooling + V2 路径的启动失败。

修复后的 Gemma3Model.forward 方法核心逻辑如下，注意默认值与 PP 语义的配合：

```python
def forward(
    self,
    input_ids: torch.Tensor | None,
    positions: torch.Tensor,
    # 与 BertModel 等可 pooling 模型保持一致的签名约定：默认 None。
    # pooling 路径等调用方从不产生 intermediate tensors，会省略该参数；
    # 若无默认值，V2 Model Runner 编译 forward 绑定参数时会直接抛
    # TypeError: missing a required argument。
    intermediate_tensors: IntermediateTensors | None = None,
    inputs_embeds: torch.Tensor | None = None,
    **kwargs,
) -> torch.Tensor | IntermediateTensors:
    # 首 PP rank 从 embed 结果构造 hidden_states，
    # 非首 rank 则必须依赖上游 rank 传下来的 intermediate_tensors。
    if get_pp_group().is_first_rank:
        if inputs_embeds is not None:
            hidden_states = inputs_embeds
        else:
            hidden_states = self.embed_input_ids(input_ids)
        residual = None
    else:
        # 防御性断言保留：非首 rank 仍强制要求 intermediate_tensors 非空。
        assert intermediate_tensors is not None
        hidden_states = intermediate_tensors["hidden_states"]
        residual = intermediate_tensors["residual"]
    for layer in islice(self.layers, self.start_layer, self.end_layer):
        hidden_states, residual = layer(
            positions,
            hidden_states,
            residual,
            **kwargs,
        )
    # 非末 rank 继续把 hidden_states 与 residual 封装后传给下一段。
    if not get_pp_group().is_last_rank:
        return IntermediateTensors(
            {"hidden_states": hidden_states, "residual": residual}
        )
    hidden_states, _ = self.norm(hidden_states, residual)
    return hidden_states

```

# 评论区精华

维护者 yewentao256 在 gemma3.py 上提出唯一一条 review 意见：建议去掉默认值旁的说明注释，只保留 intermediate_tensors: IntermediateTensors | None = None,，原话为 "We don't need the comment here"。作者采纳并更新提交，最终合并版本为无注释的单行改动。其余评论为维护者的致谢与 LGTM，没有技术争议。

- 去掉 intermediate_tensors 默认值旁的冗余注释 (style): 作者接受建议，后续提交移除注释，最终合并版本为无注释的单行改动。

# 风险与影响

- 风险：改动仅涉及一个函数参数的默认值，对显式传参的既有调用（生成、PP 路径）零影响；非首 rank 的 assert 保留，漏传仍会以断言方式暴露，不会静默出错。主要欠缺是 PR 未附带自动化回归测试，当前依赖手动验证命令，后续若重构 pooling 编译绑定逻辑可能再次回归。
- 影响：修复 Gemma3 文本模型（含 embeddinggemma-300m 等 encoder-only 用法）在 Model Runner V2 下的 pooling 启动；为 #48290 扫清测试阻塞；对普通生成服务无用户可见行为变化。影响范围小但具有阻塞性。
- 风险标记：缺专用回归测试 , 模型签名契约变更

# 关联脉络

- PR #48290 Default encoder-only pooling models to Model Runner V2: PR body 明确本修复是其前置条件：embeddinggemma-300m 在 V2 路径下因缺默认值导致 MTEB 测试在引擎初始化时失败，修复后才能让该 PR 的 CI 转绿。