SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-13

Misura i token al secondo di un LLM locale

Scopri quando una GPU a noleggio conviene rispetto al pagamento per token: misura il throughput con test a concorrenza crescente e calcola la soglia reale.

Perché i token al secondo determinano la convenienza di una GPU

I token al secondo indicano la velocità con cui il server genera il testo in output. È il valore che determina se il noleggio di una GPU costa meno del pagamento di un'API in base ai token. Un server GPU viene fatturato a ore, indipendentemente dal fatto che sia utilizzato o inattivo. Un'API gestita viene fatturata in base ai token. La GPU è quindi conveniente solo se mantiene una velocità di output sufficientemente elevata per la maggior parte delle ore pagate.

Per questo serve una misurazione, non un valore trovato altrove. Questa pagina definisce i quattro valori che vale la pena registrare, quindi fornisce i comandi per ottenerli e i calcoli per trasformarli in una decisione.

Perché il valore pubblicato dei token al secondo non è il tuo valore

DigitalOcean ha pubblicato a luglio 2026 i valori di throughput per una singola NVIDIA H200 che esegue llama3.3-70b-instruct in FP8 (virgola mobile a 8 bit) tramite vLLM. Questi valori sono utili, ma non sono i tuoi.

ChartPublished DigitalOcean H200 figures, llama3.3-70b-instruct FP8, July 2026
The data behind this chart
[
  {
    "config": "H200, one stream",
    "tok_s": "47"
  },
  {
    "config": "H100, saturated",
    "tok_s": "236"
  },
  {
    "config": "H200, saturated",
    "tok_s": "2,036"
  },
  {
    "config": "H200, saturated, in+out",
    "tok_s": "4,071.6"
  }
]

Ogni riga precedente è riportata da quella pagina. Due righe rappresentano il limite inferiore di un intervallo indicato nella pagina, quindi vanno interpretate come valori minimi. Nessuno dei valori di questo grafico è stato misurato da noi.

Inizia dalle ultime due righe. Il valore principale è 4,071.6 tok/s, mentre il throughput delle sole risposte è 2,036 tok/s. Il valore principale conta insieme i token di input e di output. Il test ha usato 1,024 token di input e 1,024 token di output, quindi quasi esattamente metà del valore principale corrisponde all'output. Questa distinzione è importante perché l'output è la parte su cui viene calcolata la fatturazione ed è anche la parte più lenta. Il prefill, cioè la lettura del prompt, elabora tutti i token di input in un unico passaggio. Il decode, cioè la generazione della risposta, produce un token alla volta. Il valore di throughput complessivo fa quindi una media tra un'operazione poco costosa e una costosa.

Ora considera la prima riga. La stessa H200, mentre gestisce una richiesta alla volta, produce 47 tok/s. Il valore con GPU satura è quindi oltre quaranta volte superiore sullo stesso hardware. Questa differenza esiste perché, durante un singolo passaggio di decode, la GPU trascorre gran parte del tempo in attesa della memoria. Le richieste concorrenti utilizzano quel tempo altrimenti inattivo. La seconda riga, 236 tok/s, riguarda una singola H100 sullo stesso modello, limitata dalla KV cache, cioè la cache di key e value: la memoria per richiesta che una conversazione in esecuzione mantiene sulla scheda. Una scheda da 80 GB può gestire meno richieste concorrenti per un modello 70B, quindi raggiunge la saturazione a un valore inferiore.

Se cambi il modello o il rapporto tra input e output, tutti i valori precedenti cambiano. I valori pubblicati definiscono le aspettative, non il budget. La stessa regola si applica a eseguire un benchmark onesto di un VPS per disco e rete.

I quattro numeri che contano

  • Time to first token, TTFT. Il ritardo tra l'invio di una richiesta e l'arrivo del primo token di output. È dato dal tempo di prefill più il tempo in coda. È il valore che l'utente percepisce direttamente.
  • Token di output al secondo, per stream. La velocità con cui viene generata una risposta dopo l'inizio dell'elaborazione. Oltre circa 20 tok/s, la generazione è già più veloce della lettura della maggior parte delle persone, quindi un'ulteriore velocità offre pochi vantaggi.
  • Throughput totale di output a saturazione. La somma dei valori di tutti gli stream concorrenti quando il server è completamente sotto carico. Questo è il valore della capacità ed è quello che determina il costo della GPU.
  • p50 e p99 del TTFT in condizioni di concorrenza. p50 è il valore della richiesta mediana. p99 è il valore al di sotto del quale rientrano 99 richieste su 100. L'accodamento si manifesta sempre prima nel p99.

