Why the config in the engine compose files (vllm_xpu/compose.yaml and
scaler/compose.yaml) is the way it is. For how to operate the
stack see README.md; for a configuration overview see INTEL_ARC_B60.md.
All values here are empirical on the Intel Arc Pro B60 (22.71 GiB usable). The
stack upgraded from intel/vllm:0.17.0-xpu to intel/vllm:0.21.0-ubuntu24.04;
the gpt-oss-20b boot and the 0.75 util ceiling were re-validated on 0.21.0, but
the other 0.17.0-era measurements below (Qwen3 context caps, the 0.86-OOM edge, the
reasoning-effort latencies) have not been re-run on 0.21.0. Nothing here is
portable to other cards or images without re-checking. The host is Linux only —
the Intel xe GPU driver is Linux-specific, so Windows and macOS are out of scope.
On this XPU build, --gpu-memory-utilization sizes the weights + KV pool but
does NOT cap torch.compile/Inductor kernel + workspace buffers, which keep
growing as new request shapes get compiled.
At 0.86 the card filled to 22.67 / 22.71 GiB (~0.04 GiB free) → OOM-on-the-edge, instability, and 504s. 0.75 (~17 GiB: ~13.7 GiB weights + ~3.3 GiB KV pool) leaves ~2.5 GiB of real headroom for that uncapped compile growth.
Re-validated on 0.21.0-ubuntu24.04 (compiled, production flags): clean boot, KV
pool ~3.96 GiB, no OOM at 0.75 — the ceiling carries over unchanged. The 0.86-OOM
edge above was characterised on 0.17.0-xpu and not re-tested on 0.21.0.
The trap: util looks like a headroom dial but it doesn't account for the
compile buffers. To grow capacity, raise --max-model-len and re-check real
VRAM — never just bump util, or you'll OOM on the edge again.
gpt-oss-20b is an MoE with ~13.7 GiB MXFP4 weights (~3.6B active params). It's
natively 128k (YaRN, max_position_embeddings=131072), but --max-model-len 65536 keeps the reserved KV pool + activation buffers small. gpt-oss's
alternating sliding-window(128) + full-attention layers halve per-request KV
cost, so the ~3.3 GiB pool holds 64k with concurrency to spare.
vLLM does a KV-cache pre-check at startup. If max-model-len × KV-per-token
doesn't fit in the VRAM left after weights + compile artifacts, startup fails
with an explicit error ("the model's max seq len … is larger than the maximum
number of tokens that can be stored in KV cache").
Methodology: pick an ambitious target, drop to the next round value if the pre-check rejects. Don't compute it analytically — compile overhead isn't predictable from outside.
Known-good empirical values on the B60:
| Model | Weights (loaded) | Working --max-model-len |
Notes |
|---|---|---|---|
| gpt-oss-20b | ~13.7 GiB | 65536 (64k) | At 0.75 util; the value shipped in vllm_xpu/compose.yaml |
| Qwen3-32B-AWQ | 18.14 GiB | 7168 | 12k and 10k both failed the pre-check |
Weights here are the loaded figure vLLM reports at startup (GiB); the ≈GB on-disk cache sizes in README/INTEL_ARC_B60 are the same weights in GB units (18.14 GiB ≈ 19 GB).
To go bigger later: raise --max-model-len AND re-measure real VRAM
headroom. Drop to 32k/16k if a future swap's pre-check rejects at startup.
- MXFP4 is the only viable format for gpt-oss. Its weights are natively
MXFP4; loading as BF16 inflates to ~40 GB and won't fit 24 GB. Intel's
container ships MXFP4 kernels for gpt-oss specifically. If MXFP4 ever fails to
load on a newer image, fall back to
intel/vllm:0.10.2-xpu(the version Intel publicly benchmarked) — do not try BF16, it doesn't fit. - Qwen: AWQ is the working path. The official
Qwen/*-FP8weights are blocked by an upstream vLLM XPU bug (RMSNormQuantFusionPassNameError). Each Qwen swap-back also means switching--reasoning-parsertoqwen3(hybrid thinking;/no_thinkdisables) and lowering--max-model-len.
Effort is a top-level request field, reasoning_effort: low|medium|high
(default medium). It's a quality/latency lever, not a throughput lever:
low≈ 307 ms TTFT-to-content — fastest to a visible answer.highcan starve content ifmax_tokensis too low (reasoning consumes the budget before any content is emitted). Pushmax_tokensup for high effort on non-trivial prompts.
- The stack runs
intel/vllm:0.21.0-ubuntu24.04(reports vLLMv0.21.1.dev17+g0a4756bb5; thedevsuffix is an scm artifact). The tag scheme dropped the-xpusuffix of older images, but it is the Intel Arc/XPU build —device_config=xpuand torch.compile runs on the B60, verified by booting gpt-oss-20b on it. - Device passthrough differs from
0.17.0-xpu: 0.21.0 requires the whole/dev/driplus a/dev/dri/by-path:romount (oneCCL enumerates viaby-pathon warm-up) or it won't boot. Details invllm_xpu/compose.yamland the README's Upgrading the vLLM image. - Gemma 4 arches are now registered (
gemma4/gemma4_mm) — unlike0.17.0-xpu, which topped out at Gemma3n. That clears the architecture gate, but running Gemma 4 on the B60 is still unproven here (XPU quant-kernel gaps), so this stack stays on gpt-oss-20b. Theqwen3andopenai_gptossreasoning parsers are present as before. - Reasoning trace field is still
message.reasoning, notreasoning_content(re-verified on 0.21.0) — see README.md for the consumer-parsing implication. - Predecessor:
0.17.0-xpuwas a frozen release-tag build (reported vLLM0.1.dev14456) that topped out at Gemma3n — kept here for upgrade context.
Two interchangeable engine images serve the same gpt-oss-20b on the same
:8000, so either can be production — one at a time (single GPU). Each has its
own folder: vllm_xpu/compose.yaml (stock intel/vllm, the default)
and scaler/compose.yaml (Intel's B-series-optimised llm-scaler-vllm
fork). The operator swap/run procedure is in the README.
Why compare: measure whether the llm-scaler fork decodes gpt-oss-20b
faster than the stock image. The single-stream decode baseline of ~60 tok/s
on the B60 (via bench.sh) was measured on 0.17.0-xpu; re-baseline on the
current 0.21.0-ubuntu24.04 stock image before comparing — that's the yardstick.
Note the stock image has since jumped 0.17→0.21, so the fork (built on an
older vLLM base) is no longer strictly newer than what it's being compared to.
Why two folders, not a compose profile: one GPU (~22.7 GiB) and gpt-oss-20b
needs ~17 GiB, so the two engines can't coexist (~31 GiB = OOM). A separate
folder per engine means every up must target an engine's folder (cd into it,
or -f its compose.yaml), so you can't start both by accident and "which
engine is prod" is always explicit.
Image: pinned to intel/llm-scaler-vllm:0.14.0-b8.3.2 (the current build;
the fork's docs warn against :latest). b8.3.2 vs the prior b8.3.1 is only a
Qwen3.5/3.6-27B accuracy fix — no gpt-oss-20b impact — but it's the right base
for a first benchmark.
--enforce-eager caveat: the staged config boots with --enforce-eager,
which (a) disables torch.compile — removing the uncapped Inductor buffer growth
that forced 0.75 util on the stock image, so a higher util would be safe here
(we keep 0.75 to match the base vLLM engine) — and (b) gives a clean first
boot. But eager mode is slower than compiled, so it
under-states the scaler's real speed. Once it boots clean, drop
--enforce-eager and re-bench for the true number (watch VRAM; back off util if
it edges toward OOM). gpt-oss-20b is MXFP4 (pre-quantised) — do not pass
--quantization. The fork inherits upstream's parser flag names; if it renamed
them the server fails fast at startup with a clear arg error.
Context for future hardware or model swaps:
- B70 vs B60 — the Arc Pro B70 (32 GB) gives roughly 1.3× decode / 1.85× prefill plus context headroom over the B60, but does not unlock Gemma 4 (that's software-gated, not a VRAM limit).
- Multi-GPU — on a consumer board a second card typically only gets a chipset x4 link, so don't tensor-/pipeline-parallel across cards; run each card as an independent engine instead.
- Model freshness — gpt-oss-20b's knowledge cutoff is mid-2024. Fresher fast MoEs (e.g. Qwen3.5/3.6-35B-A3B AWQ ≈ 24 GB) don't fit the B60's ~22.7 GiB usable, so freshness is better addressed with RAG than with a model swap on this card.