Prhub

#43525 [Kernel] Support GLM-5 dimensions for TRT-LLM ragged MLA prefill

原始 PR 作者 mmangkad 合并时间 2026-06-17 04:49 文件变更 10 提交数 2 评论 10 代码增减 +200 / -77

执行摘要

支持 TRT-LLM MLA prefill 适配 GLM-5 维度

TRT-LLM 的 ragged MLA prefill 内核已具备支持 GLM-5 维度的能力(参见 flashinfer-ai/flashinfer#3064),但 vLLM 的验证逻辑仅限 DeepSeek-R1 固定的 (128,64,128) 维度。本 PR 解除该限制,使 TRTLLM_RAGGED 能同时支持 DeepSeek-R1 和 GLM-5 两种 MLA 维度组合,同时确保 FLASHINFERTOKENSPEED_MLA 等后端仍限定于其已验证的维度。替换模型专属的 requires_r1_mla_dimensions 标志,消除命名偏差,为未来更多模型平滑接入铺平道路。

该 PR 是一项架构优雅的后端可扩展性改进,值得精读。重点关注:

  1. MLADimensions dataclass 的引入如何取代布尔标志,使后端维度验证变得透明且可组合。
  2. validate_configurationrequires_r1_mla_dimensions and not is_r1_compatible 变为白名单 membership 检查,这是“面向接口而非实现”的典型应用。
  3. 文档生成工具用 AST 解析自动更新文档,保持代码与文档同步,值得其他模块效仿。
  4. 未来新增 MLA 维度时,开发者只需在后端声明 supported_mla_dimensions + MLADimensions(...),无需改动选择器或测试框架。
讨论亮点

主要讨论来自 reviewer MatthewBonanni,他指出了两个关键设计意见:

  • 移除模型特定命名:他在整体 review 中指出“I think it'll be good to get rid of model-specific stuff (including naming) in this logic”。
  • 使用 dataclass 代替字典:针对初始版本中 supported_mla_dimensions 字典(以模型名为键),他建议改用 @dataclass(frozen=True, kw_only=True) class MLADimensions,并在各处使用该类型,以获得更干净的代码和类型安全。
    • 作者 mmangkad 在后续 commit 中采纳了全部建议,将实现从模型名键值对迁移为 list[MLADimensions],同时调整了选择器配置中的字段。最终 MatthewBonanni 批准了 PR。
    • 另外,PR body 中作者声明需要 FlashInfer 0.6.12 发布后才能合并,该版本已发布,且测试通过。

实现拆解

  1. 引入 MLADimensions 数据类:在 vllm/v1/attention/backends/mla/prefill/base.py 定义 @dataclass(frozen=True, kw_only=True) 类,包含 qk_nope_head_dimqk_rope_head_dimv_head_dim,并提供 __str__ 方法。将基类的 requires_r1_mla_dimensions 类变量替换为 supported_mla_dimensions: ClassVar[list[MLADimensions]] = [],同时更新 validate_configuration:不再检查 is_r1_compatible,而是检查 selector_config.mla_dimensions 是否在 supported_mla_dimensions 列表中。

  2. 更新各个后端声明:在 trtllm_ragged.pyflashinfer.pytokenspeed_mla.py 中,将 requires_r1_mla_dimensions = True 改为显式的 supported_mla_dimensions 列表。TRTLLM_RAGGED 包含两组维度(DeepSeek-R1 和 GLM-5),其余后端只保留 DeepSeek-R1 维度。

  3. 重写选择器与配置:在 selector.py 中,移除 is_deepseek_r1_mla_compatible 函数,MLAPrefillSelectorConfig 中删除 is_r1_compatible,改为添加 mla_dimensions: MLADimensions 字段(默认全 0)。get_mla_prefill_backend 改为从 hf_text_config 读取三个维度值构造 MLADimensions。新增 __repr__ 便于调试。

  4. 同步文档生成工具tools/pre_commit/generate_attention_backend_docs.py 新增 parse_mla_dimensions_callparse_supported_mla_dimensions 函数,从 AST 中解析 MLADimensions(...) 调用,生成可读字符串。原先基于 requires_r1_dims 的备注逻辑被替换为打印后端支持的全部维度组合,自动更新文档。

  5. 测试配套:更新 tests/v1/attention/test_mla_prefill_selector.py,移除对 is_deepseek_r1_mla_compatible 的依赖,测试直接构造 MLADimensions 对象。test_r1_dimension_requirement 重构为 test_backend_supported_dimension_validation,验证各后端维度白名单。test_mla_backends.pytest_mla_prefill_registry.py 同步调整。

文件 模块 状态 重要度
tools/pre_commit/generate_attention_backend_docs.py 文档生成 modified 7.72
vllm/v1/attention/backends/mla/prefill/selector.py 选择器 modified 7.53
vllm/v1/attention/backends/mla/prefill/base.py 基类 modified 7.27
vllm/v1/attention/backends/mla/prefill/trtllm_ragged.py 后端 modified 6.21
vllm/v1/attention/backends/mla/prefill/flashinfer.py 后端 modified 6.06
vllm/v1/attention/backends/mla/prefill/tokenspeed_mla.py 后端 modified 6.06
tests/v1/attention/test_mla_prefill_selector.py 测试 modified 6.5
tests/v1/attention/test_mla_backends.py 测试 modified 4.83
tests/v1/attention/test_mla_prefill_registry.py 测试 modified 3.7
docs/design/attention_backends.md 文档 modified 2.03

关键符号

MLADimensions.__str__ MLAPrefillBackend.validate_configuration get_mla_prefill_backend parse_mla_dimensions_call parse_supported_mla_dimensions test_backend_supported_dimension_validation

关键源码片段

vllm/v1/attention/backends/mla/prefill/selector.py core-logic

后端选择器核心变更:移除模型特定维度检测函数,改用 MLADimensions 对象作为配置,修改 selector config 结构。

# 选择器配置现在直接包含 MLADimensions,不再需要模型特定标志
class MLAPrefillSelectorConfig(NamedTuple):
    dtype: torch.dtype
    mla_dimensions: MLADimensions = MLADimensions(
        qk_nope_head_dim=0,
        qk_rope_head_dim=0,
        v_head_dim=0,
    )
​
    def __repr__(self):
        return (
            f'MLAPrefillSelectorConfig(dtype={self.dtype}, '
            f'mla_dimensions={self.mla_dimensions})'
        )# 在 get_mla_prefill_backend 中,从模型配置读取维度并构造 MLADimensions
model_config = vllm_config.model_config
if model_config is None:
    selector_config = MLAPrefillSelectorConfig(dtype=torch.get_default_dtype())
else:
    hf_text_config = model_config.hf_text_config
    selector_config = MLAPrefillSelectorConfig(
        dtype=model_config.dtype,
        mla_dimensions=MLADimensions(
            qk_nope_head_dim=getattr(hf_text_config, 'qk_nope_head_dim', 0),
            qk_rope_head_dim=getattr(hf_text_config, 'qk_rope_head_dim', 0),
            v_head_dim=getattr(hf_text_config, 'v_head_dim', 0),
        ),
    )
vllm/v1/attention/backends/mla/prefill/base.py core-logic

基类定义核心数据结构和验证逻辑:新增 MLADimensions dataclass,将 requires_r1_mla_dimensions 替换为 supported_mla_dimensions 白名单列表,重构 validate_configuration。

# 新的 MLA 维度数据类,用于替代模型特定布尔标志
@dataclass(frozen=True, kw_only=True)
class MLADimensions:
    qk_nope_head_dim: int
    qk_rope_head_dim: int
    v_head_dim: int
​
    def __str__(self) -> str:
        # 返回紧凑展示字符串,便于日志和错误提示
        return (
            f'(qk_nope_head_dim={self.qk_nope_head_dim}, '
            f'qk_rope_head_dim={self.qk_rope_head_dim}, '
            f'v_head_dim={self.v_head_dim})'
        )# 基类使用 supported_mla_dimensions 白名单替代布尔标志
class MLAPrefillBackend(ABC):
    supported_dtypes: ClassVar[list[torch.dtype]] = [torch.float16, torch.bfloat16]
    supported_mla_dimensions: ClassVar[list[MLADimensions]] = []
​
    @classmethod
    def validate_configuration(
        cls, device_capability, selector_config
    ) -> list[str]:
        invalid_reasons: list[str] = []
        # ... compute capability, dtype, is_available 检查 ...
        # 维度白名单检查
        if (
            cls.supported_mla_dimensions
            and selector_config.mla_dimensions not in cls.supported_mla_dimensions
        ):
            supported = ', '.join(str(dims) for dims in cls.supported_mla_dimensions)
            invalid_reasons.append(
                'Model does not have supported MLA dimensions '
                f'(got {selector_config.mla_dimensions}; supported: {supported})'
            )
        return invalid_reasons
vllm/v1/attention/backends/mla/prefill/trtllm_ragged.py dependency-wiring

TRTLLM_RAGGED 后端声明支持的维度列表,新增 GLM-5 维度,是功能扩展的直接受益者。

# TRTLLM_RAGGED 后端声明支持两种 MLA 维度组合
class TrtllmRaggedPrefillBackend(MLAPrefillBackend):
    supported_mla_dimensions: ClassVar[list[MLADimensions]] = [
        MLADimensions(
            qk_nope_head_dim=128,
            qk_rope_head_dim=64,
            v_head_dim=128,
        ), # DeepSeek-R1 维度
        MLADimensions(
            qk_nope_head_dim=192,
            qk_rope_head_dim=64,
            v_head_dim=256,
        ), # GLM-5 维度
    ]
    # ... 其余代码保持不变

评论区精华

使用 MLADimensions dataclass 取代模型特定命名 设计

MatthewBonanni 在 review 中建议:① 移除模型特定命名('I think it'll be good to get rid of model-specific stuff (including naming) in this logic')② 用 @dataclass(frozen=True, kw_only=True) 类 MLADimensions 替代字典 tuple,以获得更干净的设计。

结论:作者 mmangkad 采纳建议,在第二个 commit 中完成迁移,最终 reviewer 批准。 · 已解决

风险与影响

  • 维度白名单一致性:FLASHINFER 和 TOKENSPEED_MLA 后端白名单仅包含 DeepSeek-R1 维度,若用户显式指定这些后端用于 GLM-5,验证会正确拒绝,不会静默使用不支持的内核。但需要确保未来添加新后端时也遵循此模式,否则可能出现误放行。
  • 默认零维度处理:当 model_config 为 None 时,MLAPrefillSelectorConfig.mla_dimensions 默认全零,这不是任何后端支持的维度,因此 validate_configuration 会返回不支持的提示,行为合理。
  • 测试覆盖范围:单元测试覆盖了维度验证的正反例,精度测试仅在 GB300 上通过 GSM8K(94.77%),其他硬件(如 H100)上的端到端行为未验证,但注意力内核本身未修改,回归风险低。
  • 文档自动生成generate_attention_backend_docs.py 对 AST 的解析逻辑新增了 parse_mla_dimensions_call,若未来 MLADimensions 调用方式变化(如增加字段),需要同步更新该解析函数,否则文档会丢失部分维度信息。
  • 用户侧:GLM-5 模型用户现可指定 --attention-config '{"mla_prefill_backend": "TRTLLM_RAGGED"}' 获得加速;DeepSeek-R1 用户无需改动。自动选择场景下,Blackwell 设备上 FLASH_ATTN 仍优先,回退到 TRTLLM_RAGGED 也能正确处理 GLM-5 维度。
  • 系统侧:维度验证机制从硬编码布尔匹配变为后端声明式白名单,新增模型维度只需在后端类中添加一条 MLADimensions 条目,无需改动选择器核心路径,大幅提升可扩展性。
  • 团队侧:消除了模型名称(DeepSeek-R1)在代码中的耦合,基类 MLAPrefillBackend 的接口更加通用和清晰。文档自动生成工具同步改进,生成的 attention backends 页面将显示每个后端支持的具体维度而非模糊的“R1 dims only”。
核心验证逻辑重构 后端白名单扩展 配置键变更

关联 Issue

#3064 Loosened trtllm_ragged_attention_deepseek shape assertion

完整报告

参与讨论