Vissza a blogra

122B-os modell egy DGX Sparkon: élesben mérve

Qwen3.5-122B-A10B NVFP4 single Sparkon — meddig bírja, hol törik el, és érdemes-e DocAI-be tenni

A februári Qwen3.5-122B-A10B kiadás óta a community thread-ekben csordogált a kérdés: megéri a 122B paraméteres MoE-t single Sparkon futtatni, vagy maradjunk a 35B-A3B-nél? A válasz három hónapig bizonytalan volt — vagy senki sem kapcsolta össze pontosan, mit változtat a vLLM build, a checkpoint, az MTP, az NVFP4 quantization és a gpu_memory_utilization flag.

Most összekapcsoltam.

Ez az írás dokumentálja, mit néz ki egy 76 GB-os modell betöltése a 121 GiB unified memóriába egy GB10 chipen, mennyit ad az MTP különböző workload-okon (rövidülne: nem ugyanannyit), miért fogja a vLLM autoselect-elni a FLASHINFER_CUTLASS MoE backendet — annak ellenére, hogy a régi thread-ekben mindenki azt írta, hogy SM121-en bukni fog, és mit jelent pontosan az hogy „a Spark bírja a 4 párhuzamos 100K-s kérést”.

Eddigi cikkek után ez egy single-Spark mérés. Nincs cluster, nincs second machine, nincs trükk — csak egy DGX Spark, egy NVFP4-es checkpoint, és egy production-relevant kérdés: futhatna-e a DocAI ezen a setup-on?

A számokat mind a saját Spark-omon mértem 2026. április 25-én, a Sehyo/Qwen3.5-122B-A10B-NVFP4 checkpointtal és a vLLM 0.19.2rc1.dev154+g1c2c1eb8b prebuilt wheel-jével eugr/spark-vllm-docker-ből.

A landscape gyorsan

Három élő NVFP4-kvantált 122B-A10B checkpoint van jelenleg:

  • Sehyo/Qwen3.5-122B-A10B-NVFP4 — community-tested, vLLM llm-compressor-ral kvantált, az extra_weights.safetensors-ban hozza az 5 GB BF16 MTP súlyokat. 81.5 GB.
  • txn545/Qwen3.5-122B-A10B-NVFP4 — NVIDIA Model Optimizer-rel kvantált, MTP súlyok NEM benne; kézi mergelés kell az eredeti 234 GB BF16-os modellből. 75.6 GB.
  • RedHatAI/Qwen3.5-122B-A10B-NVFP4 — hivatalos NVIDIA verzió, llm-compressor + save_mtp_tensors_to_checkpoint(). Hasonló méret.

A Sehyo-t választottam, két ok: az MTP súlyok már bent vannak (mentes egy órás extract-mergelési pénztől), és a community thread-ekben a legtöbb cross-validated mérés erre épül. A txn545 elméletileg picit jobb kvantálási minőséget adhat (NVIDIA hivatalos toolkit), de azt egy következő körre, amikor lesz magyar quality eval-harness-em — most a sebesség érdekes, és a sebességet az architektúra korlátozza, nem a kvantáló.

A build amit szerintem mindenkinek használnia kéne

A community fél éve evangelizálja az eugr/spark-vllm-docker-t, és ennek megvan az oka. A stock vLLM cu130-nightly image nem build-eli a CUTLASS NVFP4 MoE kerneleket SM121-re — a GB10 architektúrára nincs precompile-elt FP4 GEMM. Az eugr build pontosan ezt javítja: TORCH_CUDA_ARCH_LIST=12.1a, prebuilt FlashInfer és vLLM wheel-ek egy automated pipeline-ből, plus egy mods/ könyvtár modell-specifikus patch-ekkel.

Maga a build 2-3 perc, ha a base image (vllm/vllm-openai:cu130-nightly) már ott van a host-on. Source build-elés (40 perc FlashInfer + 20 perc vLLM) csak akkor kell, ha custom commit-ot vagy PR-t akarsz tesztelni.

git clone https://github.com/eugr/spark-vllm-docker.git
cd spark-vllm-docker
./build-and-copy.sh

Ennyi. Az image-et vllm-node néven menti.