I primi due valori migliorano quando il server è poco utilizzato. Il terzo migliora quando il server è sotto carico. Sono in contrasto tra loro, perciò nessun singolo numero descrive un server di serving.

Imposta le lunghezze dell'input e dell'output prima di misurare

Il throughput dipende dalla struttura del traffico. Un prompt di 4,000 token con una risposta di 50 token è un carico dominato dal prefill. Un prompt di 200 token con una risposta di 2,000 token è un carico dominato dal decode. Lo stesso server restituisce valori molto diversi di token al secondo nei due casi. Scegli quindi un rapporto, riportalo accanto a ogni valore registrato e non effettuare mai confronti tra rapporti diversi. 1,024 token in ingresso e 1,024 in uscita sono un'impostazione predefinita ragionevole, perché diversi vendor pubblicano risultati con questo rapporto. Se conosci il traffico reale, usa il traffico reale.

Imposta anche la lunghezza dell'output. Un modello che raggiunge il token di arresto dopo 60 token produce un'esecuzione più breve che sembra più veloce, perché il TTFT ne rappresenta una quota maggiore. Il flag --ignore-eos nel client di benchmark vLLM fa sì che ogni richiesta generi esattamente il numero di token richiesto, mantenendo comparabili due esecuzioni. La scelta del modello incide su questi valori più di qualsiasi flag: adattare un modello Qwen 3 a una singola GPU VPS illustra l'aspetto relativo alla memoria.

Misurare prima un singolo stream

Inizia dal caso più semplice. È un controllo di coerenza e rappresenta anche un limite massimo. Ollama stampa i propri tempi.

ollama run llama3.1:8b --verbose "Write 200 words about disk scheduling."

Il valore da leggere è eval rate, cioè il numero di token di output al secondo. prompt eval rate è la velocità di prefill, mentre load duration è il tempo impiegato per caricare il modello nella VRAM. Alla prima chiamata dopo un avvio a freddo, load duration è elevato, quindi total duration è fuorviante. Esegui il comando due volte e leggi il secondo risultato. Per impostazione predefinita, Ollama scarica dalla memoria un modello inattivo dopo cinque minuti; una pausa lunga tra le esecuzioni riporta quindi al caso di avvio a freddo.

Gli stessi campi sono disponibili tramite l'API, che è più semplice da usare negli script.

curl -s http://127.0.0.1:11434/api/generate -d '{
  "model": "llama3.1:8b",
  "prompt": "Write 200 words about disk scheduling.",
  "stream": false
}' | jq '{eval_count, eval_duration,
         tok_s: (.eval_count / (.eval_duration / 1000000000))}'

eval_duration è espresso in nanosecondi, quindi la divisione per 1,000,000,000 restituisce i secondi. È esattamente la divisione prescritta dalla documentazione dell'API di Ollama per calcolare i token al secondo. Se il server non è ancora attivo, la guida per eseguire autonomamente un LLM con Ollama su un VPS descrive l'installazione e l'unità systemd.

Per misurare il TTFT serve una richiesta in streaming, e curl può calcolare il tempo al posto tuo.

curl -s -o /dev/null -N \
  -w 'ttfb=%{time_starttransfer}s  total=%{time_total}s\n' \
  http://127.0.0.1:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"Qwen/Qwen3-8B",
       "messages":[{"role":"user","content":"Write 200 words about disk scheduling."}],
       "stream":true,"max_tokens":256}'

time_starttransfer indica il momento in cui arriva il primo byte del corpo della risposta. In un completamento chat in streaming, quel byte appartiene al primo server-sent event, che contiene il primo token di contenuto oppure un delta contenente solo il ruolo, inviato subito prima. Considera quindi il valore come il TTFT con una possibile differenza pari a un event. È sufficientemente accurato per confrontare due esecuzioni sullo stesso server.

I valori ottenuti con un singolo stream fanno apparire la macchina migliore per due motivi. Il TTFT è il valore migliore ottenibile, perché non ci sono richieste in coda davanti alla tua. Anche la velocità per stream è la migliore ottenibile, perché l'intera scheda sta servendo una sola richiesta. Nessuno dei due valori indica quale carico la macchina sia in grado di gestire.

