MTP vs. prompt caching — Qwen3.8-27B-FP8 em 2× H100: qual configuração usar?
Ao rodar o Qwen3.8-27B-FP8 em duas H100, o speculative decoding MTP foi o maior ganho de decode (49 → 95 tok/s). Mas tem um detalhe: no vLLM, MTP e prefix caching são mutuamente exclusivos. Então a pergunta foi: qual configuração usar em produção?
A resposta veio de um comparativo direto entre as duas configurações: GPU0 sem MTP + prefix caching, GPU1 com MTP (3 draft tokens). As duas TP1, contexto máximo de 262K, KV cache FP8, e um proxy LiteLLM distribuindo a carga entre elas. Todos os números são TTFT p50, salvo indicação em contrário.
Decode: o MTP leva o ponto#
Primeiro a boa notícia: no decode, o MTP é mais rápido em qualquer nível de concorrência, com prompts de 1K tokens e 512 tokens de saída:

Numa única sessão, a vantagem é de 1,9× (94,9 contra 49,9 tok/s), caindo para 1,28× com 32 sessões concorrentes. Ou seja: se você gera muitos tokens a partir de prompts frios, o MTP é seu amigo.
Single-turn: prefixo compartilhado, sufixos únicos#
Aqui o jogo começa a virar. Quando várias sessões compartilham o mesmo prefixo (por exemplo, um system prompt comum), a configuração com caching fica praticamente estável conforme a concorrência aumenta, enquanto o MTP precisa refazer o prefill do prefixo a cada requisição. Com prefixo de 4K e sem concorrência, o MTP ainda vence (0,85 s contra 1,02 s); com 32 sessões, porém, ele já fica 2,6× atrás (13,55 s contra 5,20 s). Com prefixo de 16K e 16 sessões, a diferença já é de 8× (27,85 s contra 3,49 s).
E o cache hit não é pouca coisa: na segunda requisição com prefixo de 16K, o cache hit é 2,4× mais rápido que o re-prefill do MTP (0,91 s contra 2,20 s) — embora em 4K o overhead de hashing consuma boa parte do benefício.
Multi-turn: é aqui que a coisa se decide#
Sessões de três turnos, cada turno crescendo o contexto em ~1K tokens (de 4K até 64K). A TTFT do turno 2 — o tempo da primeira pergunta de acompanhamento — em escala linear, um painel por contexto-base:

Na escala linear a história fica impossível de não ver: a configuração com caching permanece estável (~1,4–5,5 s em qualquer tamanho de contexto, até 8 sessões concorrentes — só o ~1K de sufixo novo é pré-processado, o prefixo compartilhado é cache hit, ~65% de hit rate durante o teste), enquanto o MTP refaz o prefill de todo o contexto acumulado a cada turno seguinte.
Para os contextos maiores, mostro também as curvas do MTP isoladamente — numa escala logarítmica, essa “parede” quase nem parece uma:

E o lado do caching de perto, para a estabilidade ficar realmente visível (o ponto de 132 s em 64K/16 é o limite de capacidade de KV comum às duas configurações, não uma falha de caching):

Em números: com 8 sessões / 32K, o MTP já está em 28,6 s; com 16 sessões / 64K, chega a 80,9 s. A razão sobe até 16,8× (64K, 4 concorrentes). O canto 64K/16 é a exceção: ali as duas configurações batem no teto de capacidade do KV cache (16 × 64K de KV vivo são ~1,05M tokens contra um pool de 1,32M, e a instância com caching degrada ainda mais por causa dos blocos de cache pinados) — isso é limite de capacidade, não efeito de configuração.
Veredito#
| Carga de trabalho | Vencedor |
|---|---|
| Sessão única, gerações longas, prompts frios | MTP (1,3–2,2× decode) |
| Multi-turn, sessões concorrentes, contexto crescente | Prefix caching (até 17× TTFT) |
| Contexto 64K+ com 16+ sessões concorrentes | Nenhum — limite de KV |
E a conclusão prática: para cargas conversacionais / multi-turn, o prefix caching é a opção padrão, principalmente quando vários usuários compartilham contexto ou system prompts. O MTP só compensa em trabalho de decode pesado, sessão única e prompts frios. Como o vLLM torna as duas configurações mutuamente exclusivas, esta medição decidiu qual colocar em produção.