A repo eddigi állapotában a recipes/qwen3.5-122b-fp8.yaml recipe-je cluster_only: true és tensor_parallel: 2 — vagyis a 122B FP8-at a maintainer két Spark-ra méretezte. A Sehyo NVFP4-es ~78 GB-ja viszont single Sparkon kényelmesen elfér, ezért a recipe-et figyelmen kívül hagytam, és a vllm-node image-et közvetlenül egy egyedi vllm serve paranccsal indítottam.

Egy meglepetés: FLASHINFER_CUTLASS SM121-en

Itt jött az első érdekesség. A community thread-ekben (kanthai/openclaw-spark, JungkwanBan/SPARK_Qwen3.5-122B-A10B-NVFP4) konzisztensen az áll, hogy a FlashInfer CUTLASS MoE FP4 backend SM121-en bukik, mert a cvt.e2m1x2 PTX instruction nincs támogatva a GB10-en. A megoldás: VLLM_USE_FLASHINFER_MOE_FP4=0, fall back native cutlass_moe_fp4 path-ra.

A vLLM 0.19.2 + a friss eugr build viszont más history-t mond. Az indítási logban:

INFO [nvfp4.py:283] Using 'FLASHINFER_CUTLASS' NvFp4 MoE backend out of potential backends:
['FLASHINFER_TRTLLM', 'FLASHINFER_CUTEDSL', 'FLASHINFER_CUTEDSL_BATCHED',
 'FLASHINFER_CUTLASS', 'VLLM_CUTLASS', 'MARLIN', 'EMULATION'].

A vLLM autoselectelt FLASHINFER_CUTLASS-t, environment variable, kényszerítés, semmi.

A repo git log-ja mutatja az okot: d49fac1 Re-enable flashinfer_cutlass. Az eugr build mostanra olyan FlashInfer/CUTLASS verziót pull-ol, ami SM121-re már lefordul. A community lore tehát elavult, és érdemes nem szó szerint venni a régi forum thread-eket. Ami fél éve igaz volt, ma nem feltétlen.

Egy másik buktató: huggingface-cli deprecated

Apró, de nem-nyilvánvaló: a 2026 elején kiadott huggingface_hub 1.x megszüntette a huggingface-cli parancsot, helyébe hf lépett. A huggingface-cli download ... üres logot ad és kilép — az új CLI-t kell használni:

hf auth login   # az xet rate limit miatt ez kötelező, public repokhoz is
hf download Sehyo/Qwen3.5-122B-A10B-NVFP4 \
   --local-dir /opt/vllm/qwen35-122B/models/Qwen3.5-122B-A10B-NVFP4-Sehyo

Az xet backend (HF új CAS rendszere) anonim klienseket rate-limitel416 Range Not Satisfiable hibákat dobál public repokra is, ha nem vagy bejelentkezve. Egy gyors hf auth login token-nel megoldódik.

A 76 GB letöltése autentikálva ~15 perc volt egy gigabit kapcsolaton.

A cold start anatómiája

docker run -d --name vllm-122b-nvfp4 \
  --runtime=nvidia --gpus all --privileged --network host --ipc=host \
  -v /opt/vllm/qwen35-122B/models/Qwen3.5-122B-A10B-NVFP4-Sehyo:/models/qwen35-122b-nvfp4:ro \
  -v ~/.cache/vllm:/root/.cache/vllm \
  -v ~/.cache/flashinfer:/root/.cache/flashinfer \
  -v ~/.triton:/root/.triton \
  -e NCCL_IGNORE_CPU_AFFINITY=1 \
  vllm-node \
  vllm serve /models/qwen35-122b-nvfp4 \
    --served-model-name qwen35-122b-nvfp4 \
    --port 8000 --host 0.0.0.0 \
    --max-model-len 131072 \
    --max-num-seqs 4 \
    --max-num-batched-tokens 8192 \
    --gpu-memory-utilization 0.90 \
    --kv-cache-dtype fp8 \
    --enable-prefix-caching \
    --trust-remote-code \
    --enable-auto-tool-choice \
    --tool-call-parser qwen3_coder \
    --reasoning-parser qwen3 \
    --speculative-config '{"method":"mtp","num_speculative_tokens":2}' \
    --default-chat-template-kwargs '{"enable_thinking": false}'

A startup minden részletének időzítése:

