Un modello linguistico legge il prompt tutto insieme, come chi scorre una pagina con lo sguardo, ma scrive la risposta come chi detta: una parola, poi la successiva, e ogni parola richiede di rileggere a memoria tutto il modello. Da questa asimmetria discendono quasi tutti i numeri che si vedono usando un LLM (Large Language Model, modello linguistico di grandi dimensioni): il tempo prima del primo token, la velocità di scrittura, la memoria occupata, il prezzo diverso per i token in ingresso e in uscita. Questa guida segue il ciclo di generazione, le regole con cui si sceglie ogni token, la cache che evita di ricalcolare il passato, e come un server riesce a servire migliaia di utenti insieme.
Pensate al completamento automatico della tastiera del telefono, usato premendo sempre il primo suggerimento: ogni parola scelta diventa parte del testo su cui si calcola il suggerimento successivo.
Un modello linguistico decoder fa esattamente questo, con una rete molto più grande e un vocabolario di decine o centinaia di migliaia di token. Non c'è un piano della frase da qualche parte: c'è solo la domanda «dato tutto il testo fin qui, quale token viene dopo?», ripetuta.
Ogni giro del ciclo ha quattro passi. Una passata in avanti (forward pass) attraversa tutti gli strati e produce un logit, un punteggio grezzo, per ciascun token del vocabolario. La softmax trasforma i logit in una distribuzione di probabilità. Una regola di scelta, il campionamento del capitolo 2, estrae un token da quella distribuzione. Il token scelto si accoda al testo e il giro riparte.
Che cosa siano logit e softmax, e come si arriva a quei punteggi, è spiegato nella guida sul training, e la softmax si può provare a mano nel laboratorio sulle quattro classi della guida sul machine learning: qui interessa che cosa se ne fa quando il modello genera.
Il ciclo non ha una lunghezza prefissata. Si ferma in tre casi: il modello sceglie un token di fine (un token speciale che durante l'addestramento chiudeva ogni risposta, spesso chiamato EOS, End Of Sequence), il testo prodotto contiene una sequenza di stop indicata da chi chiama, oppure si raggiunge il limite massimo di token in uscita. Nel terzo caso la risposta è semplicemente tagliata: le API (Application Programming Interface, interfacce di programmazione) lo segnalano con un motivo di arresto diverso, ed è buona pratica controllarlo.
Il prompt è già tutto noto prima di cominciare. Grazie alla maschera causale, che impedisce a ogni token di guardare quelli successivi, il modello può elaborare tutti i token del prompt nella stessa passata: ogni posizione calcola il proprio vettore guardando solo quelle precedenti, e i calcoli di posizioni diverse non dipendono l'uno dall'altro. È la fase di prefill, e la sua ultima posizione produce già i logit del primo token di risposta.
La risposta invece non si può parallelizzare: il token 5 non esiste finché il token 4 non è stato scelto. È la fase di decode: una passata per ogni token in uscita. Mille token di risposta sono mille passate in sequenza, mentre mille token di prompt sono una passata sola. Il capitolo 4 mostra perché questa differenza pesa su tempi e prezzi.
Schema: nella fase di prefill i sei token del prompt «La capitale d'Italia è» entrano in una sola passata, che produce i logit del primo token di risposta. Nella fase di decode ogni token successivo, «Roma», «,», «una», «città», richiede una passata propria, in sequenza.
Premi «Passata successiva» e guarda quanti token entra in ogni passata e come cresce il contesto; prova poi a togliere la cache KV (key-value, capitolo 3).
Le probabilità sono inventate e si mostrano solo i quattro candidati migliori su un vocabolario che ne ha decine di migliaia; la scelta è sempre quella più probabile (greedy). I conteggi di token elaborati sono quelli reali di un decoder: con la cache ogni passata di decode elabora il solo token nuovo; senza, rielabora ogni volta tutto il testo.
Il modello restituisce una distribuzione; quale token prendere è una decisione separata, fatta da poche righe di codice nel server, e cambia molto il carattere del testo.
È come una giuria che dà un voto a ogni candidato: si può proclamare sempre il primo, oppure estrarre a sorte pesando i voti, magari dopo aver escluso chi ha preso troppo poco.
Greedy (avido) significa prendere sempre il token più probabile. È deterministico e va bene per risposte brevi e fattuali, ma su testi lunghi tende a ripetersi e a scegliere la strada più banale. Campionare significa estrarre a caso secondo le probabilità: il testo diventa più vario, al prezzo di qualche scelta improbabile. La temperatura, già vista nella guida sul training, divide i logit prima della softmax: sotto 1 accentua le differenze e avvicina il greedy, sopra 1 le appiattisce. A temperatura 0 la maggior parte delle librerie passa direttamente al greedy.
Il problema del campionamento puro è la coda: decine di migliaia di token con probabilità minuscole che, sommate, pesano. Estrarre spesso significa prima o poi pescare dalla coda, e un solo token assurdo può far deragliare il resto della frase. I filtri tolgono la coda e rinormalizzano ciò che resta, cioè dividono per la somma rimasta in modo che le probabilità tornino a sommare 1.
| Regola | Che cosa tiene | Pregio | Limite |
|---|---|---|---|
| Top-k | i k token più probabili | semplice, costo fisso | numero rigido: troppi candidati quando il modello è sicuro, troppo pochi quando è incerto |
| Top-p (nucleus) | i token più probabili fino a superare una probabilità cumulata p | si adatta: pochi candidati se la distribuzione è appuntita, molti se è piatta | con temperature alte la coda si gonfia e il nucleo si allarga molto |
| Min-p | i token con probabilità almeno pmin × quella del token migliore | soglia relativa alla sicurezza del modello, regge meglio le temperature alte | più recente, non tutte le API lo espongono |
Top-p è stato proposto da Holtzman e colleghi (2019), che hanno mostrato come il testo generato con greedy o beam search tenda alla ripetizione e quello campionato senza filtri all'incoerenza; min-p da Nguyen e colleghi (2024).
Muovi temperatura, top-k, top-p e min-p: le barre grigie sono le probabilità originali, quelle colorate le probabilità dopo i filtri, già rinormalizzate.
Dodici candidati con logit inventati ma plausibili; un vocabolario vero ha una coda di decine di migliaia di token, che rende i filtri ancora più importanti. L'ordine applicato qui è: penalità, temperatura, top-k, top-p, min-p. Le librerie non usano tutte lo stesso ordine, e il risultato può cambiare un po'. Le 20 estrazioni sono indipendenti, tutte dallo stesso contesto: servono a vedere la frequenza, non a generare una frase.
Un altro modo di correggere i logit è guardare il testo già scritto. La penalità di presenza sottrae un valore fisso al logit di ogni token che è già comparso almeno una volta; la penalità di frequenza sottrae un valore proporzionale a quante volte è comparso. È la forma usata, per esempio, dalle API (interfacce di programmazione) di OpenAI. La penalità di ripetizione introdotta con il modello CTRL (Keskar e colleghi, 2019) invece divide i logit positivi dei token già visti per un fattore (1,2 nel lavoro originale) e moltiplica quelli negativi.
Sono strumenti grossolani: il modello non distingue una ripetizione noiosa da una necessaria, come il nome di una variabile in un codice o un termine tecnico in una spiegazione. Con i modelli moderni addestrati a seguire istruzioni si usano poco, e valori alti peggiorano la qualità.
Il campionamento usa un generatore di numeri pseudocasuali: fissando il seed (il seme da cui il generatore parte) si ottengono le stesse estrazioni, come mostra il laboratorio. Ci si aspetterebbe allora che a temperatura 0, o con lo stesso seed, la stessa domanda dia sempre la stessa risposta. Nei servizi reali spesso non succede, per ragioni numeriche più che casuali.
Per questo alcuni provider offrono il seed come garanzia «per quanto possibile», non assoluta. Ottenere un'inferenza davvero riproducibile richiede calcoli che diano lo stesso risultato qualunque sia la dimensione del batch, e costa un po' di velocità.
Nell'attenzione ogni token produce tre vettori: una query, una key e un value. Il token corrente confronta la propria query con le key di tutti i token precedenti e mescola i loro value secondo quei punteggi (il meccanismo è descritto nel capitolo sugli strati della guida sul training). Per generare il token 501 servono quindi le key e i value dei 500 token precedenti, in ogni strato.
Il punto chiave è la maschera causale. Siccome un token non guarda mai quelli che vengono dopo, il suo vettore in ogni strato non cambia quando la risposta si allunga: le key e i value del token 37 sono gli stessi alla passata 40 e alla passata 400. Ricalcolarli ogni volta sarebbe puro spreco.
La cache KV (key-value, chiavi e valori) li conserva: a ogni passata di decode si calcolano query, key e value del solo token nuovo, si aggiungono key e value alla cache e si legge la cache per l'attenzione. Il decoder con maschera causale, e il perché un encoder come BERT non può farlo, è il tema della guida sulle architetture.
Prendiamo un prompt di 1.000 token e una risposta di 500. Con la cache il modello elabora 1.000 token nel prefill e poi uno per passata: circa 1.500 elaborazioni di token in tutto. Senza cache, ogni passata rielabora l'intero testo: 1.000 la prima volta, 1.001 la seconda, fino a 1.499.
Calcolo · lavoro senza cache
Il prezzo si paga in memoria. La query del token corrente serve una volta e si butta; key e value invece restano per tutta la conversazione, per ogni strato e per ogni testa che ne ha di proprie.
Per Llama 3 8B: 32 strati, 8 teste KV, ogni testa di dimensione 128, numeri in bf16. Il conto dà:
Calcolo · cache KV di Llama 3 8B
Un contesto di 8.192 token occupa 1 GiB per conversazione; uno di 128.000 token, il massimo di Llama 3.1, circa 16 GiB, quanto i pesi del modello stesso. La memoria della cache cresce in modo lineare con i token e con il numero di conversazioni servite insieme.
Nell'attenzione originale a più teste (MHA, Multi-Head Attention) ogni testa ha query, key e value propri: Llama 2 7B, con 32 teste, mette in cache 32 coppie di key e value per strato, cioè 512 KiB per token.
La MQA (Multi-Query Attention, Shazeer 2019) fa condividere a tutte le teste di query una sola coppia di key e value; la GQA (Grouped-Query Attention, Ainslie e colleghi 2023) sta in mezzo: le teste di query sono divise in gruppi e ogni gruppo condivide una coppia. Llama 3 8B ha 32 teste di query e 8 teste KV, quindi gruppi da quattro, e una cache quattro volte più piccola di quella di un'attenzione completa delle stesse dimensioni.
Le query restano tutte: ogni testa continua a cercare cose diverse, ma lo fa negli stessi archivi. La perdita di qualità della GQA è piccola rispetto alla MQA, che ne ha una più evidente; per questo la GQA è diventata la scelta più comune. Altre strade riducono ancora la cache: comprimerla in un vettore latente più piccolo (MLA, Multi-head Latent Attention, in DeepSeek-V2 e V3), limitare alcuni strati a una finestra degli ultimi token, oppure quantizzarla a 8 bit.
Scegli un modello oppure muovi strati, teste KV e contesto, e guarda quanta memoria serve per token, per conversazione e per tutte le conversazioni servite insieme.
La formula è esatta per l'attenzione standard, MHA, GQA e MQA; non vale per varianti come MLA o le finestre scorrevoli. I numeri reali di un server sono un po' più alti: frammentazione (capitolo 5), attivazioni temporanee e memoria riservata dalla libreria. 1 GiB = 2³⁰ byte; GPU da 80 GB = 80·10⁹ byte, come si dichiarano le schede.
Una GPU (Graphics Processing Unit) può fare due cose lentamente: calcolare e spostare dati dalla propria memoria ai circuiti di calcolo. Quale delle due fa da collo di bottiglia dipende da quante operazioni si fanno per ogni byte letto, la cosiddetta intensità aritmetica.
Pensate a un cuoco con un dispensa lontana: se per ogni ingrediente preso fa cento piatti, conta la sua velocità ai fornelli; se per ogni ingrediente fa un piatto solo, conta quanto in fretta va e torna dalla dispensa.
Ogni passata deve leggere tutti i pesi dalla memoria: 16 GB per un modello da 8 miliardi di parametri in bf16 (bfloat16, 2 byte per numero). Nel prefill, quella lettura serve a elaborare migliaia di token insieme: ogni peso letto viene usato migliaia di volte, e il limite è la potenza di calcolo. Si dice che il prefill è compute-bound.
Nel decode con una sola conversazione, invece, la stessa lettura di 16 GB serve per un token: circa due operazioni per ogni peso, cioè per ogni due byte. I circuiti di calcolo aspettano quasi sempre la memoria: il decode è memory-bound.
In più ogni passata rilegge l'intera cache KV (key-value) della conversazione, che cresce token dopo token. Con una banda di memoria di qualche TB/s (terabyte al secondo), leggere 16 GB richiede alcuni millisecondi: è il tempo minimo per token, qualunque sia la potenza di calcolo della scheda.
Il TTFT (Time To First Token, tempo al primo token) è quanto si aspetta prima di vedere comparire qualcosa: rete, coda sul server e prefill. Cresce con la lunghezza del prompt. Il TPOT (Time Per Output Token, tempo per token in uscita) è il tempo medio tra un token e il successivo dopo il primo; l'ITL (Inter-Token Latency, latenza tra token) è la stessa grandezza misurata token per token, utile per vedere gli scatti. La latenza totale è circa:
Calcolo · latenza totale
In una chat con streaming conta molto il TTFT; in un'elaborazione in batch di documenti conta il numero totale di token al secondo.
I modelli che «ragionano» prima di rispondere generano token di ragionamento, visibili o no. Sono token in uscita a tutti gli effetti: allungano l'attesa e si pagano come output.
I provider fanno pagare a milione di token, e il token in uscita costa di solito alcune volte quello in ingresso (rapporti tra 3 e 8 sono comuni). Non è arbitrario: un token di prompt è una piccola frazione di una passata eseguita a pieno regime di calcolo, mentre un token di risposta occupa una passata intera, limitata dalla memoria, e tiene occupata per tutto il tempo la cache KV della conversazione. Per lo stesso motivo alcuni listini alzano il prezzo oltre una certa lunghezza del contesto.
Molte richieste cominciano allo stesso modo: lo stesso prompt di sistema, le stesse definizioni dei tool, lo stesso documento lungo su cui si fanno più domande. La cache KV di quel prefisso è identica ogni volta, perché dipende solo dai token che vengono prima. Il prompt caching dei provider la conserva per qualche minuto dall'ultimo uso: la richiesta successiva che inizia con esattamente lo stesso prefisso salta quella parte del prefill.
Il TTFT scende e i token letti dalla cache costano una frazione del prezzo normale (per alcuni provider un decimo); scriverli in cache può costare un po' di più.
Due conseguenze pratiche. Il prefisso deve coincidere token per token: basta un orario o un identificativo all'inizio del prompt di sistema per invalidare tutto, quindi le parti che cambiano vanno in fondo. E non va confuso con la cache delle risposte, che un'applicazione o un gateway tiene per restituire una risposta già data a una domanda uguale o simile, senza chiamare il modello: quella è descritta nella guida sull'ingegneria dei sistemi basati su LLM (Large Language Model). Il prompt caching risparmia il prefill, ma la risposta viene generata ogni volta.
Muovi i token in ingresso e in uscita e la parte di prompt già in cache: guarda come si dividono il tempo (prefill contro decode) e il costo.
Modello a «tetto» semplificato. GPU ipotetica con 3,35 TB/s di banda e 989 TFLOPS (mille miliardi di operazioni al secondo) in bf16, gli ordini di grandezza di una scheda da datacenter recente, usata all'80% della banda e al 50% del calcolo; con 4 GPU tutto moltiplicato per 4, come se la divisione fosse perfetta. Una sola richiesta, senza coda né rete. La quantizzazione accorcia il decode (meno byte da leggere) ma qui non il prefill. Prezzi inventati: 3 $ per milione di token in ingresso, 0,30 $ letti dalla cache, 15 $ in uscita.
Se nel decode la GPU (Graphics Processing Unit) passa il tempo a leggere i pesi, la mossa ovvia è usare ogni lettura per più conversazioni. Leggere 16 GB di pesi e usarli per 64 token di 64 utenti diversi costa quasi quanto usarli per uno solo.
È come un autobus: il viaggio costa più o meno lo stesso con un passeggero o con cinquanta. Il batching fa salire più passeggeri; tutto il resto di questo capitolo serve a farne salire di più, o a far andare l'autobus più veloce.
Il batching statico raccoglie un gruppo di richieste e le porta avanti insieme fino alla fine: chi ha chiesto una risposta di 20 token aspetta chi ne ha chiesta una di 2.000, e i posti liberati restano vuoti. Il batching continuo, introdotto dal sistema Orca (Yu e colleghi, 2022), decide la composizione del batch a ogni passata: una conversazione che finisce esce subito, una richiesta nuova entra al suo posto.
Oggi è il comportamento normale dei motori di inferenza come vLLM, SGLang e TensorRT-LLM. Una variante, il prefill a blocchi (chunked prefill), spezza i prompt lunghi in pezzi da mescolare alle passate di decode, così l'arrivo di un documento enorme non blocca la scrittura degli altri utenti.
Il limite al numero di conversazioni insieme è la memoria della cache KV (key-value, capitolo 3). I primi sistemi riservavano a ogni richiesta uno spazio contiguo per la lunghezza massima possibile, perché non si sa in anticipo quanto sarà lunga la risposta. Kwon e colleghi (2023) hanno misurato che in quei sistemi solo il 20–40% circa della memoria della cache conteneva davvero dati utili: il resto era prenotato e mai usato, o frammentato.
PagedAttention, il cuore di vLLM, applica l'idea della memoria virtuale dei sistemi operativi: la cache è divisa in blocchi di dimensione fissa (16 token per impostazione predefinita) assegnati man mano che servono, anche non contigui, con una tabella che dice dove sta ogni blocco.
Lo spreco scende sotto il 4%, nel batch entrano molte più conversazioni e il throughput, il numero di token prodotti al secondo dal server, nel lavoro originale cresce di 2–4 volte a parità di latenza. I blocchi si possono anche condividere: più richieste con lo stesso prefisso puntano agli stessi blocchi, che è un modo di realizzare il prompt caching del capitolo 4.
Aumenta le conversazioni nel batch e confronta la prenotazione per la lunghezza massima con la cache a pagine: guarda quante entrano davvero e come cambiano throughput e velocità di ciascuno.
Modello da 8 miliardi di parametri in bf16 (bfloat16, 2 byte per peso) con cache di Llama 3 8B (128 KiB per token) su una GPU ipotetica da 80 GB con le stesse prestazioni del capitolo 4; 4 GB lasciati alla libreria. Ogni passata dura il massimo tra il tempo per leggere pesi e cache e il tempo per calcolare. Si ignorano il prefill delle richieste nuove, la crescita delle conversazioni durante la generazione e lo spreco residuo della cache a pagine.
Il batching aumenta i token al secondo del server, non quelli della singola conversazione. Per accelerare la singola risposta si sfrutta la stessa asimmetria in un altro modo: siccome il decode è limitato dalla memoria, una passata del modello grande su 5 token costa quasi quanto una su un token solo. La decodifica speculativa (Leviathan e colleghi, 2023; in parallelo Chen e colleghi, DeepMind) usa un modello bozza piccolo e veloce che propone γ token in sequenza; il modello grande li controlla tutti in una passata sola, come fosse un pezzetto di prefill.
La verifica accetta ogni token proposto x con probabilità:
Calcolo · accettazione di un token
dove p è la probabilità del modello grande e q quella della bozza.
Al primo rifiuto si ricampiona da una distribuzione corretta e il resto della bozza si butta; se tutti vengono accettati, la stessa passata regala un token in più. Il risultato notevole è che il testo prodotto ha esattamente la stessa distribuzione che avrebbe dato il modello grande da solo: si guadagna velocità senza perdere qualità.
Il guadagno dipende da quanto spesso la bozza indovina, cioè dal tasso di accettazione α, e varia con il tipo di testo: alto per codice e testo prevedibile, basso per testo creativo. Esistono varianti senza modello separato, che aggiungono al modello grande piccole teste che indovinano più token in avanti (per esempio Medusa).
Muovi il tasso di accettazione, il numero di token proposti e il costo della bozza: le barre mostrano l'accelerazione attesa per ogni lunghezza della bozza.
Formule del lavoro di Leviathan e colleghi: token attesi per passata (1 − αγ+1) / (1 − α); accelerazione = token attesi / (γ·c + 1), con c il costo di una passata della bozza in unità del modello grande. Assumono che ogni token sia accettato in modo indipendente con la stessa probabilità α e che verificare γ + 1 token costi come una passata normale, cosa vera solo finché il decode resta limitato dalla memoria: con batch molto grandi il vantaggio cala.
Se il decode è limitato dai byte letti, dimezzare i byte dei pesi accelera quasi della metà il decode e libera memoria per la cache. La quantizzazione rappresenta i pesi con meno bit: da 16 (bf16, bfloat16) a 8 (int8 o FP8, virgola mobile a 8 bit) o a 4, con un fattore di scala per ogni gruppo di pesi per non perdere l'ordine di grandezza. Metodi come GPTQ (quantizzazione post-addestramento per modelli GPT) e AWQ (Activation-aware Weight Quantization, quantizzazione che tiene conto delle attivazioni) scelgono come arrotondare guardando dati di esempio, per sbagliare meno proprio sui pesi che contano di più.
| Precisione | Byte per peso | Pesi di un 8B | Pesi di un 70B | Qualità, di solito |
|---|---|---|---|---|
| bf16 | 2 | 16 GB | 140 GB | riferimento |
| int8 / FP8 | 1 | 8 GB | 70 GB | differenze minime nella maggior parte dei test |
| int4 | 0,5 (più le scale) | ≈ 4–5 GB | ≈ 35–40 GB | perdita piccola ma misurabile, più evidente nei modelli piccoli e nei compiti difficili |
Si quantizza anche la cache KV, di solito a 8 bit, con la stessa logica: più conversazioni nella stessa memoria. Prima di adottare una versione quantizzata conviene misurarla sui propri compiti.
Un'applicazione spesso non vuole prosa ma dati: un oggetto JSON (JavaScript Object Notation) con certi campi, la chiamata a un tool con argomenti validi. Chiederlo nelle istruzioni funziona quasi sempre, e «quasi» è il problema: basta un «Certo! Ecco il JSON:» davanti, una virgola in più o un valore fuori elenco per far fallire il parser. La decodifica vincolata risolve il problema nel punto in cui nasce, la scelta del token.
A ogni passata, prima del campionamento, il server calcola quali token sono compatibili con lo schema dato il testo prodotto fin lì, e porta a meno infinito il logit di tutti gli altri. Dopo la softmax quei token hanno probabilità zero; i token ammessi si dividono la probabilità rimasta, rinormalizzata come nei filtri del capitolo 2. Il modello sceglie liberamente, ma solo tra le continuazioni valide.
Lo schema, per esempio un JSON Schema o una grammatica, viene tradotto in un automa: una macchina a stati che sa, in ogni punto, quali caratteri possono venire dopo. Il lavoro difficile è passare dai caratteri ai token, perché un token può contenere più caratteri e attraversare più stati dell'automa. Librerie come Outlines (Willard e Louf, 2023), XGrammar e le grammatiche di llama.cpp precalcolano per ogni stato l'insieme dei token ammessi, così la maschera costa poco a ogni passata.
Le modalità di output strutturato «stretto» delle API (interfacce di programmazione) dei provider e il function calling vincolato si basano su questo meccanismo: è il motivo per cui una chiamata a tool ha argomenti sintatticamente validi, come si vede nella guida da assistente ad agente.
{
"type": "object",
"properties": {
"stato": {
"enum": ["aperto", "chiuso"]
},
"priorita": {
"type": "integer",
"minimum": 1, "maximum": 5
}
},
"required": ["stato", "priorita"],
"additionalProperties": false
}
Avanza una passata alla volta con e senza vincolo: con il vincolo i token incompatibili con lo schema spariscono e gli altri si dividono la loro probabilità.
Probabilità inventate e solo quattro o cinque candidati per passata; per semplicità i candidati sono gli stessi nei due modi, mentre un modello vero, dopo un «Certo», continuerebbe con altra prosa. La maschera e la rinormalizzazione sono quelle reali: probabilità zero ai token vietati, divisione per la somma dei rimasti.
| Concetto | Dove agisce | Che cosa cambia | Che cosa costa o rischia |
|---|---|---|---|
| Generazione autoregressiva | il ciclo intero | prompt in una passata, risposta in una passata per token | la risposta non si parallelizza |
| Temperatura, top-k, top-p, min-p | la scelta, dopo i logit | quanto è vario o prevedibile il testo | troppo alti: incoerenza; troppo bassi: ripetizione |
| Penalità | i logit dei token già usati | meno ripetizioni | penalizza anche le ripetizioni necessarie |
| Cache KV (key-value) | attenzione, ogni strato | il decode elabora solo il token nuovo | memoria lineare in token e conversazioni |
| GQA, MQA (attenzione a query raggruppate o a query multiple) | architettura dell'attenzione | cache più piccola, da alcune a decine di volte rispetto all'attenzione completa | piccola perdita di qualità, maggiore con MQA |
| Prefill contro decode | uso della GPU (scheda acceleratrice) | TTFT (tempo al primo token) dal prompt, TPOT (tempo per token) dalla banda di memoria | uscita più cara dell'ingresso nei listini |
| Prompt caching | prefill di un prefisso identico | TTFT e costo dell'ingresso più bassi | serve un prefisso stabile; dura pochi minuti |
| Batching continuo, PagedAttention | il server | più conversazioni per passata, throughput più alto | ogni utente scrive un po' più lento |
| Decodifica speculativa | il decode della singola conversazione | meno passate del modello grande, stessa distribuzione | serve una bozza che indovini spesso |
| Quantizzazione | pesi e cache in memoria | meno byte da leggere, più spazio per la cache | perdita di qualità crescente sotto gli 8 bit |
| Decodifica vincolata | maschera sui logit | output sempre conforme allo schema | forma garantita, contenuto no |