Prhub

#30275 [Model] Support LongCat 2.0 FP8

原始 PR 作者 BBuf 合并时间 2026-07-07 19:51 文件变更 23 提交数 5 评论 1 代码增减 +481 / -91

执行摘要

支持 LongCat 2.0 FP8 模型在 8x B300 上部署与推理

支持 meituan-longcat/LongCat-2.0-FP8 在 SGLang 中运行。原 PR #30202 提供了基础实现,但在实际 8x B300 服务验证中发现精度问题,需修复后合入。

本 PR 的 ngram token table 跳过掩码设计和 DSA indexer head padding 技巧值得精读;建议后续补充端到端集成测试并监控 decode 性能。

讨论亮点

该 PR 由 ispobock 快速审批通过,无实质性设计讨论。内部协作体现在 commit log 中,BBuf 和 sunjiaqi11 合作修复了 serving 精度问题。

实现拆解

  1. LongCat 配置自动发现:在 python/sglang/srt/utils/hf_transformers/config.py 中新增 _try_load_longcat_config 函数,通过检查 architectures 字段是否包含 LongCat 架构名,自动加载自定义配置类 longcat_flash.py,并处理 model_type 为 null 的兼容问题。

  2. 模型层调整:修改 python/sglang/srt/models/longcat_flash.py,在 LongcatFlashDecoderLayer.forward 中传递 prev_topk_indices 参数以支持 DSA indexer 跨层传播;LongcatFlashModel.forward 同样传递 topk_indices

  3. 统一 ngram token 表更新:新增 python/sglang/srt/model_executor/ngram_token_table.py,提供 update_ngram_token_table_after_sampling 函数,根据 skip_token_table_update 掩码跳过未完成的 chunked prefill 请求的伪 token,防止污染 token 表。对应测试文件覆盖三个场景。

  4. 重构 ngram 嵌入层:修改 python/sglang/srt/layers/n_gram_embedding.py,移除 decode 分支,统一使用 compute_n_gram_ids;新增 eos_token_id 参数;将 VocabParallelEmbeddingenable_tp 改为 use_attn_tp_group,确保与 LongCat 的 TP 设置一致。

  5. 增强 DSA Indexer:在 python/sglang/srt/layers/attention/dsa/dsa_indexer.py 中添加 _pad_heads_for_deep_gemm 静态方法(当 head 数 < 32 时填充)和 _mask_init_and_local_tokens 方法(遮蔽初始/局部 token 的 logits),支持 LongCat 的 ngram 预测策略。

  6. 填充 ngram 元数据:在 scheduler.pyforward_batch_info.pybase_runner.py 中为 warmup 和 CUDA graph dummy batch 填充 ngram_embedding_info 的必要字段,避免图捕获阶段报错。

文件 模块 状态 重要度
test/registered/unit/model_executor/test_ngram_token_table.py ngram 测试 added 7.75
python/sglang/srt/model_executor/ngram_token_table.py ngram 表 added 7.87
python/sglang/srt/layers/attention/dsa/dsa_indexer.py 注意力索引 modified 7.57
python/sglang/srt/utils/hf_transformers/config.py 配置解析 modified 6.72
python/sglang/srt/layers/n_gram_embedding.py ngram 嵌入 modified 6.72
python/sglang/srt/models/longcat_flash.py 模型层 modified 6.66
python/sglang/srt/managers/scheduler.py 调度器 modified 5.85
python/sglang/srt/model_executor/forward_batch_info.py 前向批次 modified 5.75

关键符号

update_ngram_token_table_after_sampling _try_load_longcat_config _pad_heads_for_deep_gemm _mask_init_and_local_tokens NgramEmbedding.__init__ LongcatFlashDecoderLayer.forward LongcatFlashModel.forward

关键源码片段

python/sglang/srt/model_executor/ngram_token_table.py data-contract

核心新文件,实现 ngram token 表更新逻辑,包含 chunked prefill 跳过掩码机制。

"""Utilities for updating LongCat ngram embedding token tables."""from __future__ import annotationsimport torchfrom sglang.jit_kernel.ngram_embedding import update_token_table
​
​
def update_ngram_token_table_after_sampling(
    *,
    ngram_embedding_info,
    next_token_ids: torch.Tensor,
    req_pool_indices: torch.Tensor,
    seq_lens: torch.Tensor,
    batch_size: int,
) -> bool:
    """Update the ngram token table with sampled tokens.    Returns whether the token table was updated.
    """
    skip_token_table_update = ngram_embedding_info.skip_token_table_update
    if skip_token_table_update is not None:
        # 跳过 chunked prefill 未完成的请求:它们的采样 token 是伪预测,不能污染 token 表
        indices = (~skip_token_table_update).nonzero(as_tuple=True)[0]
        if indices.numel() == 0:
            return False
        update_token_table(
            ne_token_table=ngram_embedding_info.token_table,
            tokens=next_token_ids[indices].to(torch.int32),
            row_indices=req_pool_indices[indices],
            column_starts=seq_lens[indices].to(torch.int32),
            req_lens=torch.ones(
                indices.numel(), dtype=torch.int32, device=next_token_ids.device
            ),
            ignore_tokens=None,
        )
        return True
​
    # 无 mask 时,直接写入所有 token
    ngram_embedding_info.out_column_starts[:batch_size] = seq_lens
    ngram_embedding_info.out_req_lens[:batch_size] = 1
    update_token_table(
        ne_token_table=ngram_embedding_info.token_table,
        tokens=next_token_ids.to(torch.int32),
        row_indices=req_pool_indices,
        column_starts=ngram_embedding_info.out_column_starts,
        req_lens=ngram_embedding_info.out_req_lens,
        ignore_tokens=None,
    )
    return True

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  • 配置依赖风险_try_load_longcat_config 依赖于 HuggingFace 配置的 architectures 字段,若上游模型变更可能导致加载失败。
  • token 表污染风险skip_token_table_update 掩码的正确性依赖上游正确设置,若其他模型误用可能导致 ngram 表被伪 token 污染。
  • DSA indexer 逻辑耦合_pad_heads_for_deep_gemm_mask_init_and_local_tokens 仅适用于 LongCat,若被其他模型误用可能产生错误结果。
  • decode 路径合并风险:统一使用 compute_n_gram_ids 替代原有的 decode 分支,虽然简化了逻辑,但可能对 decode 阶段的性能有隐忧(未报告退化)。
  • 测试覆盖缺口:仅针对 token table 更新有单元测试,缺少端到端集成测试(模型加载+推理)。
  • 用户:可使用 LongCat-2.0-FP8 模型,在 8x B300 配置下 GSM8K 准确率 95.9%,吞吐约 1084 token/s。
  • 系统:配置文件解析逻辑增加对 LongCat 的自动识别,对非 LongCat 模型无影响(回退原逻辑)。
  • 团队:为后续添加类似 ngram 增强模型提供了可复用的 token 表更新和 indexer 扩展模式。
新模型引入 核心调度逻辑变更 DSA indexer 扩展 缺少端到端集成测试

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论