PhaseIdő (cold)Idő (warm cache)Megjegyzés
CUDA + tokenizer init~20s~20sKonstans
Loading weights (76 GB)501s557sDisk-bound, EXT4
Drafter (MTP) loading73s84s5 GB BF16, ugyanonnan
torch.compile (backbone)36.5s10.1sCache hit jelentős
torch.compile (eagle_head)6.6s0.25sCache hit erős
FlashInfer autotune~10s~8sPer-config tuning
CUDA graph capture12-17s11-15sPIECEWISE mode
Total~12 perc~12 perc

Két dolog érdekes itt.

Az első: a 76 GB-os weight loading 8 perc 21 másodperc — és ez nem javul cache-ből. A vLLM ezt explicitten meg is mondja az indító logban:

Filesystem type for checkpoints: EXT4. Checkpoint size: 75.89 GiB.
Available RAM: 41.40 GiB.
Auto-prefetch is disabled because the filesystem (EXT4) is not a recognized
network FS (NFS/Lustre) and the checkpoint size (75.89 GiB) exceeds 90% of
available RAM (41.40 GiB).

A 121 GiB unified memóriából csak 41 GiB jutott file cache-nek indításkor (a vLLM container, az egyéb processek, és a futáskor allokálódó struktúrák foglalják a többit). A 76 GB checkpoint nem fér el a 41 GB cache-be, így minden restartnál a teljes diszk-olvasást újra meg kell csinálni. NFS vagy Lustre fájlrendszeren a vLLM auto-prefetch tudna gyorsítani, EXT4-en nem.

A második: a torch.compile cache nagyot dob. A backbone modell compile-jánál 36.5s → 10.1s, a draft head-nél 6.6s → 0.25s. Ezeket mindenképp érdemes mounted volume-ban tartani (~/.cache/vllm-be), különben minden restart 40+ másodpercet pazarol.

Production szempontból a 12 perces startup nem rosszabb mint egy normál microservice deploy ablakja, de kell hozzá egy deploy stratégia: blue-green-szerű flow, ahol az új container felindul, smoke-tesztelődik, és csak utána kapcsolódik forgalomra.

Memory budget a 121 GiB unified pool-ban

Model weights (NVFP4):           76.02 GiB
KV cache (fp8, 128K, 4 seq):     30.33 GiB    → 595,584 tokens
CUDA graph memory:                0.27 GiB
torch.compile / FlashInfer:      ~5 GiB
Container + Python + scheduler:  ~5 GiB
─────────────────────────────────────────
Total used:                     ~117 GiB

A gpu-memory-utilization 0.90 flagnél a vLLM 121.7 × 0.9 ≈ 110 GiB-ot foglal magának, és ebből kapja meg a 30 GiB KV cache pool-t. Ha 0.92-re emelnéd, +1 GiB KV-t kapnál, de OOM-kockázat van, mert a CUDA graph capture run-time-ban allokál.

A 595K token KV pool elég 4 párhuzamos 128K kontextusra is — 4 × 131072 = 524K, és a vLLM blokkos allokátora dinamikusan oszt el. A startup logban olvasható szám:

Maximum concurrency for 131,072 tokens per request: 12.89x

Ami azt mondja, hogy ha a kérések átlagosan 50%-os kontextus-kihasználtsággal mennek (ami real-world-ban realistic), akkor ~13 párhuzamos kérést bír. Worst case (mindenki maxon) ~4-5×.

Single-stream tok/s — 5 workload, 4 setup

Itt a fő összefoglaló a single-stream (concurrency=1) mérésekből. A benchmark scriptem 1 warmup + 3 measured run-t csinál minden workloadon, mediánt jelentek. MTP-2 mindenhol bekapcsolva, thinking off (--default-chat-template-kwargs '{"enable_thinking": false}'), temperature=0.

Workload32K default32K tuned128K tunedDescription
Q&A24.725.225.620 token magyar prompt, 256 token output
Code30.129.730.1Python binary search request, 300 token
JSON-KIE31.030.730.9Magyar számla kinyerés JSON-ba
Magyar23.723.924.6200 szavas magyar összefoglaló
Long-RAG-8K26.925.726.18K kontextus + kérdés, 256 token
Long-RAG-32Kn/an/a26.430K kontextus + kérdés, 256 token

