Qwen3.6-35B-A3B · GPTQ-Int4 · vLLM XPU

Qwen3.6-35B-A3B with GPTQ-Int4 on vLLM XPU, 105.8 t/s warm decode with MTP speculation.

105.8
WARM DECODE (T/S)
51.2
COLD DECODE (T/S)
1.50
WARM TTFT (S)
15.99
COLD TTFT (S)
31.4
PEAK VRAM (GB)
1
CONCURRENT REQS
llm-servingvllmgptqb70ASRock B70baseline

Based on: https://github.com/SergiioB/intel-arc-pro-b70-inference-cookbook/blob/master/docs/qwen36-35a3/QWEN36-MOE-VLLM-XPU.md

Config

Item Value
Backend vLLM, image vllm/vllm-openai-xpu@sha256:2c42…ca97, VLLM_TARGET_DEVICE=xpu
Model llmfan46/Qwen3.6-35B-A3B-uncensored-heretic-Native-MTP-Preserved-GPTQ-Int4
Weights GPTQ Int4 (--quantization gptq), activations float16
Context --max-model-len 163840 (≥ 131k requirement ✓)
GPU 1× Arc Pro B70 32GB (card2/renderD129); second B70 unused by this service
VRAM budget --gpu-memory-utilization 0.9 (~28.8 GB usable)
KV cache --kv-cache-dtype fp8, prefix caching OFF (benchmark-safe)
Scheduler --max-num-seqs 64, --max-num-batched-tokens 16384
Speculative decoding ON. MTP, 4 spec tokens; 3 MTP patches at startup (patch_mtp.py, patch_boundary.py, patch_mtp_ptr_wrap.py) from the B70 cookbook by SergiioB, B70_MTP_BF16_DRAFT=1
Extras auto tool choice (qwen3_coder parser), --reasoning-parser qwen3, --language-model-only
Env XPU graphs ON (VLLM_XPU_ENABLE_XPU_GRAPH=1), PYTORCH_ALLOC_CONF=expandable_segments:True, ZE_FLAT_DEVICE_HIERARCHY=COMPOSITE, ZE_AFFINITY_MASK=0
Endpoint http://your-LAN-IP:9932, served name Qwen3.6-35B-A3B

Stats (measured 2026-10-17 ~00:15 UTC, client-side streaming + /metrics cross-check)

Metric Cold (req #1) Warm (req #2, APC hit)
Prompt tokens 64,346 64,346
TTFT 15.99 s 1.50 s
Prefill throughput ~4,024 tok/s ~42,897 tok/s (cache)
Completion tokens 512 512
Decode tok/s (incl. MTP speculation) 105.8 105.7
Total E2E 20.83 s 6.34 s
VRAM 29.5 GB at startup → 31.4 GB after test (only ~0.6 GB headroom left)
MTP acceptance mean acceptance length 3.07; 51.8% (346 accepted / 668 drafted); per-position 0.784 / 0.593 / 0.407 / 0.287

Server /metrics cross-check: TTFT sum/count = 17.46/2, E2E = 27.17/2, prompt tokens = 128,692/2, all consistent with client timings.

Server log lines (as logged)

Findings

Recommendations

Quality variant (improve output fidelity)

  1. --dtype bfloat16, logs show Casting torch.bfloat16 to torch.float16; the model is natively bf16 and we're downcasting it. Free fix, small fidelity gain.
  2. KV cache fp8 → bf16, vLLM itself warns fp8 KV "may cause accuracy drop"; matters most at 131k+ context. Cost: KV token capacity halves (322k → ~161k ≈ exactly one full-context request); needs the VRAM trade-off accepted.
  3. Weights GPTQ-Int4 → BF16 with TP=2 across both B70s, biggest quality jump; ~35 GiB of weights won't fit one 32 GB card but fits the pair. Also fixes the concurrency ceiling (see speed).

Speed variant (improve tok/s / TTFT)

  1. Raise --max-num-batched-tokens (16384 → 32768+), 64k prefill currently chunks across ≥4 iterations.
  2. Verify MTP is net-positive first (run without --speculative-config), then tune draft depth: per-position acceptance decays 0.78 → 0.29, so num_speculative_tokens=2 may cost less per step for similar effective speed.
  3. TP=2 across both B70s, parallelizes prefill and decode (shared with quality #3); second GPU is currently idle.
  4. APC stays ON, warm long prompts are nearly free (TTFT 1.5 s vs 16 s cold).

Measurement hygiene

Follow-up

Appendix: docker-compose (verbatim, as provided 2026-10-20)

services:
  vllm:
    image: vllm/vllm-openai-xpu@sha256:2c427ef477da092eb6f2cdbbbd24950b5fa171565b916db69d4c7bb10e68ca97
    container_name: b70
    privileged: true
    restart: unless-stopped
    ports:
      - "9932:9932"
    devices:
      - /dev/dri
    group_add:
      - "992"
    cap_add:
      - SYS_PTRACE
    volumes:
      - ./models:/models:Z
      - ./cache:/root/.cache/huggingface:Z
      - ./patches/patch_mtp_nightly.py:/patch_mtp.py:ro
      - ./patches/patch_mtp_boundary.py:/patch_boundary.py:ro
      - ./patches/patch_mtp_ptr_wrap.py:/patch_mtp_ptr_wrap.py:ro
    environment:
      HF_HOME: /root/.cache/huggingface
      HUGGINGFACE_HUB_CACHE: /root/.cache/huggingface/hub
      VLLM_TARGET_DEVICE: xpu
      ZE_FLAT_DEVICE_HIERARCHY: COMPOSITE
      ZE_AFFINITY_MASK: "0"
      B70_MTP_BF16_DRAFT: "1"
      VLLM_XPU_ENABLE_XPU_GRAPH: "1"
      PYTORCH_ALLOC_CONF: "expandable_segments:True"
      TORCHINDUCTOR_COMPILE_THREADS: "1"
    entrypoint:
      - bash
      - -lc
    command:
      - |
        set -e

        echo "========================================"
        echo " B70 vLLM"
        echo "========================================"

        echo "=== GPU CHECK ==="
        python -c 'import torch; print("XPU count:", torch.xpu.device_count()); [print(i, torch.xpu.get_device_name(i)) for i in range(torch.xpu.device_count())]'

        echo "=== MTP PATCH ==="
        python /patch_mtp.py

        echo "=== patch_boundary PATCH ==="
        python /patch_boundary.py

        echo "=== patch_mtp_ptr_wrap PATCH ==="
        python /patch_mtp_ptr_wrap.py

        echo "=== STARTING vLLM ==="

        exec vllm serve "llmfan46/Qwen3.6-35B-A3B-uncensored-heretic-Native-MTP-Preserved-GPTQ-Int4" \
          --quantization gptq \
          --dtype float16 \
          --max-model-len 163840 \
          --gpu-memory-utilization 0.9 \
          --kv-cache-dtype fp8 \
          --port 9932 \
          --max-num-seqs 64 \
          --max-num-batched-tokens 16384 \
          --enable-auto-tool-choice \
          --tool-call-parser qwen3_coder \
          --served-model-name Qwen3.6-35B-A3B \
          --language-model-only \
          --reasoning-parser qwen3 \
          --speculative-config '{"method":"mtp","num_speculative_tokens":4}'

The three MTP patch scripts are from the Intel Arc Pro B70 Inference Cookbook by SergiioB.

RELATED
2026-10-16 · vLLM XPU · 1x B70 · ctx 163840