Skip to content

[Config] Unify indexer cache dtype under attention_config.indexer_kv_dtype - #52550

Merged
zyongye merged 1 commit into
vllm-project:mainfrom
zyongye:unify-indexer-kv-dtype
Aug 17, 2026
Merged

[Config] Unify indexer cache dtype under attention_config.indexer_kv_dtype#52550
zyongye merged 1 commit into
vllm-project:mainfrom
zyongye:unify-indexer-kv-dtype

Conversation

@zyongye

@zyongye zyongye commented Aug 16, 2026

Copy link
Copy Markdown
Member

Purpose

The sparse-attention indexer picked its K-cache dtype through two unrelated knobs:

flag type read by
attention_config.use_fp4_indexer_cache bool DeepSeek V3.2/V4 only
attention_config.indexer_kv_dtype enum MiniMax M3 only

Because each model read only one of them, passing both was accepted and quietly
resolved in favor of the bool on the DeepSeek path. A config asking for an fp8
indexer cache (--attention_config.indexer_kv_dtype fp8) alongside
--attention_config.use_fp4_indexer_cache=True ran MXFP4, with no warning. I hit
exactly this in a local DSV4 recipe whose "fp8 indexer" arm had in fact been
running MXFP4 for its whole history.

This PR makes indexer_kv_dtype the single knob and deprecates
use_fp4_indexer_cache.

Changes

vllm/config/attention.py

  • indexer_kv_dtype gains an "auto" default, resolved per model by the new
    resolve_indexer_kv_dtype(default). The old "bf16" default was never
    meaningful for DeepSeek, whose indexer cache is always quantized; "auto"
    means fp8 there and bf16 for M3, preserving both models' current behavior.
  • use_fp4_indexer_cache becomes bool | None = None. When set it logs a
    deprecation warning (removal in v0.19) and maps True -> "mxfp4". False is
    a no-op because it already selected the model default. Conflicting values now
    raise instead of one silently winning.
  • The deprecated field is excluded from compute_hash, so
    use_fp4_indexer_cache=True and indexer_kv_dtype=mxfp4 share a compile
    cache entry rather than splitting it.

vllm/v1/attention/backends/mla/indexer.py

  • New dsa_indexer_uses_fp4(vllm_config) centralizes resolution + validation for
    the DeepSeek path, so the model side and the metadata builder cannot disagree.
    It rejects dtypes the DSA indexer has no kernels for (bf16, nvfp4) instead
    of failing later in kernel selection, and turns the existing Blackwell
    assert into a ValueError so the check survives python -O.

Callersmodels/deepseek_v4/attention.py and
models/minimax_m3/nvidia/model.py go through the shared helpers. DSV4 now
validates at model construction too, not only at backend build.

Configs — the two tracked gsm8k eval configs move to
--attention_config.indexer_kv_dtype=mxfp4.

Backward compatibility

--attention_config.use_fp4_indexer_cache=True keeps working and keeps
selecting MXFP4; it just warns. All three CLI spellings were exercised
(--attention_config.indexer_kv_dtype=mxfp4, the deprecated flag, and JSON
--attention-config '{"indexer_kv_dtype": "nvfp4"}').

The one intentional behavior change: a config passing both flags with
different values used to silently take the bool, and now raises. That
combination was always a contradiction; on the DeepSeek path it produced a cache
dtype the config did not ask for.

Not a duplicate

Per the duplicate-work checks in AGENTS.md:

gh pr list --repo vllm-project/vllm --state open --search "indexer_kv_dtype"
gh pr list --repo vllm-project/vllm --state open --search "use_fp4_indexer_cache"
gh pr list --repo vllm-project/vllm --state open --search "deprecate indexer cache"
gh pr list --repo vllm-project/vllm --state open --search "unify indexer dtype attention config"

Nearest open PRs, all adjacent rather than overlapping — none touches
vllm/config/attention.py or unifies the two knobs:

If #51209 lands first the overlap is a small context conflict in
DeepseekV4Indexer.__init__, trivially rebasable.

Testing

pre-commit run --files <changed files>          # all hooks pass, incl. mypy
.venv/bin/python -m pytest tests/config/test_config_generation.py \
                          tests/engine/test_arg_utils.py -q
# 98 passed, 1 failed

The single failure is test_config_generation.py::test_ray_runtime_env
(ModuleNotFoundError, ray not installed); confirmed pre-existing by rerunning
it on a clean stash of main.

Config-resolution matrix verified directly (default -> auto; deprecated
True -> mxfp4 + warning; deprecated False -> auto; conflict -> raises;
auto -> fp8/bf16 per model; hashes of the deprecated and new spellings match).

Model evaluation

Real serving run on the DeepSeek path this change is riskiest for — TP8 over
2x GB300 (8 GPUs), DSpark speculative decoding (7 tokens, greedy),
--attention-config.backend FLASHINFER_MLA, --kv-cache-dtype fp8,
cudagraph_mode FULL_DECODE_ONLY, driven by the new flag
--attention_config.indexer_kv_dtype=mxfp4.

Engine log confirms the unified flag drives both consumers to the MXFP4 path:

attention_config=AttentionConfig(..., use_fp4_indexer_cache=None, indexer_kv_dtype='mxfp4', ...)
[attention.py:810] Using MXFP4 indexer cache for Lightning Indexer.
[indexer.py:558] DSA indexer decode path: use_flattening=False supports_varlen=True (next_n=8, use_fp4_cache=True)

aime25, 4 epochs, n=120, 0 request errors, temperature 1.0 / top_p 0.95,
thinking enabled, max_tokens 150000:

metric value
exact_match 1.0000
pass@4 1.0000

Caveat worth stating plainly: aime25 is saturated for this checkpoint, so this
result confirms the MXFP4 path is intact end-to-end but cannot by itself
distinguish it from fp8 or from the pre-change build. The stronger evidence for
"no behavior change" is that "auto" resolves to each model's previous default
and the resolution matrix above is exhaustive over the flag combinations.

AI assistance

AI assistance (Claude Code) was used for this change. I reviewed every changed
line, ran the tests and the multi-node eval above myself, and can defend the
change end-to-end.

…dtype

The DeepSeek sparse indexer and the MiniMax M3 indexer picked their K-cache
dtype through two unrelated knobs: `use_fp4_indexer_cache` (bool, read only by
DSV4) and `indexer_kv_dtype` (enum, read only by M3). Passing both was
accepted and silently resolved in favor of the bool for DSV4, so a config
asking for an fp8 indexer could run MXFP4.

Make `indexer_kv_dtype` the single knob and deprecate `use_fp4_indexer_cache`:

- `indexer_kv_dtype` gains an "auto" default that each model resolves to its
  own default (fp8 for the DeepSeek sparse indexer, bf16 for M3). The previous
  "bf16" default was never meaningful for DSV4, whose indexer cache is always
  quantized.
- `use_fp4_indexer_cache` becomes `bool | None`; when set it logs a
  deprecation warning and maps True to "mxfp4". False is a no-op, since it
  already selected the model default. Conflicting values raise instead of one
  silently winning.
- `dsa_indexer_uses_fp4()` centralizes resolution and validation for the
  DeepSeek path, so the model side and the metadata builder cannot disagree.
  It rejects dtypes the DSA indexer has no kernels for (bf16, nvfp4) and
  turns the Blackwell check into a ValueError so it survives `python -O`.
- The deprecated field is excluded from `compute_hash`, so
  `use_fp4_indexer_cache=True` and `indexer_kv_dtype=mxfp4` share a compile
  cache entry.

Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@zyongye

zyongye commented Aug 16, 2026

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #84112 for commit b5a2aafdecb4.

@zyongye
zyongye enabled auto-merge (squash) August 17, 2026 02:01
@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Aug 17, 2026
@zyongye
zyongye merged commit 967e104 into vllm-project:main Aug 17, 2026
121 checks passed
@zyongye
zyongye deleted the unify-indexer-kv-dtype branch August 17, 2026 02:54
Alessandra005 pushed a commit to Alessandra005/vllm that referenced this pull request Aug 17, 2026
…dtype (vllm-project#52550)

Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Alessandra005 <aurib032@fiu.edu>
zyp2014 pushed a commit to zyp2014/vllm that referenced this pull request Aug 21, 2026
…dtype (vllm-project#52550)

Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
wyettzeng pushed a commit to wyettzeng/vllm that referenced this pull request Aug 21, 2026
…dtype (vllm-project#52550)

Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Wyett <wyettzeng@gmail.com>
zufangzhu pushed a commit to zufangzhu/vllm that referenced this pull request Aug 24, 2026
…dtype (vllm-project#52550)

Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Zhu, Zufang <zufang.zhu@intel.com>
khushali9 pushed a commit to khushali9/vllm that referenced this pull request Aug 29, 2026
…dtype (vllm-project#52550)

Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: khushali9 <khushali.desai9@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants