[Model] Support bidirectional (encoder-only) attention for DeepSeek e… (#52948)

Signed-off-by: Egor <erop001@gmail.com> Signed-off-by: Egor <47443236+Lossfull@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>

Egor committed Aug 19, 2026 at 19:36 UTC e9e1630e93b13b241c4cdb52c47e35fd38c6eb46
4 files changed +35 -3
tests/models/registry.py
+5
@@ -593,6 +593,11 @@ _EMBEDDING_EXAMPLE_MODELS = {
593 hf_overrides={"architectures": ["BertSpladeSparseEmbeddingModel"]},
594 ),
595 "BgeM3EmbeddingModel": _HfExamplesInfo("BAAI/bge-m3"),
596 + "DeepseekV3BidirectionalModel": _HfExamplesInfo(
597 + "ai-sage/Giga-Embeddings-instruct-10B-A1.8B-0826",
598 + trust_remote_code=True,
599 + hf_overrides={"model_type": "deepseek_v3", "auto_map": None},
600 + ),
601 "Gemma2Model": _HfExamplesInfo("BAAI/bge-multilingual-gemma2"),
602 "Gemma3TextModel": _HfExamplesInfo("google/embeddinggemma-300m"),
603 "GritLM": _HfExamplesInfo("parasail-ai/GritLM-7B-vllm"),
vllm/config/model.py
+6
@@ -1877,6 +1877,12 @@ class ModelConfig:
1877 # kv_lora_rank indicates that a Transformers model implementation uses MLA
1878 return getattr(self.hf_text_config, "kv_lora_rank", None) is not None
1879 # Manually maintained list of model types for vLLM model implementations
1880 +
1881 + # Bidirectional DeepSeek variants (is_causal=False, used by some
1882 + # embedding models) must use the non-MLA attention path, since the
1883 + # MLA kernels only support causal attention.
1884 + if not getattr(self.hf_text_config, "is_causal", True):
1885 + return False
1886 return self.is_deepseek_mla
1887
1888 @property
vllm/model_executor/models/deepseek_v2.py
+23 -3
@@ -47,7 +47,11 @@ from vllm.distributed import (
47 )
48 from vllm.logger import init_logger
49 from vllm.model_executor.layers.activation import SiluAndMul
50 -from vllm.model_executor.layers.attention import Attention, RSWAAttention
50 +from vllm.model_executor.layers.attention import (
51 + Attention,
52 + EncoderOnlyAttention,
53 + RSWAAttention,
54 +)
55 from vllm.model_executor.layers.attention_layer_base import AttentionLayerBase
56 from vllm.model_executor.layers.fused_moe import (
57 FusedMoEFactory,
@@ -98,7 +102,7 @@ from vllm.model_executor.models.utils import (
102 from vllm.platforms import current_platform
103 from vllm.sequence import IntermediateTensors
104 from vllm.utils.torch_utils import direct_register_custom_op
101 -from vllm.v1.attention.backend import AttentionBackend
105 +from vllm.v1.attention.backend import AttentionBackend, AttentionType
106 from vllm.v1.attention.backends.mla.indexer import (
107 DeepseekV32IndexerBackend,
108 )
@@ -553,7 +557,22 @@ class DeepseekV2Attention(nn.Module):
557 mscale = yarn_get_mscale(scaling_factor, float(mscale_all_dim))
558 self.scaling = self.scaling * mscale * mscale
559
556 - self.attn = Attention(
560 + # DeepSeek is causal by default (decoder-only). Bidirectional
561 + # (encoder-only) attention is used by embedding models derived from
562 + # this architecture, which set `is_causal=False` on the HF config.
563 + # This only applies on the non-MLA path, since the MLA kernels are
564 + # causal-only; `ModelConfig.use_mla` already disables MLA for these
565 + # models.
566 + if getattr(config, "is_causal", True):
567 + attn_type = AttentionType.DECODER
568 + else:
569 + attn_type = AttentionType.ENCODER_ONLY
570 + attn_cls = (
571 + EncoderOnlyAttention
572 + if attn_type == AttentionType.ENCODER_ONLY
573 + else Attention
574 + )
575 + self.attn = attn_cls(
576 self.num_local_heads,
577 self.qk_head_dim,
578 self.scaling,
@@ -561,6 +580,7 @@ class DeepseekV2Attention(nn.Module):
580 cache_config=cache_config,
581 quant_config=quant_config,
582 prefix=f"{prefix}.attn",
583 + attn_type=attn_type,
584 )
585
586 def forward(
vllm/model_executor/models/registry.py
+1
@@ -230,6 +230,7 @@ _EMBEDDING_MODELS = {
230 "BertSpladeSparseEmbeddingModel": ("bert", "BertSpladeSparseEmbeddingModel"),
231 "BgeM3EmbeddingModel": ("roberta", "BgeM3EmbeddingModel"),
232 "DeciLMForCausalLM": ("nemotron_nas", "DeciLMForCausalLM"),
233 + "DeepseekV3BidirectionalModel": ("deepseek_v2", "DeepseekV3ForCausalLM"),
234 "Gemma2Model": ("gemma2", "Gemma2ForCausalLM"),
235 "Gemma3TextModel": ("gemma3", "Gemma3Model"),
236 "GlmForCausalLM": ("glm", "GlmForCausalLM"),