A minap két H100-on is lefuttattam a Qwen3.8-27B-FP8-at, és az MTP-speculative decoding hozta a legnagyobb decode-gyorsulást (49 → 95 tok/s). De van egy bökkenő: a vLLM-ben az MTP és a prefix caching kölcsönösen kizárja egymást, szóval az volt a kérdés, hogy melyik konfigurációt érdemes élesben használni.

A választ úgy kaptam meg, hogy egymás ellen futtattam a két verziót: GPU0 no-MTP + prefix caching, GPU1 MTP (3 draft token). Mindkettő TP1-es, 262K maximum kontextus, FP8 KV cache, és egy LiteLLM proxy osztja el köztük a forgalmat. Az összes szám TTFT p50, hacsak nem írom másképp.

Decode: az MTP viszi a pontot#

Először is a jó hír: decode-ban az MTP a teljes konkurrenciasávban gyorsabb, 1K tokenes promptokkal és 512 kimeneti tokennel:

MTP decode throughput

Egyetlen session-nél 1,9×-es az előny (94,9 vs 49,9 tok/s), ami 32 párhuzamos session-nél 1,28-szorosra szűkül. Szóval ha hideg promptokból generálsz sok tokent, az MTP a barátod.

Single-turn: közös prefix, egyedi suffixek#

Itt már fordul a kocka. Ha több session ugyanazt a prefixet használja (pl. közös rendszerpromptot), akkor a cache-sel futó konfiguráció a konkurrencia növekedésével gyakorlatilag lapos marad, míg az MTP-nek minden kérésnél újra prefill-elnie kell a teljes prefixet. 4K prefixnél konkurrencia nélkül még az MTP nyer (0,85 s vs 1,02 s), de 32 session-nél már 2,6-szeres hátrányban van (13,55 s vs 5,20 s). 16K prefixnél pedig 16 session-nél már 8-szoros a különbség (27,85 s vs 3,49 s).

A cache-hit sem elhanyagolható: második kérésnél, 16K prefix mellett a cache-hit 2,4-szer gyorsabb, mint az MTP re-prefillje (0,91 s vs 2,20 s) — igaz, 4K-nál a hash-elés többletköltsége felemészti az előny nagy részét.

Multi-turn: itt dől el a dolog#

Háromfordulós meneteket futtattam, minden forduló ~1K tokennel növelte a kontextust (4K-tól 64K-ig). A második forduló TTFT-je — vagyis az első követő kérdés ideje — lineáris skálán, kontextusonként külön panelen:

Multi-turn TTFT lineáris skálán, kontextusonként

Lineáris skálán lehetetlen nem észrevenni a lényeget: a cache-t használó konfiguráció lapos marad (~1,4–5,5 s minden kontextusméretnél, 8 párhuzamos sessionig — csak az ~1K új suffixet prefill-eli, a közös prefix cache-hit, a futás alatt ~65%-os hit rate), míg az MTP minden követő fordulónál újra lefuttatja a teljes felhalmozott kontextust.

Nagyobb kontextusokra az MTP görbéit külön is megmutatom — logaritmikus skálán ez a „fal" szinte nem is látszik:

MTP fala lineáris skálán

A cache oldalát pedig közelről, hogy a laposság tényleg látszódjon (a 132 s-os pont 64K/16-nál mindkét konfig közös KV-kapacitás-határa, nem cache-hiba):

Prefix caching lineáris skálán, közelről

Számokban: 8 session / 32K-nál az MTP már 28,6 s; 16 session / 64K-nál 80,9 s. Az arány egészen 16,8×-ig megy (64K, 4 concurrent). A 64K/16-os sarok viszont kivétel: ott mindkét konfig a KV cache kapacitáshatárába ütközik (16 × 64K élő KV ~1,05M token a 1,32M-es pool ellen, ráadásul a cache-elő példányon a pinned cache-blokkok miatt még rosszabbul is romlik a helyzet) — ez kapacitáshatár, nem konfigurációs hatás.

Verdikt#

Munkaterhelés Nyertes
Egy session, hosszú generálás, hideg prompt MTP (1,3–2,2× decode)
Multi-turn, párhuzamos sessionök, növekvő kontextus Prefix caching (akár 17× TTFT)
64K+ kontextus, 16+ párhuzamos session Egyik sem — KV kapacitáshatár

A lényeg: konverzációs, multi-turn munkaterhelésnél a prefix caching az alapértelmezés, főleg ha több felhasználó osztozik a kontextuson vagy a rendszerprompton. Az MTP csak akkor fizetődik ki, ha decode-nehéz, hideg, egy-session munkád van. Mivel a vLLM-ben a kettő nem működhet együtt, ez a mérés eldöntötte nálam, hogy mit rakok élesbe.