Come eseguire una scansione della concorrenza?

Una scansione esegue lo stesso carico di lavoro fisso con livelli di concorrenza crescenti e registra i risultati di ogni passaggio. vLLM include il client necessario e usa l'API OpenAI, quindi funziona anche con Ollama e con qualsiasi altro servizio compatibile con OpenAI.

vllm bench serve \
  --backend openai-chat \
  --base-url http://127.0.0.1:8000 \
  --endpoint /v1/chat/completions \
  --model Qwen/Qwen3-8B \
  --dataset-name random \
  --random-input-len 1024 \
  --random-output-len 1024 \
  --ignore-eos \
  --num-prompts 160 \
  --max-concurrency 16 \
  --percentile-metrics ttft,tpot,itl,e2el \
  --metric-percentiles 50,99

--max-concurrency limita il numero di richieste simultanee ed è la variabile da modificare nella scansione. --num-prompts indica il numero totale di richieste inviate; impostalo a circa dieci volte la concorrenza per ottenere una media stabile. Il riepilogo mostra Output token throughput (tok/s): e Total token throughput (tok/s):, quindi Mean TTFT (ms):, Median TTFT (ms): e P99 TTFT (ms): sotto l'intestazione Time to First Token.

L'output non include la frequenza per singolo stream, ma basta una divisione per calcolarla. Mean TPOT (ms): indica il tempo medio per ogni token di output successivo al primo: 25 ms per token corrispondono a 40 token al secondo per stream. Dividendo il throughput dell'output per la concorrenza si ottiene lo stesso risultato.

Esegui quindi il ciclo e salva ogni risultato.

for C in 1 4 16 32 64 128; do
  vllm bench serve \
    --backend openai-chat \
    --base-url http://127.0.0.1:8000 \
    --endpoint /v1/chat/completions \
    --model Qwen/Qwen3-8B \
    --dataset-name random \
    --random-input-len 1024 \
    --random-output-len 1024 \
    --ignore-eos \
    --num-prompts $(( C * 10 )) \
    --max-concurrency "$C" \
    --percentile-metrics ttft,tpot,itl,e2el \
    --metric-percentiles 50,99 \
    --save-result --result-filename "sweep-c$C.json"
done
Lettura dei file JSON salvati

Ogni esecuzione scrive un file. Estrai quindi in una sola volta i campi desiderati da tutti i file.

for f in sweep-c*.json; do
  jq -r --arg f "$f" \
    '[$f, .output_throughput, .total_token_throughput,
      .median_ttft_ms, .p99_ttft_ms] | @tsv' "$f"
done

output_throughput indica i token di output al secondo. total_token_throughput include anche i token di input; con un rapporto 1:1 il valore è quindi quasi il doppio. p99_ttft_ms esiste solo perché --metric-percentiles includeva 99; se richiedi un percentile che non era stato richiesto, jq stampa null.

Che cosa mostra realmente un test di concorrenza?

ChartIllustrative sweep shape: 8B model, one 24 GB GPU, 1024 in / 1024 out
The data behind this chart
[
  {
    "label": "1 stream",
    "per_stream_tok_s": 92,
    "total_tok_s": 92,
    "ttft_p50_ms": 48,
    "ttft_p99_ms": 61
  },
  {
    "label": "4 streams",
    "per_stream_tok_s": 88,
    "total_tok_s": 352,
    "ttft_p50_ms": 71,
    "ttft_p99_ms": 96
  },
  {
    "label": "16 streams",
    "per_stream_tok_s": 71,
    "total_tok_s": 1136,
    "ttft_p50_ms": 152,
    "ttft_p99_ms": 244
  },
  {
    "label": "32 streams",
    "per_stream_tok_s": 54,
    "total_tok_s": 1728,
    "ttft_p50_ms": 287,
    "ttft_p99_ms": 498
  },
  {
    "label": "64 streams",
    "per_stream_tok_s": 34,
    "total_tok_s": 2176,
    "ttft_p50_ms": 611,
    "ttft_p99_ms": 1240
  },
  {
    "label": "128 streams",
    "per_stream_tok_s": 18,
    "total_tok_s": 2304,
    "ttft_p50_ms": 1490,
    "ttft_p99_ms": 3820
  }
]

Queste 6 righe illustrano l'andamento prodotto da un test su una piccola GPU disponibile a noleggio, con ordini di grandezza plausibili. Non sono misurazioni del tuo server e non rappresentano dati del fornitore. Esegui il ciclo precedente e sostituiscile con i tuoi valori.

Osserva l'andamento, perché è questo che si può generalizzare. Con un solo flusso, l'intera macchina produce 92 token al secondo, con un TTFT p99 di 61 ms. A 128 streams, il totale raggiunge 2304 token al secondo, venticinque volte di più, mentre ogni singolo flusso scende a 18 token al secondo e il TTFT p99 raggiunge 3820 ms. Il throughput totale aumenta perché il batching trasforma i tempi di attesa della memoria in lavoro utile. La velocità per flusso diminuisce perché la stessa capacità di calcolo viene condivisa.

L'ultimo raddoppio è indicativo. Passare da 64 a 128 flussi aggiunge meno del sei percento al totale, mentre il TTFT p99 aumenta all'incirca di tre volte. Questo indica che la cache KV è piena e che le richieste si accodano invece di essere elaborate. Il punto operativo utile è precedente: con 32 flussi, la macchina produce ancora 1728 token al secondo, il 75 percento del picco, a 54 token al secondo per flusso e con un TTFT p99 di 498 ms. Usa questo punto come capacità dichiarata. Il picco della curva non è un valore che puoi offrire agli utenti.

Ollama e vLLM non misurano la stessa cosa

Esegui questa scansione su un server Ollama con la configurazione predefinita: il totale cambierà appena. OLLAMA_NUM_PARALLEL è impostato su 1 per impostazione predefinita, quindi viene elaborata una sola richiesta mentre le altre restano in attesa. È questa coda a far aumentare il p99 del TTFT, mentre l'output totale rimane stabile. Aumenta questo valore prima di eseguire qualsiasi misurazione.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_NUM_PARALLEL=8"

Riavvia con sudo systemctl restart ollama, quindi verifica che il modello occupi ancora una quantità di memoria compatibile. Ogni slot parallelo riceve una propria quota della finestra di contesto. La documentazione di Ollama specifica quindi che un contesto da 2K con 4 richieste parallele alloca 8K. Se aumenti abbastanza il numero di slot, il modello esce dalla VRAM. Controlla ollama ps: se una colonna PROCESSOR contiene un valore come 48%/52% CPU/GPU, una parte del modello è in esecuzione sulla CPU e il throughput diminuirà all'aumentare della concorrenza, invece di aumentare. Oltre il numero di slot paralleli, le richieste vengono accodate fino a OLLAMA_MAX_QUEUE, che per impostazione predefinita è 512. Dopo questo limite, il server restituisce 503.

vLLM usa il continuous batching. Inserisce quindi nuove richieste nel batch in esecuzione quando si liberano gli slot. La curva continua a salire finché non si esaurisce la cache KV. Ollama è ottimizzato per un solo modello, una sola macchina e costi di configurazione ridotti. I due motori producono quindi risultati diversi sulla stessa scansione. Questo è il tema reale di Ollama e vLLM a confronto come motori di serving. Registra il motore e la versione che hanno prodotto ogni valore.

Cinque modi per misurare la cosa sbagliata

  • Il client è lontano. Eseguire il benchmark dal laptop tramite Internet aggiunge il round trip della connessione a ogni TTFT, quindi si misura la connessione domestica. Eseguire il client nella stessa regione del server.
  • Il modello era a freddo. La prima richiesta deve caricare i pesi e, con vLLM, può anche eseguire la graph capture. Inviare un batch di riscaldamento e scartare il risultato.
  • La prefix caching ha risposto al posto vostro. vLLM abilita il caching automatico dei prefissi per impostazione predefinita. Inviare ripetutamente lo stesso prompt misura quindi la cache anziché il prefill e il TTFT scende a una frazione del valore reale. --dataset-name random evita questo comportamento perché ogni prompt è diverso. Per esserne certi, avviare il server con --no-enable-prefix-caching.
  • Gli output erano brevi. Con risposte di 32 token, il TTFT domina ogni richiesta e i token al secondo descrivono in realtà il prefill. Usare --ignore-eos con una lunghezza di output realistica.
  • È stata riportata una concorrenza pari a 1. È il numero più favorevole nel prospetto e non ha alcuna relazione con i costi.

