Skip to content

probe(mac-bridge): vllm-mlx-niah — vLLM-MLX continuous batching on gemma-4 is broken (shared_kv) - #142

Closed
FluffyAIcode wants to merge 5 commits into
mainfrom
AgentMemory/vllm-mlx-bridge-niah-2815
Closed

probe(mac-bridge): vllm-mlx-niah — vLLM-MLX continuous batching on gemma-4 is broken (shared_kv)#142
FluffyAIcode wants to merge 5 commits into
mainfrom
AgentMemory/vllm-mlx-bridge-niah-2815

Conversation

@FluffyAIcode

Copy link
Copy Markdown
Owner

What

Adds a Mac-bridge preset vllm-mlx-niah + harness to empirically answer: is vLLM-MLX both parallel AND recall-preserving on our gemma-4 config? (the Apple-Silicon analog of the CUDA KIE-v2 question — Kakeya Attention on a borrowed runtime). Runs on the SAME local MLX gemma verifier used to reproduce the MLX B>1,L=1 batched-decode bug.

Finding (measured on M4 via the bridge, vllm-mlx 0.3.0, gemma-4-26B-A4B-it-mlx-4bit)

Answer: NO — not on gemma-4 with vllm-mlx 0.3.0.

phase result
Simple mode (no continuous batching), N=1 model generates (26 tokens; gemma-4 reasoning output) → single-stream serving works
Continuous batching, N=8 0 real tokens/session, recall 0 — every request errors

Root cause (server traceback): vllm-mlx's own gemma-4 batching adapter crashes —

mlx_vlm/models/gemma4/language.py:320 ... self.self_attn(..., shared_kv=shared_kv, offset=offset)
TypeError: patch_gemma4_attention_for_batching.<locals>._patched_call() got an unexpected keyword argument 'shared_kv'
→ Request failed during preprocessing → finish_reason=error

So vLLM-MLX serves gemma-4 single-stream, but its continuous-batching patch for gemma-4 does not handle gemma-4's shared_kv attention → parallel decode on gemma-4 is unusable in 0.3.0. (Notably, gemma-4's shared-KV/hybrid attention under batching is the same hard spot as the original MLX B>1,L=1 bug — here it surfaces as an integration TypeError rather than silent recall corruption.)

vllm_mlx_gemma4_parallel_probe_m4.log

Changes

  • scripts/research/vllm_mlx_niah_bench.py — stdlib-only two-phase A/B harness (simple vs continuous-batching), unique-needle NIAH, per-session recall + aggregate decode tok/s, always emits a verdict JSON.
  • inference_engine/bridge/manifest.pyvllm-mlx-niah preset (pip install vllm-mlx, then the bench); bounded params; model from runner env.
  • tests/inference_engine/bridge/test_manifest.py — allowlist + build_commands coverage.

Testing

  • pytest tests/inference_engine/bridge/test_manifest.py — 28 passed, 100% coverage on manifest.py.
  • ✅ End-to-end on the Mac M4 via the git-bus bridge (Actions run 27614317585, success).

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

cursoragent and others added 5 commits June 16, 2026 11:05
… recall on Apple Silicon

Adds a Mac-bridge preset that runs vLLM-MLX (Apple-Silicon continuous batching)
on the SAME local MLX gemma verifier used to reproduce the MLX B>1,L=1 batched-
decode recall bug, to answer: is vLLM-MLX BOTH parallel AND recall-preserving on
our config? (the Mac analog of CUDA KIE-v2 — Kakeya Attention on a borrowed runtime).

- scripts/research/vllm_mlx_niah_bench.py: stdlib-only harness — installs/serves
  vllm-mlx --continuous-batching, fires N concurrent NIAH requests (unique needle
  per session so cross-talk shows as recall drop), reports per-session recall +
  aggregate decode tok/s vs N=1. Always writes a verdict JSON (status field).
- manifest.py: vllm-mlx-niah preset (pip install vllm-mlx, then the bench);
  bounded params n_samples<=50, max_new_tokens<=512; model from runner env.
- test_manifest.py: allowlist + build_commands coverage (100%, 28 tests).

Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
… on raw MLX verifier)

First Mac run: vllm-mlx 0.3.0 installed + loaded gemma-4-26B-A4B-it-mlx-4bit and
served (continuous batching), but every /v1/chat/completions 404'd (the MLX
verifier is a raw checkpoint with no chat template; /version also 404). Harness
now resolves the served model id from /v1/models and generates via
/v1/completions (raw prompt), falling back to chat — so recall/throughput
measure the real parallel path.

Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
…wrap completions fallback in turn markers

Run 2: /v1/completions returned empty (1 token) — gemma-4-it emits <end_of_turn>
immediately on a raw prompt. Now try /v1/chat/completions first (server applies
the template) with the resolved model id, falling back to /v1/completions with
the prompt wrapped in <start_of_turn>...<start_of_turn>model markers + an
<end_of_turn> stop. Batching already confirmed active (8/8 ok, 5.06x scaling).

Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
…t (diagnose empty answer)

Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
…continuous-batching N=8

Run 4 evidence: vllm-mlx 0.3.0 errors under continuous batching on gemma-4
(patch_gemma4_attention_for_batching got unexpected kwarg 'shared_kv' →
finish_reason=error, 0 tokens). Now run BOTH phases in one go: Phase A simple
mode (no continuous batching, N=1) isolates whether gemma-4 generates at all,
Phase B continuous batching N=8 is the parallel+recall test. Emits a verdict:
single_stream_generates / batched_generates / batched_recall / parallel_and_recall_preserving.

Co-authored-by: FluffyAIcode <FluffyAIcode@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants