Puntata 229
Puntata 229 — Inference: latenza, throughput, batching
Livello: 🧙 Maestro Yoda · Capitolo 21 · Open source e HuggingFace
“Quanto è veloce questo modello?” è una domanda senza una risposta. Esistono almeno cinque numeri diversi che il marketing chiama “velocità”. Capirli è la differenza tra dimensionare giusto un server e accorgersi a produzione iniziata che spendi 3× il previsto.
Le 5 metriche che contano
Per ogni richiesta a un LLM, ci sono fasi distinte. E quindi metriche distinte.
1. TTFT — Time To First Token
Tempo dall’invio della richiesta al primo token in output. Include:
- Setup HTTP
- Tokenizzazione del prompt
- Prefill (forward pass su tutto il prompt per riempire KV cache)
- Generazione del primo token
TTFT cresce con la lunghezza del prompt (prefill è O(N²) sul context, anche se ottimizzato).
Per UX: <500ms si percepisce “istantaneo”, 1-3s “ok”, >5s “lento”.
2. TPOT — Time Per Output Token (o “inter-token latency”)
Tempo medio tra un token in output e il successivo, dopo il primo.
- Su un’API frontier: tipicamente 10-30 ms/token.
- Su Ollama M3 Q4: 15-25 ms/token.
- Su vLLM A100 BF16 (batch=1): 8-15 ms/token.
- Su modelli reasoning (o-series, R1): può salire a 30-80 ms/token visibile, più ovviamente il “thinking” interno nascosto.
TPOT è quasi costante per token (a parità di context). Salirà un po’ man mano che il context cresce.
3. End-to-end latency
TTFT + (TPOT × output_tokens). Per una risposta da 200 token a 20 ms/token con TTFT 300ms: ~4.3s totali.
Per UX streaming: la cosa che conta è TTFT (l’utente vede il primo carattere) e TPOT (la velocità di scrittura). End-to-end conta solo per chiamate batch.
4. Throughput (token/sec aggregato)
Numero di token generati al secondo complessivamente dal server, sommando tutte le richieste concorrenti.
Su un singolo utente, throughput = 1/TPOT. Con 100 utenti concorrenti su vLLM, può salire a 1000-3000 tok/s aggregati — ma la singola request ne vede solo una frazione.
È la metrica economica: pagar la GPU 24h fa rendere se la riempi.
5. Concurrency / requests/sec
Quante richieste indipendenti il server gestisce contemporaneamente senza degradare SLA. Dipende da:
- Throughput max
- KV cache disponibile (più users = più KV cache totale)
- Tempo medio di una richiesta
Prefill vs decode: la dicotomia che spiega tutto
Una request LLM ha due fasi computazionalmente diverse:
Prefill
- Riceve il prompt completo (es. 2000 token).
- Calcola un forward pass su tutti i token in parallelo.
- Riempie la KV cache.
- Produce 1 token (il primo).
- È compute-bound (le GPU/TPU vanno al 90%+ utilization).
Decode
- Per ogni token in output: un forward pass sul singolo token, riusando la KV cache.
- È memory-bound (il bottleneck è leggere la KV cache + i pesi dalla VRAM, non il calcolo).
- GPU spesso al 20-40% di utilization.
Conseguenza pratica:
- Server saturi sul prefill = pochi utenti con prompt lunghi.
- Server saturi sul decode = molti utenti con risposte lunghe.
vLLM e TGI ottimizzano entrambe le fasi separatamente. Sistemi tipo disaggregated serving (Sarathi-Serve, DistServe) dedicano GPU diverse alle due fasi per massimizzare utilization. Stato 2026: già in alcuni provider serious, non ancora mainstream.
Batching: la magia del throughput
Senza batching, ogni request occupa la GPU per la sua durata. Con batching: aggreghi N request, le fai girare insieme, ammortizzi il costo di leggere i pesi dalla VRAM.
Static batching (vecchio)
Aspetti N richieste, le fai partire insieme, aspetti che finiscano tutte. Spreco: la più lenta blocca tutte.
Continuous (in-flight) batching (vLLM, TGI, 2023+)
Le request entrano ed escono dal batch dinamicamente, token per token. Quando una finisce, ne entra un’altra. Throughput 3-5× più alto di static.
Speculative decoding
Un modello piccolo “draft” propone k token in avanti. Il modello grande li verifica in parallelo. Se accettati: hai generato k token al costo di 1 step. Speedup tipico 2-3× su decode senza degradare qualità.
Prefix caching
Se molte request iniziano con lo stesso prompt (es. system prompt aziendale comune), la KV cache del prefisso viene riusata. Riduce il prefill quasi a zero. Supportato da vLLM, SGLang, TGI.
Cosa influenza la velocità: la cruda lista
- Modello (dimensione): 70B è ~10× più lento di 7B su same hardware.
- Quantization: Q4 è ~2× più veloce di FP16 (per memory bandwidth).
- Hardware: H100 vs A100 ≈ 2-3× su decode. Blackwell B200 vs H100 ≈ 1.5-2.5×. M3 Max vs 4090 ≈ comparable on single user 8B.
- Context length: prefill è ~quadratic; decode lineare nel context.
- Batch size: throughput aggregato sale, latency per-request rimane simile fino a saturazione.
- Speculative decoding: 2-3× su decode.
- Output length: solo decode → tempo totale = TTFT + N × TPOT.
- Sampling: greedy/argmax > temperature > beam search per velocità.
- Network: per API remote, RTT + streaming overhead.
Come stimare il bisogno hardware
Esempio: vuoi servire un Llama 3.1 70B AWQ a 50 utenti concorrenti, prompt medi 1500 token, risposte medie 400 token, TTFT ≤2s, TPOT ≤40ms.
Step:
- Modello 70B AWQ = ~40 GB pesi. Una H100 80 GB ce la fa, ma KV cache?
- KV cache per request: ~2 × layers × heads × head_dim × seq_len × dtype. Per Llama 70B FP16: ~80 KB/token. Con 1900 token max (prompt+resp): ~150 MB/request. ×50 = 7.5 GB.
- Totale VRAM: 40 + 7.5 + buffer = ~55 GB. Sta in una H100 80 GB.
- Throughput: una H100 su 70B AWQ fa ~30-60 tok/s decode aggregato in batch=50. Risposta media 400 token: ~10-15s decode totale. Per utente: vede ~25-40 tok/s effettivi.
- Conclusione: 1 H100 può servire 50 utenti con QoS rilassato. Se vuoi TPOT 20ms/token per utente: serve 2-4 H100 o speculative decoding aggressivo.
(Questi numeri sono stime; calibrale con benchmark reali sul tuo prompt-mix.)
Le 4 trappole più comuni
a) Misurare solo single-user
Sviluppi, fai un benchmark con 1 utente alla volta, dimensioni così. Poi in produzione hai 50 utenti, scopri che il server collassa o che TPOT si quadruplica. Misura sempre con il prompt-mix e la concurrency reali.
b) Confondere TTFT e TPOT
Marketing dice “200 tok/sec!” — fantastico, ma se TTFT è 6s, l’utente percepisce lentezza atroce. Lo streaming la mitiga solo se TPOT è basso.
c) Ignorare il KV cache
Con context 128k e 100 utenti, la KV cache può richiedere centinaia di GB. La gente dimensiona “il modello” e dimentica la cache.
d) Non considerare prefix caching
Se il tuo system prompt è 3000 token e ce l’hanno tutti gli utenti, il prefill viene buttato N volte senza prefix caching. Con: il prefill avviene una volta sola, risparmiando GPU.
Strumenti per misurare
vllm bench: built-in, simula carico e produce p50/p95/p99 di TTFT/TPOT.oha,hey,wrk: load testing HTTP generale.- GuideLLM (Neural Magic): benchmark specifico LLM serving.
- OpenLLM Bench (BentoML): metriche standard.
- NVIDIA Nsight: profilatura GPU low-level.
Per produzione: Prometheus + Grafana con metriche esposte da vLLM/TGI nativamente. Allerta su p95 TPOT > threshold.
Costi: la conseguenza economica
Throughput → token/$.
A grandi linee 2026:
- API frontier (GPT, Claude): $1-15 per milione di token (input/output, varia).
- Open weight su vLLM auto-hosted (Llama 3.1 70B AWQ su H100 spot $2/h, throughput 1500 tok/s): ~$0.20-0.50 per milione di token a saturazione.
- Open weight su provider managed (Together, Fireworks, Deepinfra): $0.20-1 per milione.
Self-hosting vince se mantieni la GPU satura. Se la usi al 10%, paghi 5× più di un’API.
Glossario lampo
- TTFT / TPOT — Time To First Token / Time Per Output Token. Le due metriche di latenza che contano per lo streaming.
- Prefill / Decode — le due fasi di un’inferenza LLM, compute-bound vs memory-bound rispettivamente.
- KV cache — cache delle attivazioni K e V degli strati di attention, evita ricalcolo durante decode.
- Continuous batching — aggregazione dinamica delle richieste in arrivo, standard 2024+ per high-throughput serving.
- Speculative decoding — usa un draft model piccolo per proporre token in avanti, verificati dal modello grande.
Take-away
L’inference economy degli LLM si gioca su 5 numeri: TTFT, TPOT, throughput, concurrency, costo. Misurarli male significa o overprovisioning (paghi 3× il necessario) o underprovisioning (SLA buchi e utenti che se ne vanno). Ottimizzarli bene — quantization + AWQ + continuous batching + prefix caching + speculative decoding — riduce il costo per token di 5-10× negli ultimi due anni.
➡️ Prossima puntata: fine-tunare un open model end-to-end, dal dataset al deploy.