A három setup különbsége:

  • 32K default: --max-model-len 32768, --max-num-batched-tokens 4096, no prefix caching
  • 32K tuned: --max-num-batched-tokens 8192, --enable-prefix-caching hozzáadva
  • 128K tuned: ugyanaz, --max-model-len 131072-re emelve

Két meglepő megfigyelés.

Az első: a 128K-s setup ugyanúgy gyors (sőt picit gyorsabb), mint a 32K-s, kis kontextusú kéréseken. Ezt nem vártam — a max_model_len növelése elméletileg több KV blokkot allokál és bonyolultabb scheduling-et okoz. A gyakorlatban ez nem érződik. Production ajánlás: --max-model-len 131072 egyszer, és ne fuss külön 32K-s instance-t. A unified memory budget is alig változik (30.33 GiB KV vs ~31 GiB volt 32K-n).

A második: a tuning szinte semmit nem ad single-stream-en. A --max-num-batched-tokens 4096 → 8192 változás ±1% tartományon belül mozog. A vLLM warning a default 4096-osnál azt mondta, hogy az MTP-vel suboptimal — ez koncurrent terhelésen lesz fontos, single-stream-en nem.

A --enable-prefix-caching viszont egy helyen ütött: a Long-RAG TTFT-jét drasztikusan csökkentette.

TTFT — ahol a prefix caching dolgozik

Workload32K default TTFT32K tuned TTFT128K tuned TTFT
Q&A (~20 tok)0.27s0.27s0.27s
Code (~30 tok)0.28s0.28s0.28s
JSON-KIE (~200 tok)0.44s0.44s0.44s
Magyar (~30 tok)0.30s0.29s0.29s
Long-RAG-8K (~7500 tok)4.41s2.59s2.55s
Long-RAG-32K (~30K tok)n/an/a3.87s (warm) / 18.11s (cold)

A Long-RAG-8K-n a TTFT 4.41s → 2.59s (-41%) csak a --enable-prefix-caching flag-től. A benchmark script 4-szer küldi ugyanazt a hosszú prompt-ot egymás után, tehát a 2-3-4. run prefix cache hit, a TTFT egy része a fix prefix tokenizálását spórolja.

A Long-RAG-32K első cold run TTFT-je 18.11 másodperc, prefix cache hit-tel 3.87s — a vLLM majdnem teljes egészében cache-eli a 30K kontextus-prefix-et, és csak a néhány utolsó (nem-fix) tokent prefilleli újra. Ez egy 5×-ös gain ami real-world RAG-ban (ahol gyakran ugyanaz a system prompt + retrieved chunk-ok elejüek tartalmaznak fix elemeket) érdemi user perception javulást ad.

A vLLM a Mamba-cache + prefix-caching kombinációhoz ad egy figyelmeztetést:

Mamba cache mode is set to 'align' for Qwen3_5MoeForConditionalGeneration
... Its support for Mamba layers is experimental.

A Qwen3.5 hibrid GatedDeltaNet architektúrában a Mamba layer-ek prefix cache-elése kísérletes. A mérésekben nem láttam quality regressziót (a Long-RAG-8K outputjai értelmesek), de production-ben érdemes a chat_template_kwargs és a system prompt rögzített prefix-ét dokumentálni — mert ha az változik request-ről request-re, a prefix cache nem tud hit-elni.

MTP acceptance — workload-függő, és nagyon

Itt jön talán a legérdekesebb adat a cikkben. Az MTP acceptance rate (mennyi a draft tokenből fogadódik el) drámaian függ a workload típusától:

WorkloadMTP-2 acceptance (single-stream)
JSON-KIE100.00% (3/3 run azonos)
Code94-99% (run-by-run kicsi variance)
Long-RAG-32K74-81%
Long-RAG-8K71-78%
Q&A67-74%
Magyar63-67%

A JSON-KIE 100%-os acceptance rate megdöbbentő. Egy 301 token output-ban minden speculatív tokent a draft eltalál. Magyarázat: a JSON struktúra annyira előrejelezhető (kapcsos zárójelek, ismétlődő kulcsnevek, vesszők, idézőjelek), hogy a kis MTP draft head triviálisan kitalálja a következő tokeneket. A modell tényleg csak a mező-értékeknél „gondolkodik” — a struktúrát végigfutja.

