Fix hybrid linear attention dispatch by layer id with draft-worker awareness (#27120)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cheng Wan
2026-06-03 14:11:14 -07:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 7716fa00e0
commit e485ad6ac1
3 changed files with 5 additions and 23 deletions
@@ -314,6 +314,10 @@ def attn_backend_wrapper(runner: "ModelRunner", full_attn_backend: "AttentionBac
"If this is a custom hybrid model, use register_linear_attn_model() "
"from sglang.srt.configs.linear_attn_model_registry."
)
if runner.is_draft_worker:
# FIXME: we assume that MTP/NEXTN always use full-attention.
full_attn_layers = [0]
else:
full_attn_layers = cfg.full_attention_layer_ids
return HybridLinearAttnBackend(
full_attn_backend, linear_attn_backend, full_attn_layers
@@ -16,7 +16,6 @@ from sglang.srt.layers.attention.mamba.mamba_state_scatter_triton import (
fused_mamba_state_scatter_with_mask,
)
from sglang.srt.layers.radix_attention import RadixAttention
from sglang.srt.layers.radix_linear_attention import RadixLinearAttention
from sglang.srt.mem_cache.memory_pool import HybridReqToTokenPool
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
from sglang.srt.model_executor.model_runner import ModelRunner
@@ -784,21 +783,6 @@ class HybridLinearAttnBackend(AttentionBackend):
def _is_full_attn(
self, layer: Optional[RadixAttention], layer_id: Optional[int] = None
) -> bool:
# Explicit linear-attention subclass → strong linear signal (KDA, GDN,
# Qwen3-Next, Qwen3.5 main linear layers).
if isinstance(layer, RadixLinearAttention):
return False
# Some hybrid models (Ling-2.5/2.6) wrap their linear layers in plain
# `RadixAttention` rather than `RadixLinearAttention`. Those wrappers
# set `_is_linear_attention=True` on the attn module so we can
# distinguish them from full-attention RadixAttention instances —
# including MTP/NEXTN draft layers, which are full and must default to
# the full-attn path.
if layer is not None and getattr(layer, "_is_linear_attention", False):
return False
if isinstance(layer, RadixAttention):
return True
if layer is not None:
layer_id = layer.layer_id
assert layer_id is not None, "either layer or layer_id must be provided"
@@ -508,12 +508,6 @@ class BailingMoELinearAttention(nn.Module):
quant_config=quant_config,
prefix=f"{prefix}.attn",
)
# Marker for HybridLinearAttnBackend._is_full_attn: Bailing wraps
# linear-attention layers in a plain RadixAttention, so the
# dispatcher can't tell from the type alone that this is a linear
# layer (would otherwise default to the full-attn backend, e.g. the
# same way MTP/NEXTN draft layers are routed).
self.attn._is_linear_attention = True
self.group_norm_size = getattr(config, "group_norm_size", 1)
self.rms_norm_eps = float(getattr(config, "rms_norm_eps", 1e-5))