🧙 Maestro Yoda Cap. 21 · Open source e HuggingFace

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.

dashboard di un centro di controllo aereo con tre grandi indicatori — “TTFT 240ms”, “TPOT 28ms/token”, “Throughput 1840 tok/s”. Un controllore sudato beve caffè. Sotto: “5 numeri, una verità sola: dipende”

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

  1. Modello (dimensione): 70B è ~10× più lento di 7B su same hardware.
  2. Quantization: Q4 è ~2× più veloce di FP16 (per memory bandwidth).
  3. 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.
  4. Context length: prefill è ~quadratic; decode lineare nel context.
  5. Batch size: throughput aggregato sale, latency per-request rimane simile fino a saturazione.
  6. Speculative decoding: 2-3× su decode.
  7. Output length: solo decode → tempo totale = TTFT + N × TPOT.
  8. Sampling: greedy/argmax > temperature > beam search per velocità.
  9. 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:

  1. Modello 70B AWQ = ~40 GB pesi. Una H100 80 GB ce la fa, ma KV cache?
  2. 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.
  3. Totale VRAM: 40 + 7.5 + buffer = ~55 GB. Sta in una H100 80 GB.
  4. 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.
  5. 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.