A natural language workloadok (Magyar, Q&A) ~63-70%-on mozognak, ami a community báziseknek megfelelő szám.

Production következmény: a DocAI-ban a strukturált output use case-ekre (számla KIE, proposal canvas JSON, company lookup eredmény) az MTP gyakorlatilag dupla decode tok/s-t ad. A natural language chat agent-en csak ~1.4×-es gain.

A 100% acceptance ihlet tovább: érdemes lenne num_speculative_tokens=3-mal próbálkozni. Ha a draft 2 tokent triviálisan eltalál, valószínűleg 3-at is 80%+ pontossággal — és 80% × 3 token = 2.4 elfogadott token per step több mint a jelenlegi 100% × 2 token. Ez egy következő körre marad.

Concurrent stress — ahol a Spark megmutatja magát

Eddig single-stream számokat néztünk, ami egy felhasználós scenario. Production-ben ritkán ez van — több párhuzamos kérés érkezik, és az aggregate throughput (nem a per-request) az ami számít.

Egy benchmark_concurrent.py scriptet írtam, ami N szállas worker pool-lal hív API-t megadott időtartamban, mix-elt workload típusokkal. Három mix profile-t teszteltem:

  • uniform_short: 4 párhuzamos szál, mind rövid prompt (Q&A + Code + JSON + Magyar round-robin), 90 másodperc
  • mixed_typical: 4 párhuzamos szál, 3 rövid + 1 Long-RAG-8K (a „DocAI realistic mix”), 90 másodperc
  • long_only_128k: 4 vagy 2 párhuzamos szál, mindegyik ~108K token kontextus, 90/180 másodperc — a stress test

A számok:

MixConcurrencyDurationReqs doneAggregate tok/sMTP accept
uniform_short490s2063.8676.13%
mixed_typical490s2057.6573.89%
long_only_128k490s814.6575.89%
long_only_128k2180s66.5475.84%

Az uniform_short aggregate 63.86 tok/s2.1× a single-stream JSON-KIE-csúcs (30.9 tok/s). Pontosan ezt vártam egy MoE modelltől: 4 párhuzamos request különböző expertekt aktivál, így a 273 GB/s memory bandwidth jobban kihasználódik (csak ~10B aktív paraméter olvasódik be tokenenként, és a 4 request különböző subset-et használ).

A mixed_typical 57.65 tok/s — kicsit alacsonyabb, mert a Long-RAG-8K a 4 szál egyikét fogja prefill alatt. A többi 3 szál még eközben generál, ezért az aggregate még mindig magas.

A long_only_128k adat azonban a sztori fő tanulsága:

A Spark fal: 4× 100K-s párhuzamosan kéne — sajnos nem

Az első mérés 4 szálas, 90 másodperc — 0 request fejeződött be. Ránézve a vLLM logba: prompt overflow. A workload script make_long_rag_messages(115000) becslése 4 char/token volt, magyar szöveggel az tényleges tokenizáció ~1.14× annyi → 130817 input + 256 output = 131073, 1 token overflow a 131072 limiten. A vLLM mindegyik kérést 400 Bad Request-tel utasította vissza, és a script errors: 0 mezője hibásan jelentett (a lehetőség azonnal kapott választ, nem az explicit timeout volt a probléma).

A target tokent 95000-re csökkentve (~108K tényleges magyar token), a tényleges állapot megmutatkozott:

c=2, 180 másodperc:

  • 6 request fejeződött be 182.3 másodperc alatt → kb. 60s/request átlag
  • TTFT p50: 20 másodperc (két párhuzamos prefill chunked módon)
  • TTFT p95: 112 másodperc (worst-case egy késő érkezőre)
  • Decode p50: 20.6 tok/s per request (közel single-stream szint)
  • Aggregate: 6.54 tok/s

c=4, 90 másodperc:

  • 8 request fejeződött be 106.2 másodperc alatt → ~52s/request
  • TTFT p50: 20.66s, p95: 40.33s
  • Decode p50: 6.2 tok/s per request
  • Aggregate: 14.65 tok/s

