Cos'è la KV-cache, in un paragrafo

Un transformer genera un token alla volta, e ogni nuovo token "presta attenzione" a ogni token precedente. Senza cache, produrre il token 1.000 significherebbe ricalcolare i vettori key e value dei 999 token che lo precedono — a ogni singolo passo. La KV-cache memorizza quei vettori key/value così ciascuno è calcolato una volta e riusato. È l'unica ottimizzazione che rende pratica la generazione — e il prezzo è memoria che cresce con ogni token nel contesto.

La formula

KV-cache bytes = 2 × context_length × n_layers × n_kv_heads × head_dim × bytes_per_value × batch

Leggendo ogni termine:

  • 2 — un set per le key, uno per i value.
  • context_length — i token tenuti in contesto. È il termine che controlli, e scala tutto linearmente.
  • n_layers × n_kv_heads × head_dim — l'architettura del modello. Nota n_kv_heads, non le teste di attenzione — è qui che la GQA risparmia memoria (sotto).
  • bytes_per_value — 2 per cache FP16, 1 per Q8, ~0,5 per Q4. È la leva della quantizzazione.
  • batch — numero di richieste simultanee. Ogni utente concorrente ha bisogno di una cache separata completa — è il termine che tutti dimenticano.

Un esempio pratico: Llama 3.3 70B

Llama 3.3 70B ha 80 layer, 8 teste KV (usa grouped-query attention) e una dimensione di testa di 128. Per una singola richiesta con cache FP16:

per token = 2 × 80 × 8 × 128 × 2 bytes = 327,680 bytes ≈ 0.31 MB 8K context → ~2.5 GB 32K context → ~10 GB 128K context → ~40 GB ← grande quanto i pesi Q4!

Quell'ultima riga è il nocciolo della questione. I pesi Q4 sono ~40GB; a pieno contesto 128K la cache raddoppia il tuo fabbisogno di memoria, portandolo a ~80GB. Ecco perché la nostra guida VRAM insiste nel dimensionare per pesi più cache — e perché il "ci sta" di un calcolatore che conta solo i pesi è una trappola. Ora moltiplica per la concorrenza: dieci utenti simultanei a 32K di contesto ciascuno richiedono dieci cache — ~100GB di sola cache.

Perché la GQA ha cambiato tutto (e le vecchie formule mentono)

Le formule più vecchie della KV-cache usano il numero di teste di attenzione. I modelli moderni usano la grouped-query attention (GQA), dove molte teste query condividono un piccolo numero di teste key/value — Llama 70B ha 64 teste query ma solo 8 teste KV. Poiché la cache memorizza le teste KV, la GQA taglia la dimensione della cache di quel rapporto (8× qui). Una formula pre-GQA predirebbe otto volte la memoria e ti farebbe scartare per paura un modello che in realtà ci sta. Usa sempre n_kv_heads, che trovi nel config.json del modello come num_key_value_heads.

Le due leve che rendono sostenibile il contesto lungo

1. Quantizzazione della cache. La cache non deve essere FP16. Memorizzarla a Q8 (1 byte/valore) dimezza la memoria della cache; Q4 la riduce a un quarto. In Ollama, attivala con la variabile d'ambiente OLLAMA_KV_CACHE_TYPE=q8_0; in llama.cpp usa --cache-type-k/--cache-type-v; vLLM e SGLang hanno opzioni di cache FP8. In pratica la cache Q8 è quasi lossless ed è l'impostazione che rende di più nel lavoro locale a contesto lungo — trasforma il nostro esempio Llama a 128K da ~40GB di cache a ~20GB.

2. Dimensiona giusto la finestra. Un modello che pubblicizza 256K di contesto non ti obbliga ad allocare 256K. Imposta il contesto al tuo bisogno reale: un assistente di chat raramente usa più di 8–16K; un sistema document-RAG dimensionato al suo budget di chunk potrebbe servire 32K, non 256K. In Ollama è num_ctx; in vLLM, --max-model-len. Allocare margine che non usi mai è pura VRAM sprecata — il rovescio del consiglio "alza num_ctx" nelle nostre pagine sull'assistente di coding e Qwen3-Coder, dove l'errore va nella direzione opposta.

La checklist pratica

  • Dimensiona la VRAM come pesi + KV-cache + ~1–2GB di overhead — mai i soli pesi.
  • Calcola la cache sul TUO contesto e sulla TUA concorrenza, non sul massimo del modello.
  • Attiva prima la cache Q8 — costa quasi nulla in qualità ed è ciò che libera più spazio in assoluto.
  • Per il serving, ricorda che ogni richiesta concorrente moltiplica la cache — è questo a limitare il numero di utenti, non i pesi.
  • Preferisci i modelli GQA (praticamente tutti quelli attuali) e leggi num_key_value_heads da config.json per il conto esatto.