Két nap, hat óra Triton tuning, egy GB10, és egy nagy semmi
Avagy hogyan tanultam meg, hogy a pure-kernel benchmark nem egyenlő a serving nyereséggel
Ez nem egy „x-szeres gyorsulást értem el” cikk lesz. Ez pont az ellenkezője: egy kétnapos tuning maraton, aminek a végén a production configom 5-7%-kal rosszabb a két hete futó verziónál, és ezt most szépen elmesélem, mert szerintem ez hasznosabb, mint egy újabb diadalmas blog.
Aki csak a végét akarja: a Triton MoE tuning a benchmark_moe.py --tune-nal a Qwen3.5-35B-A3B-FP8-ra a DGX Sparkon 6 órán át fut és ront ~10%-ot a prefill TTFT-n. A többi 9000 szó opcionális.
A setup
Van egy DocAI nevű projektem — dokumentum-feldolgozó SaaS magyar KKV-knak, könyvelőirodáknak, ügyvédi irodáknak. A hardver egy NVIDIA DGX Spark, rajta GB10 chip (Blackwell, SM 12.1, 128 GB unified LPDDR5x), a model pedig Qwen/Qwen3.5-35B-A3B-FP8 vLLM-en keresztül.
A konfigom pár hete rendben futott — --max-num-seqs 32, --gpu-memory-utilization 0.45, --max-model-len 131072, a szokásos FP8 KV cache. A vLLM image cu130-nightly volt, úgy 3 hete kihúzva. A workload vegyes: chat agent (hosszú rendszerpromt + tool schemák), KIE batch (OCR → JSON dokumentum-feldolgozás), plus egy Marker-alapú PDF pipeline section header processzorral.
Aztán elolvastam a saját doksimat arról a hónap eleji incidensről, ahol egy egyoldalas PDF 15 percre beragadt egy LLM hívás körül queue contention miatt. Ennek kapcsán gyűjtöttem egy listát, hogy mit lehetne még gyorsítani. A lista tetején ott volt:
Triton fused_moe tuning a GB10-re (közepes munka, becsült 1.5-2x gyorsulás)
A vLLM log ugyanis ezt sugdosta minden indulásnál:
Using default MoE config. Performance might be sub-optimal!
Config file not found: E=256,N=512,device_name=NVIDIA_GB10,dtype=fp8_w8a8,block_shape=[128,128].json
Na ezt gyerünk, gondoltam. Két nap és 6 óra compute után itt vagyunk.
Baseline mérés, mert nem akartam anekdotikus cikket
Először is kellett egy rendes benchmark. A vllm bench serve eszközzel három scenario-t mértem, hogy ne egyetlen számot mutogassak:
- A: single decode — 512 input, 512 output, batch=1. Klasszikus „egy user generálás alatt” mérés
- B: prefill-bound — 8192 input, 256 output, 4 concurrent. A KIE workload szimulációja
- C: concurrent contention — 2048 input, 512 output, 16 concurrent. A chat agent + KIE verseny
A --ignore-eos flag-et mindenhol bekapcsoltam (különben az output-len csak felső határ lenne, és a modell korán leállhat, torzítva a throughput-ot). --num-warmups 3 minden teszt előtt, seed=42 rögzítve. Ha már benchmark, akkor rendes benchmark.
Baseline eredmények (3 hetes nightly image)
| Teszt | Output tok/s | Mean TTFT | Mean TPOT |
|---|---|---|---|
| A: single decode | 48.92 | 190 ms | 20.11 ms |
| B: prefill (8k) | 75.88 | 4855 ms | 33.87 ms |
| C: concurrent (16) | 208.04 | 4828 ms | 67.61 ms |
Ez lesz a viszonyítási pont. 48.92 tok/s single decode, 4855 ms Mean TTFT a KIE workload-on, 208 tok/s total throughput 16 concurrent-tel. Jegyezd meg, ezeket a számokat sokat fogjuk látni.
Első meglepetés: a nightly frissítés rontott
Mielőtt indítanám a tune-t, frissítem az image-et, mondom. Hátha a 3 hét alatt beérett valami új kernel — a FlashInfer MoE backend támogatás, esetleg a CUTLASS fejlesztések. Ez is egy adatpont lesz a cikkhez: „mennyit ér pusztán egy nightly pull?”
docker pull vllm/vllm-openai:cu130-nightly
Új hash, új verzió: 0.19.1rc1.dev231+g9dd5ee011. Boot, logot nézem, három új sor ugrik be amik eddig nem voltak:
Selected CutlassFp8BlockScaledMMKernel for Fp8LinearMethod
Using Triton/FLA GDN prefill kernel
Asynchronous scheduling is enabled.
Mamba cache mode is set to 'align' for Qwen3_5MoeForConditionalGeneration
by default when prefix caching is enabled
Szép, új kernelek a dense FP8 linear layer-ekhez, új prefill kernel a linear attention layer-ekhez (a Qwen3.5-A3B hibrid arch miatt a 40 layer-ből 30 linear attention). Aszinkron scheduling mint új default. És egy Mamba cache mode is 'align' ami experimental címkével van megjelölve és azt írja „Please report any issues you may observe”. Na, ezt jegyezzük meg.
Rohanok mérni:
| Teszt | Baseline | Phase 2 (új image) | Δ |
|---|---|---|---|
| A: tok/s | 48.92 | 49.76 | +1.7% |
| B: Mean TTFT | 4855 | 5941 | +22% ⚠️ |
| B: tok/s | 75.88 | 70.06 | −7.7% |
| C: Mean TTFT | 4828 | 6893 | +43% ⚠️ |
| C: tok/s | 208.04 | 197.67 | −5.0% |
Várj. +22% TTFT? +43%? Az új nightly lassabb lett. Ez nem az amit vártam.
Nyomozás 1: az async scheduling
A vLLM forráskódban két új flag létezését derítettem ki:
--async-scheduling, --no-async-scheduling
--mamba-cache-mode {align,all,none}
Próbáltam az async-ot kikapcsolni először. Egy sed volt csak, de sajnos én voltam az akinek nem ment a parancs — persze kétszer kellett neki nekirugaszkodni, elsőre nem illeszkedett a kívánt sorra (a command: > folded scalar-nál a sortörések furcsán viselkednek). Végül manuális szerkesztéssel be a --no-async-scheduling.
| Teszt | Phase 2 (async ON) | Phase 2.5a (async OFF) | Δ |
|---|---|---|---|
| B: Mean TTFT | 5941 | 5249 | −12% ✅ |
| C: Mean TTFT | 6893 | 5153 | −25% ✅ |
Jó, ez segített. Az async scheduling új default a v0.19-ben, és prefill-heavy concurrent workload-on visszaesést okoz. Nem tudom pontosan miért — az elméletben az async a GPU utilization-t javítja, de ha a workload nem kihasználja, csak szinkronizációs overhead marad.
A throughput egyébként nem állt vissza (71.73 vs baseline 75.88). Maradt egy ~5% hátrány, aminek az okát kiderítettem, de rájöttem nem tudok vele mit csinálni.
Nyomozás 2: a mamba_cache_mode=align rejtély
A Qwen3.5-A3B egy hibrid attention arch: 10 full-attention layer + 30 linear attention layer. A linear attention layer-eknek recurrent state-jük van (mamba-szerűen), és a vLLM ezt külön cache-eli prefix caching-gel együtt.
A v0.19-ben új: van egy mamba_cache_mode="align" automatikus felülírás a Qwen3.5-MoE-re prefix caching esetén. Ezt próbáltam --mamba-cache-mode none-nal kikapcsolni, de hiába — a modell config hook (a vLLM-ben /usr/local/lib/.../models/config.py:310-348) felülírja amit a CLI flag ad. A boot log változatlanul mutatta:
WARNING Mamba cache mode is set to 'align' for Qwen3_5MoeForConditionalGeneration
by default when prefix caching is enabled
Tehát a maradék ~5% regresszió valószínűleg ettől van, és nem override-olható CLI-ben. A prefix caching teljes kikapcsolása megszüntetné (mert akkor nincs mamba align), de a chat agent-ünknek fontos a prefix cache. Szóval itt vesztettünk 5%-ot, és mozdulni nem tudunk rajta. Noted, de maradunk.
A főesemény: Triton MoE tuning
Oké, most jön a kaland. A benchmark_moe.py --tune letunelja a Triton fused_moe kernel paramétereit (block_m, block_n, block_k, num_stages, num_warps) a Qwen3.5-A3B architektúrájára (E=256 experts, moe_intermediate_size=512, topk=8). A várható eredmény: 1.5-2× gyorsulás a MoE kernel-en.
Az első próbálkozás:
ModuleNotFoundError: No module named 'ray'
Na de ez könnyen orvosolható: pip install --quiet ray && python3 benchmark_moe.py --tune. Második próba indul, első becslésem a tunelási időre: 25-40 perc, alapján hogy a default sweep 1-4096 batch méretre fut (én a közepes sweep-et választottam: 1, 4, 8, 16, 32, 64, 128, mert a max-num-seqs 32 miatt a reális batch méret nem megy 128 fölé serving közben).
Start tuning over 640 configurations...
Hát ez 640 config kernel konfig permutáció per batch. Az első batch 10 perc alatt jött. A második 20 perc. Kilencedik percben néztem fel és megkérdeztem Claude-tól, hogy muszáj-e végigvárnom, vagy elmehetek aludni.
Claude azt mondta: ne szakítsd meg, indítsd újra docker run -d detached módban --name-mel és perzisztens log fájllal. Megszakítottam a 45 percnyi futást (brutális), újraindítottam detached módban, megadtam magam a sorsnak és aludtam.
Reggel kiderült: a tuning 5 óra 48 percig tartott. Nagyon messze az eredeti 25-40 perc becsléstől. De a JSON kimenet szép:
Writing best config to /save/E=256,N=512,device_name=NVIDIA_GB10,
dtype=fp8_w8a8,block_shape=[128,128].json...
Tuning took 20905.83 seconds
Mind a 7 batch méretre tuned config. A JSON tartalmaz BLOCK_SIZE_M=16/32, BLOCK_SIZE_N=128/256, num_warps=8, num_stages=2-4 értékeket, workload-függő progresszióval. Szép tuned config.
Bind-mount a vLLM image fused_moe/configs/ mappájába (csak az egy fájlra, hogy ne takarjak le semmi mást), restart, és a boot log:
Using configuration from /usr/local/lib/python3.12/dist-packages/vllm/
model_executor/layers/fused_moe/configs/E=256,N=512,device_name=NVIDIA_GB10,
dtype=fp8_w8a8,block_shape=[128,128].json for MoE layer.
Nincs „Config file not found” warning. A tuned config aktív. Indulunk mérni.
Phase 3 eredmények — 6 óra tunelés után
| Teszt | Phase 2.5a (untuned) | Phase 3 (tuned) | Δ |
|---|---|---|---|
| A: tok/s | 49.01 | 48.94 | ≈0% |
| B: Mean TTFT | 5249 | 5857 | +11.6% 😬 |
| B: tok/s | 71.73 | 69.32 | −3.4% |
| C: Mean TTFT | 5153 | 5302 | +2.9% |
| C: tok/s | 204.39 | 204.46 | ≈0% |
A B TTFT ROSSZABB lett. Az A és C szinte változatlan.
Gyanakodtam hogy variancia lesz, csináltam két extra replikációt (seed=123, seed=456):
| Seed | Phase 3 B Mean TTFT |
|---|---|
| 42 | 5857 ms |
| 123 | 5678 ms |
| 456 | 5793 ms |
| Átlag | 5776 ms (±90 ms) |
Nope, nem variancia. A szórás ±90 ms, az átlag 527 ms-mal magasabb mint a phase 2.5a. Statisztikailag megbízhatóan rosszabb.
Fun fact: a throughput is konzisztensen rosszabb, 69.96 vs 71.73 tok/s (−2.5%).
6 óra tuning, és ront egy kicsit.
Hé, miért ront egyáltalán?
Ez volt a pillanat amikor leültem és őszintén feltettem magamnak a kérdést. A benchmark_moe.py egy pure-kernel benchmark — csak a MoE forward pass-t méri, izoláltan. De a vLLM serving kontextusában ez a kernel nem izoláltan fut:
- A chunked prefill megszabdalja a prefill-t különböző batch méretekre, amik közül a tuned JSON-ban csak egy-egy pont van. Két batch méret között (pl. 8 és 16) a default heurisztika hasznosabb lehet, mint a tunelt konfig ami csak ezekre a fix pontokra optimal.
- A CUDA graph capture több batch mérettel is capture-öl, és lehet, hogy a graph-ban „beégetett” kernel választás máshogy viselkedik, mint egy friss kernel launch.
- A Mamba cache align mode miatt a MoE forward pass nem egyedül fut, hanem egy komplex scheduler dönt arról, hogy melyik request melyik step-ben milyen batch-ben van.
Tehát a benchmark_moe.py azt méri ami nem releváns. A GB10-en a default Triton heurisztika a workload tényleges eloszlására jobb választást hoz, mint egy workload-agnostic tuning.
Ez a cikk fő tanulsága, amit megpróbálok élesen megfogalmazni: pure-kernel benchmark nem egyenlő serving benchmark. A benchmark_moe.py --tune egy micro-benchmark, ami a kernel execution time-ot optimalizálja — de egy valós serving workload-ban a kernel latency csak egy része a teljes latency-nek, és a tuning-gal nyert 5% kernel gyorsulás elveszhet a scheduler interakciókban.
Még pár kísérlet, mert nem adtam fel
gpu-memory-utilization 0.55
„Lehet nem volt elég KV pool.” Emeltem 0.45 → 0.55. A KV pool 174k → 467k tokenre nőtt (2.7×). Lássuk:
| Teszt | Phase 3 (0.45) | Phase 4 (0.55) | Δ |
|---|---|---|---|
| A: tok/s | 48.94 | 48.67 | ≈0% |
| B: Mean TTFT | 5776 avg | 5744 avg | ≈0% |
| C: Mean TTFT | 5302 | 5571 | +5% 🤔 |
| C: tok/s | 204.46 | 204.01 | ≈0% |
Semmi. A KV pool 174k tokenen sem volt szűk (16 concurrent × 2.5k = 40k token max aktív). A 0.55 csak felesleges memória-elvétel a doc-pipeline elől. Ha ezt élesítem, a Marker/Surya modellek gondba kerülhetnek.
enforce-eager (CUDA graph OFF)
„Hátha a graph compile tesz valami hülyeséget.” Kipróbáltam --enforce-eager-t.
A: tok/s: 30.02 (vs 48.94)
B: Mean TTFT: 7460 (vs 5776)
−33% decode throughput. A CUDA graph érdemben számít. Rögtön visszavettem. (Bónusz: a boot ~70 másodperccel rövidebb lesz eager módban mert nincs torch.compile, de ez nem ér 33% teljesítményvesztést.)
VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS=1
A log maga ajánlotta. Ez pontosabb CUDA graph memória-becslést ad. Várható hatás: kicsit több KV pool. Ingyen win, gondoltam.
Valóság: nem win, hanem accounting fix. A log konkrétan ezt írja ki:
The current --gpu-memory-utilization=0.4500 is equivalent to
--gpu-memory-utilization=0.4434 without CUDA graph memory profiling.
To maintain the same effective KV cache size as before, increase
--gpu-memory-utilization to 0.4566.
Az env var pontosabb, igen. De ugyanannál a 0.45-nél kisebb KV pool-t ad, mert pontosabban elszámolja a CUDA graph memóriát. Ha ugyanannyit akarsz mint eddig, emelned kell 0.4566-ra.
Ingyen ebéd nincs. A log őszinte volt, csak én reméltem valami mást.
A végső production config
Két nap, sok kávé, 6 óra tuning compute, kilenc fázis mérés. A végén:
services:
qwen35_vllm:
image: vllm/vllm-openai:cu130-nightly
environment:
HF_TOKEN: ${HF_TOKEN}
TORCHINDUCTOR_COMPILE_THREADS: "1"
VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS: "1" # pontosabb accounting
volumes:
- ~/.cache/huggingface:/root/.cache/huggingface
- triton-cache:/root/.cache/torch/triton
# NINCS MoE tuned config bind-mount — nem érte meg
command: >
Qwen/Qwen3.5-35B-A3B-FP8
--max-model-len 131072
--max-num-batched-tokens 65536
--gpu-memory-utilization 0.45
--max-num-seqs 32
--kv-cache-dtype fp8_e4m3
--enable-chunked-prefill
--enable-prefix-caching
--no-async-scheduling # egyetlen igazi win
--reasoning-parser qwen3
--enable-auto-tool-choice
--tool-call-parser qwen3_coder
--limit-mm-per-prompt '{"image":1}'
--trust-remote-code
Végső számok (phase 6) vs. baseline
| Teszt | Baseline (3 hetes) | Phase 6 (production v1) | Δ |
|---|---|---|---|
| A: tok/s | 48.92 | 49.31 | +0.8% |
| B: Mean TTFT | 4855 | 5170 | +6.5% |
| B: tok/s | 75.88 | 73.33 | −3.4% |
| C: Mean TTFT | 4828 | 4943 | +2.4% |
| C: tok/s | 208.04 | 193.24 | −7.1% |
Igen, a phase 6 kicsit rosszabb, mint a 3 hetes image volt. Ez lett a két napos tuning munka első „vége”. De nem ez lett a végleges production config — lásd a phase 7 szekciót lentebb.
Akkor most mit tanultam?
Sok mindent, igazából. Itt van hat tanulság, fontossági sorrendben:
1. Pure-kernel benchmark ≠ serving benchmark
A benchmark_moe.py --tune azt méri, hogy egy izoláltan futtatott MoE kernel mennyire gyors egy adott batch méreten. A valós serving workload-ban ez a kernel nem izoláltan fut: a scheduler, a chunked prefill, a CUDA graph capture, a prefix caching, a mamba cache align — mindegyik befolyásolja, hogy mikor milyen batch méretben hívódik meg a kernel. A pure-kernel optimum és a serving optimum nem ugyanaz a pont.
Konkrét tanulság: ha benchmark_moe.py-t futtatsz, a kimenetet fogadd szkepszissel. Mérd le a valós serving workload-on előtte/utána. A pure-kernel nyereség lehet 1.5×, de a serving nyereség lehet negatív.
2. A vLLM nightly új alapértelmezései alattomosak
A v0.19-ben két új default van, amik mindketten bizonyos workload-okra ártanak:
async_scheduling=Trueprefill-heavy concurrent workload-on ~12% TTFT regressziót okoz. Override:--no-async-scheduling.mamba_cache_mode="align"(Qwen3.5-MoE + prefix caching) további ~5-10% regresszió. Nem override-olható CLI-ben, csak a prefix caching kikapcsolásával.
Frissítéskor mérj mindkét irányban, különösen a TTFT-t.
3. A CUDA graph érdemben számít
--enforce-eager a decode throughput-ot 33%-kal levágja. A 70 sec torch.compile overhead induláskor bőven megéri. Ha kisebb graph pool-t akarsz, a cudagraph_capture_sizes listát szűkítsd, ne az eager módot kapcsold be.
4. Pontosabb accounting ≠ több erőforrás
A VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS=1 javítja az elszámolást, de nem növeli a KV pool-t. Ugyanannyit akarsz? Emelned kell a gpu-memory-utilization paramétert. A log nem hazudik.
5. gpu-memory-utilization csak akkor hat, ha a KV pool szűk
A 174k token KV pool-t nem tudtam eleget használni 16 concurrent request-tel (max 40-80k aktív). A 467k tokenes pool (0.55 mem util) ugyanúgy viselkedett — csak felesleges memóriát zárt el a pipeline többi része elől. Ha a num_preemptions_total 0 és a kv_cache_usage_perc alacsony, ne emeld.
6. A 6 órás negatív eredmény is eredmény
Senki más nem akar 6 órát tuning-computera költeni hogy megtudja, nem éri meg. Ezt a 6 órát most megspóroltam másoknak. Ez az érték, amit a cikk nyújt.
Utólagos frissítés: phase 7 — a max-num-batched-tokens kísérlet
Miután leültem megírni ezt a cikket, megéledt bennem egy gondolat. A phase 6 configban a --max-num-batched-tokens 65536 maradt az eredeti értéken — ez a paraméter a chunked prefill egyetlen forward pass-ban feldolgozható token mennyiségét határozza meg. A hipotézis egyszerű:
Kisebb chunks → finomabb ütemezés a decode-dal. A 65k nagy chunk-ok a prefill/decode interleavinget elnyomják, ami TTFT tail-variancia-t okozhat. Kisebb chunks finomabb scheduling-et adnak, rövidebb preemption window-kat, és jobb tail latency-t.
Egyetlen változás a phase 6-hoz képest: 65536 → 16384. Minden más maradt.
Phase 7 eredmények — meglepő mértékű javulás
| Teszt | Phase 6 | Phase 7 (16k chunks) | Δ |
|---|---|---|---|
| A: Output tok/s | 49.31 | 49.15 | zaj |
| A: P99 TTFT | 668 ms | 176 ms | −74% 🎯 |
| B: Mean TTFT avg | 5170 | 4935 | −4.5% |
| B: P99 TPOT avg | ~39 ms | ~50 ms | +28% ⚠️ |
| C: Output tok/s | 193.24 | 207.92 | +7.6% ✅ |
| C: Mean TTFT avg (2 seed) | 4943 | 4146 | −16% ✅ |
| C: P99 TPOT | 97.07 ms | 77.34 ms | −20% ✅ |
A C teszt seed=42-en egy outlier P99 TTFT (8269 ms) jött be — ez önmagában még kétségbe vonta volna az eredményt. De seed=123-mal a P99 TTFT 5283 ms, jobb mint a phase 6 5917 ms-je. Tehát a seed=42 kiugrás zaj volt, nem a hipotézis cáfolata.
A chat workload tiszta bizonyítéka — D teszt
A C túl szélsőséges a valós chat workload-nak (16 concurrent extrém). Kiegészítettem egy D tesztet — 2048 input, 256 output, 2 concurrent — ami a DocAI chat agent tényleges profilját szimulálja:
| Metrika | Phase 7 D átlag (2 seed) |
|---|---|
| Mean TTFT | 719 ms |
| P99 TTFT | 902 ms |
| Mean TPOT | 24.97 ms |
| P99 TPOT | 25.67 ms (variancia ±1 ms!) |
| Output tok/s | 72.26 |
Ezek production-quality számok: a chat user 1 másodperc alatt kap első tokent még a worst case-ben is, és a streaming tempó ~40 tok/s lineárisan — a TPOT variancia elhanyagolható.
Tanulság — a „közönséges” paraméter
A max-num-batched-tokens egy alapvető vLLM scheduler flag, nincs benne Triton kernel tuning, nincs 6 órás compute. Egyetlen érték módosítása. És hozta azt amit a teljes MoE tuning maraton nem tudott:
- Single user P99 TTFT −74%
- Concurrent stress throughput +7.6%
- Tail TPOT variancia −20%
A tanulság pedig ez: a legnagyobb nyereséget gyakran nem az egzotikus kernel-tuning hozza, hanem egy jól megválasztott scheduler paraméter. A chunked prefill granularitása, a batch méret, a KV pool méretezés — ezek mind „közönséges” config értékek, amiket a vLLM doksi nem reklámoz látványosan, de a tényleges serving teljesítményre nagyobb hatásuk van, mint a kernel optimalizálásoknak.
A phase 7 a valódi production. A phase 6 config fájl archíválva referenciának.
Új végső config (phase 7)
--max-model-len 131072
--max-num-batched-tokens 16384 # <-- egyetlen változás a phase 6-hoz képest
--gpu-memory-utilization 0.45
--max-num-seqs 32
--kv-cache-dtype fp8_e4m3
--enable-chunked-prefill
--enable-prefix-caching
--no-async-scheduling
A teljes eredménymátrix, kiegészítve
| Fázis | Config | A tok/s | A P99 TTFT | B TTFT avg | C TTFT | C tok/s | C P99 TPOT |
|---|---|---|---|---|---|---|---|
| Baseline | régi image | 48.92 | — | 4855 | 4828 | 208.04 | — |
| Phase 2 | új image | 49.76 | — | 5941 | 6893 | 197.67 | — |
| Phase 2.5a | async OFF | 49.01 | — | 5249 | 5153 | 204.39 | 68.34 |
| Phase 3 | + MoE tuned | 48.94 | — | 5776 avg | 5302 | 204.46 | 68.02 |
| Phase 4 | + 0.55 util | 48.67 | — | 5744 avg | 5571 | 204.01 | 67.67 |
| Phase 5a | + eager | 30.02 | — | 7460 | — | — | — |
| Phase 6 | v1 production | 49.31 | 668 | 5170 | 4943 | 193.24 | 97.07 |
| Phase 7 | v2 production | 49.15 | 176 | 4935 | 4146 avg | 207.92 avg | 77.34 |
Mit lehet még csinálni?
Pár ötlet ami felmerült, de nem próbáltam ki, mert a cikket valamikor le kell zárni:
- Prefix caching OFF kísérlet: ha a chat agent-et és a KIE workload-ot szétválasztanám két vLLM instance-ra, a KIE-n kikapcsolhatnám a prefix caching-et (úgysincs hit) → megszűnne a mamba align overhead. Valószínűleg visszanyerhető a 5-10% regresszió.
- Speculative decoding (EAGLE / Qwen MTP): a decode throughput 2-3×-os javulás potenciálja a single-request path-on. A Qwen3.5-MoE-re van MTP drafter (
qwen3_5_mtp.py). Külön kutatási projekt. - Várakozás a FlashInfer MoE SM12.1 támogatására: a
--use-flashinfer-moe-fp8most még hibára fut az A3B block-wise FP8-on, de ha ez befut a következő hónapokban, az lesz az igazi ugrás. 48 → 100-150 tok/s tartományba.
Ezek már egy másik cikk témái. Most ezt lezárom.
Köszönetnyilvánítás
Az egész nyomozás közben Claude volt az asszisztensem a terminálba érkezett log-parser és kísérleti javaslat szerepben — a benchmark script paraméterezést, a sed trükköket (amik néha nem futottak le), a statisztikai értelmezéseket ő javasolta vagy validálta. Ha kétnapos tuning maraton kell, és nem akarsz egyedül ülni a logok fölött, jó társ.
Rendszer: NVIDIA DGX Spark, GB10 (SM 12.1), 128 GB LPDDR5x unified memory
Model: Qwen/Qwen3.5-35B-A3B-FP8 (hibrid attention, 40 layer, 10 full-attn + 30 linear-attn, E=256 MoE experts)
vLLM: 0.19.1rc1.dev231+g9dd5ee011 (cu130-nightly image, 2026-04-13)
Benchmark eszköz: vllm bench serve (built-in)
Minden JSON eredmény, docker-compose fájl, és tuned MoE config elérhető — ha érdekel a reprodukció vagy a részletes percentile-eloszlások, írj.