A c=4 vs c=2 aggregate-ben 2.2× — vagyis több párhuzamosság kicsit jobb a teljes throughputra, de a per-request decode tok/s 20.6-ról 6.2-re zuhan (3.3×-os esés). Egy egyedi user szempontból ez katasztrofális: a 6.2 tok/s azt jelenti, 1 token / 160ms — ahol egy 200 szavas magyar válasz (~250 token) wall-clock-ban ~40 másodperc, plus a 20s prefill, plus a queue-be várás.

A Spark nem alkalmas több felhasználós, kontextus-nehéz interaktív loadra ezzel a 122B-NVFP4 modellel. Mire való:

  1. Single-user interaktív DocAI chat rövid promptokkal (24-31 tok/s, 0.3-0.5s TTFT) ✅
  2. DocAI batch KIE strukturált JSON output (31 tok/s, 100% MTP acceptance) ✅
  3. Single RAG query akár 30K kontextusig (3.87s warm TTFT) ✅
  4. Multi-user chat rövid promptokkal (4 user, ~16 tok/s/user, jó UX) ✅
  5. Multi-user RAG középhosszú kontextussal (~57 tok/s aggregate) ⚠️ degraded UX
  6. Multi-user dokumentum-elemzés 100K+ kontextussal ❌ nem alkalmas

A 6-os pontot második Sparkkal lehetne enyhíteni (TP=2 cluster, ~70 tok/s aggregate a community szerint), vagy egy NVFP4 backend bekapcsolásával (Albond v2 hybrid INT4+FP8 + INT8 LM head ~51 tok/s single-stream a community szerint, de quality regresszió kockázat).

A számok mögött: mit is mértünk valójában

Egy zárszó arról, hogy a fenti táblázatok mit jelentenek és mit nem. A benchmark egy fix prompt-ot és fix max_tokens-t használ, és a script ugyanazt a 4-5-6 promptot futtatja. Ez a setup kifejezetten kedvez a prefix caching-nek — a Long-RAG-8K-n a 2.59s TTFT a 4-szer ugyanazon prompt-tal mért érték. Egy real-world DocAI use case-ben, ahol minden RAG retrieval más chunkokat hoz, a TTFT inkább a cold first run-hoz lesz közelebb (4.4-18 másodperc).

A decode tok/s ezzel szemben nagyrészt prompt-független (a memory bandwidth-bound throughput nem nagyon függ attól, mit generálsz, csak hogy mennyit). A ~25-31 tok/s single-stream tartomány valós DocAI prod terhelésen is hasonló lesz.

Egy másik kaveat: a enable_thinking: false flag-gel mértünk. Ezt KIE-feladatokra hivatalosan ajánlják (a Qwen3.5-ös research card és a community thread-ek konzisztensen). Egy „thinking on” mérés más sztorit mondana — egy egyszerű Q&A 1500+ tokenre nőne (a model magában gondolkodik), és a real wall-time arányosan többszörös lenne. Erre a DocAI-nak nincs szüksége.

Konklúzió: érdemes-e DocAI-be tenni?

Még nem. Két tényező hiányzik a végleges ítélethez.

Az első: quality benchmark. A jelenlegi prod modell a Qwen3.6-35B-A3B-FP8. A 122B-NVFP4 elméletileg több paraméterrel okosabb, de az NVFP4 quantization ront valamennyit. Hány százalékot pontosabb a magyar számla KIE-én? Mennyivel jobb a magyar legal Q&A? Ezt a mérést egy következő körben fogom csinálni, a memóriámban már szereplő „DocAI magyar eval harness” részeként. A throughput szempontjából:

ModellSingle-stream JSON-KIE tok/sAggregate (4 user)
Qwen3.6-35B-A3B-FP8 (jelenlegi prod)~50-60~80-100
Qwen3.5-122B-A10B-NVFP4 (mért)30.963.86

A 122B lassabb mint a 35B-ABF8 ezen a workload-on. Nyilvánvalóan: kétszer annyi memóriát kell végigolvasni tokenenként. Az MTP behozza ezt 2.1×-szel, plus a 100% acceptance JSON-on, de még akkor is alulmarad.