Trasforma il valore misurato in una decisione

Usa il throughput di output a regime ottenuto durante lo sweep, non il valore per singolo stream, e confrontalo con il prezzo per token. Il punto di pareggio si calcola con una divisione:

break_even_tok_s = (price_per_hour / price_per_million_output_tokens) * 1000000 / 3600

Applica il calcolo ai prezzi di DigitalOcean di luglio 2026. Il loro endpoint di inferenza dedicato H200 costava $4.47 all'ora, mentre l'equivalente serverless costava $0.65 per milione di token. Quindi 4.47 diviso 0.65 equivale a 6.88 milioni di token all'ora. Dividendo per 3,600 secondi si ottengono circa 1,910 token di output al secondo. I prezzi sono quelli di DigitalOcean. La divisione è nostra.

La parola decisiva è sostenuto. Raggiungere 1,910 token al secondo a regime per due ore al giorno non significa mantenere un throughput sostenuto di 1,910 token al secondo, perché paghi anche le altre ventidue ore. Il punto di crossover calcolato da DigitalOcean per il GPU Droplet più economico, da $3.44 all'ora, corrisponde a un tasso medio di utilizzo sostenuto del 72.2 percento. Al di sotto di questa soglia, conviene il prezzo per token. Di solito sono le ore di GPU inattiva, non i token elaborati lentamente, a rendere antieconomico il self-hosting.

La decisione dipende quindi da due fattori. Lo sweep indica il limite massimo. Il tuo profilo di traffico indica quale frazione di quel limite utilizzi effettivamente. Moltiplica i due valori, poi porta il risultato a il punto di pareggio tra GPU VPS e API con prezzo per token e individua la risposta per il tuo volume.

FAQ

Qual è un buon numero di token al secondo per un LLM self-hosted?

Esistono due risposte, perché questa metrica ha due funzioni. Per una persona che legge l'output, qualsiasi valore superiore a circa 20 token generati al secondo per stream è già più veloce della velocità di lettura. Un valore maggiore non offre quindi vantaggi. Per i costi conta il throughput totale di output a saturazione. Un valore adeguato è quello che supera il punto di pareggio. Con un costo di $0.65 per milione di token e un server dal costo di $4.47 all'ora, a prezzi di luglio 2026 questa soglia è vicina a 1,910 token generati al secondo in modo continuativo. Un singolo stream su un modello di grandi dimensioni non la raggiunge. Questo è il motivo per cui esiste il batching.

Perché il throughput di Ollama rimane invariato quando aggiungo richieste simultanee?

OLLAMA_NUM_PARALLEL ha come valore predefinito 1. Il server gestisce quindi una richiesta alla volta per modello e accoda le altre, fino a OLLAMA_MAX_QUEUE (512 per impostazione predefinita), prima di restituire 503. L'output totale rimane invariato mentre il p99 TTFT aumenta. Questo indica la presenza di una coda, non di una GPU satura. Imposta la variabile in un drop-in di systemd e riavvia il servizio. Controlla quindi ollama ps, perché ogni slot parallelo moltiplica il contesto allocato e può spostare parte del modello sulla CPU.

Devo misurare il tempo al primo token o i token al secondo?

Entrambi, perché aumentano in direzioni opposte al crescere del carico. Il TTFT è ciò che percepisce l'utente, mentre il throughput di output a saturazione determina il costo in fattura. Registra il TTFT p50 e p99 a ogni livello di concorrenza. Scegli quindi il livello di concorrenza più alto per cui il TTFT p99 è ancora accettabile. Indica il throughput raggiunto a quel livello come capacità del sistema, non il valore massimo rilevato nel punto più alto della curva.

Un valore maggiore di token al secondo indica sempre un costo inferiore per token?

No. Il costo per token è il prezzo orario diviso per il numero di token effettivamente generati dal server in quell'ora. Un server veloce che rimane inattivo per gran parte della giornata ha quindi comunque un costo elevato per token. A determinarlo è l'utilizzo, non la velocità di picco. Controlla anche le unità di misura: un throughput totale di token dichiarato include i token di input. Con un rapporto input/output di 1:1, il valore è quindi vicino al doppio del tasso di output su cui viene calcolato il costo.

#benchmarking#tokens-per-second#vllm#ollama#gpu-vps