A második: a valódi production usage pattern. A jelenlegi DocAI single-tenant — egy magyar SME ügyfél, max 3-5 user párhuzamosan, többségében rövid chat + KIE batch + alkalmi RAG. Erre a 122B-NVFP4 vagy a 35B-FP8 mindketten elégségesek. Ha a quality előny érzékelhető — pl. a magyar legal Q&A markánsan jobb a 122B-n —, akkor a sebesség-veszteség elfogadható ár, mert a user latency még akceptábilis (32K kontextusú JSON-KIE 10s-on belül megvan). Ha a quality előny nem érzékelhető, maradunk a 35B-FP8-on, mert single-stream gyorsabb és kevesebb memory pressure.

A Spark hardware oldalt a mérések megerősítik: single-stream 122B-NVFP4 production ready single Sparkon, multi-stream középhosszú kontextusra is megfelelő, multi-stream 100K+ kontextusra nem skálázódik.

Mit lehet még csinálni

Pár kísérlet ami a következő körre marad:

  • num_speculative_tokens=3 — a JSON-KIE 100% acceptance arra utal, hogy a 2-es draft trivialísan eltalálódik, érdemes próbálkozni 3-mal. Becsült gain: +20-30% strukturált workloadon.
  • txn545/Qwen3.5-122B-A10B-NVFP4 kontroll-mérés — picit más kvantáló (NVIDIA Model Optimizer), kérdés hogy a magyar quality változik-e.
  • Albond v2 hybrid INT4+FP8 — community report szerint single Sparkon 51 tok/s, de „Qwen3.5-35B Native FP8 + MTP is much better than Qwen3.5-122B int4-AutoRound” — quality regresszió kockázat.
  • Második Spark cluster (TP=2) — a 397B-MoE-hez amúgy is kell, és a 122B-n a community 70 tok/s körüli aggregate-et lát. Ha a multi-user pattern elindul, ez lehet a megoldás. Pénzkérdés.
  • SGLang — a txn545 checkpoint tartalmazza az SGLang-támogatást is. Egyező hardware-en nem várható radikális gain (memory bandwidth bound), de a strukturált output (constrained JSON) gyorsabb lehet. Build-elési költség nem kicsi, ezért csak ha a JSON-KIE sebesség kifejezett bottleneck.

Pár utolsó adat a teljességhez

A 14 perces hidegindítás után a Spark stabil futott 90+ percen át a benchmark sorozat alatt, OOM nélkül, restart nélkül. A nvidia-smi 11 GB GPU memory használatot mutatott (a többi ~76 GB CPU oldalán van a unified memóriában). A container 3.22% CPU-t használt idle-en, és a vLLM internal scheduler-loop kb. 10-20% CPU-t használt active inference alatt.

Egy single Spark áram-felvétele a benchmark alatt mért módon: 3-10W idle, ~150-180W full inference. A LPDDR5x memory az ami fűt, nem a GPU compute (273 GB/s sustained random access ezen a chip-méret alatt komoly igény).

A teljes setup (build, modell letöltés, 4 mérési kör, 3 restart) ~3 óra volt egy-egy döntés között a felhasználói részemen, ami azt mondja, hogy 24 órán belül egy tetszőleges DGX Spark tulajdonosnak végrehajthatóak ezek a mérések. A eugr/spark-vllm-docker repo, a Sehyo checkpoint, és a fenti 8 vLLM flag — ennyi.

A számok alapján a 122B-NVFP4 egy single Sparkon technikailag megy, és bizonyos use case-ekre alkalmas. A produktív döntés — DocAI-ben jó-e — egy quality eval-tól függ, és arra még nincsenek számaim. De a sebességet most mérjük, és tudunk mire mondani igent.


Rendszer: NVIDIA DGX Spark, GB10 (SM 12.1), 128 GB LPDDR5x unified memory
Modell: Sehyo/Qwen3.5-122B-A10B-NVFP4 (76 GB checkpoint, MTP súlyokkal együtt)
vLLM: 0.19.2rc1.dev154+g1c2c1eb8b (eugr/spark-vllm-docker prebuilt wheel, cu130-nightly base, 2026-04-25)
MoE backend: FLASHINFER_CUTLASS (autoselected SM121-en)
Benchmark eszköz: saját benchmark_concurrent.py + vllm bench serve

A teljes JSON eredmény-szett, a docker run paraméterek és a concurrent benchmark script elérhető — ha érdekel a reprodukció vagy a részletes percentile-eloszlások, írj.