Livello di ragionamento per LLM locali: costi reali
Scopri come il livello di ragionamento cambia token, latenza e uso della finestra di contesto su CPU o GPU locali, senza modificare pesi e quantizzazione.
Quali effetti ha il livello di ragionamento su un LLM locale
Il livello di ragionamento indica per quanto tempo il modello deve elaborare la risposta prima di fornirla. Modifica soltanto la lunghezza della fase di ragionamento. I pesi salvati su disco sono identici a ogni livello, così come la quantizzazione, e la risposta viene prodotta dallo stesso passaggio forward. Cambia il numero di token che il modello utilizza inizialmente per il proprio blocco note interno.
Questa distinzione è importante per il modo in cui vengono utilizzati questi token. In un'API hosted, i token di ragionamento compaiono in fattura. Su un VPS di tua proprietà, consumano tempo di generazione sulla tua CPU o GPU e spazio nella finestra di contesto. Un modello configurato al livello di ragionamento massimo può utilizzare gran parte dell'output per elaborare la risposta prima di produrre la prima parola. Su hardware self-hosted, questo può fare la differenza tra una risposta in due secondi e una risposta in due minuti.
Dove risiede il livello: nel template della chat, non nei pesi
Un modello di ragionamento è addestrato per generare un segmento di ragionamento, generalmente racchiuso tra i tag <think> e </think>, prima della risposta finale. Il livello di impegno è un'istruzione che il template della chat del modello inserisce nel prompt. Questo template è un file Jinja distribuito con il modello. Legge una variabile come reasoning_effort e genera una riga diversa a livello di sistema per ogni valore. Il modello è stato addestrato ad accorciare o allungare il proprio blocco di ragionamento in risposta a quella riga.
Ne derivano due conseguenze. I nomi dei livelli appartengono al modello, non al runtime. Un nome indicato nella scheda di un modello può quindi non avere alcun significato per un altro modello. Inoltre, se un componente della catena sostituisce il template della chat del modello con uno generico, la variabile non viene mai inserita nel prompt e l'impostazione non produce alcun effetto, senza segnalare errori.
Verificata il 2026-08-20, la scheda del modello Qwen3.8-27B documenta tre livelli di impegno: low, medium e xhigh, con xhigh come valore predefinito. high non esiste. Il ragionamento si abilita con enable_thinking, attivo per impostazione predefinita. La scheda documenta inoltre preserve_thinking, anch'esso attivo per impostazione predefinita, che conserva nella cronologia della conversazione il ragionamento dei turni precedenti. gpt-oss usa invece low, medium e high. Molte altre famiglie accettano soltanto un valore booleano. Consulta la scheda relativa alla versione esatta che hai scaricato, perché questi nomi non sono standard. Prima viene Eseguire un modello 27B su un VPS. Questa pagina spiega cosa impostare dopo che il modello ha iniziato a rispondere.
Perché un maggiore sforzo di ragionamento costa di più su un VPS
Token di output. I token di ragionamento vengono generati e seguono lo stesso ciclo di decodifica della risposta. Supponiamo che un’attività produca 200 token di risposta e 4.000 token di ragionamento. Sono stati generati 4.200 token, ma il lettore ne ha visti 200. La velocità di decodifica dipende dalla larghezza di banda della memoria e da quanta quantizzazione hai scelto, quindi l’unico margine rimasto è il numero di token.
Tempo reale. L’utente attende il primo token della risposta, perché tutto ciò che lo precede appare come una schermata vuota o un indicatore di caricamento compresso. I token di ragionamento vengono emessi per primi, quindi l’attesa è approssimativamente pari al numero di token di ragionamento diviso per la velocità di decodifica, più il tempo di elaborazione del prompt. Raddoppiando la lunghezza del ragionamento, raddoppia anche questa attesa.
Contesto. I token di ragionamento occupano la finestra di contesto come qualsiasi altro token. Con preserve_thinking attivo, il blocco di lavoro del primo turno è ancora presente nel prompt al quinto turno. Di conseguenza, l’elaborazione del prompt diventa più lenta a ogni turno, mentre la finestra si riempie da entrambe le estremità. Aumentare num_ctx per contenerlo richiede memoria per la cache KV che, su un VPS senza GPU, corrisponde alla RAM di sistema che potresti non avere a disposizione.
Quando aumentare il livello e quando mantenerlo basso
Aumentalo per le attività in cui un passaggio intermedio errato compromette il risultato: calcoli in più passaggi e conversioni di unità, pianificazione di una modifica su più file, codice che deve essere compilato e problemi con vincoli in cui un'unica risposta deve soddisfare più condizioni contemporaneamente. In questi casi il ragionamento svolge un lavoro effettivo e una sequenza più lunga è un modo economico per rilevare un errore che il modello altrimenti consoliderebbe.
Mantienilo basso quando la risposta è già presente nell'input e il compito consiste nel trasferirla. Rientrano in questa categoria l'estrazione, la classificazione, l'assegnazione di tag, la traduzione, la riscrittura, la sintesi e la formattazione. La fase di ragionamento si limita per lo più a riformulare il compito e lascia al modello lo spazio per mettere in discussione un'intuizione iniziale corretta.
Mantienilo basso anche per tutte le attività interattive. In una chat o in un editor partecipi direttamente al processo: una risposta rapida che puoi correggere è preferibile a una risposta lenta che devi attendere. Questo è il compromesso reale alla base del collegamento di un agente di programmazione a un modello locale: un agente effettua molte chiamate di piccole dimensioni e il costo del ragionamento viene applicato a ognuna di esse.
Come impostare il livello in llama.cpp
llama.cpp scrive direttamente la variabile nel template. È quindi il runtime in cui è possibile verificare con certezza che il livello sia arrivato. Impostare -m sul file GGUF già disponibile.
llama-server -m ./qwen3.8-27b-Q4_K_M.gguf \
--jinja \
--reasoning-effort medium \
--reasoning-format deepseek \
-c 32768 \
--host 127.0.0.1 --port 8080--jinja usa il chat template del modello ed è abilitato per impostazione predefinita nelle build correnti. --reasoning-effort accetta default, minimal, low, medium, high, xhigh o max; default indica di lasciare invariata l'impostazione predefinita del template. Questo elenco appartiene al vocabolario di llama.cpp, non a quello del modello. Passare quindi soltanto un nome riportato nella scheda del modello: un livello non definito dal template può causare un errore del template al momento della richiesta. --reasoning-format deepseek sposta il ragionamento da message.content a message.reasoning_content. Questo consente di misurare la separazione nella sezione successiva.
Per disattivare il ragionamento, invece di limitarne la durata, impostare direttamente la variabile del template:
llama-server -m ./qwen3.8-27b-Q4_K_M.gguf --jinja \
--chat-template-kwargs '{"enable_thinking": false}'--reasoning-budget è un meccanismo diverso. Imposta un limite, in token, per il segmento di ragionamento: 0 lo interrompe immediatamente, mentre -1 lo lascia senza limiti. Non chiede al modello di pianificare un segmento più breve. Entrambi i flag si applicano all'intero server. llama-server non accetta reasoning_effort come campo per singola richiesta. Per offrire contemporaneamente due livelli di ragionamento servono quindi due processi su due porte.
vLLM espone la stessa variabile per singola richiesta, all'interno del body compatibile con OpenAI:
{"model": "Qwen/Qwen3.8-27B",
"messages": [{"role": "user", "content": "Summarise this changelog in two lines."}],
"chat_template_kwargs": {"reasoning_effort": "medium"}}Come impostare il livello in Ollama
Ollama dispone di un campo dedicato, think, su /api/chat e /api/generate. Accetta true, false oppure uno tra low, medium, high e max; max richiede il livello massimo offerto dal modello. Per i modelli che lo supportano, il ragionamento è attivo per impostazione predefinita.
ollama run qwen3.8:27b --think=low "Draft a one line commit message for a README typo fix"{"model": "qwen3.8:27b",
"messages": [{"role": "user", "content": "Which HTTP status code means the request body was too large?"}],
"think": "low",
"stream": false}Il ragionamento viene restituito in message.thinking e la risposta in message.content, già separati. In una sessione interattiva ollama run, /set think e /set nothink consentono di attivarlo o disattivarlo senza riavviare.
Ora si nota la discrepanza. Il vocabolario di Ollama comprende low, medium, high e max. Il template di Qwen3.8 definisce low, medium e xhigh. È quindi necessario mappare un insieme sull’altro. Inoltre, un modello Ollama contiene un template incluso nel proprio tag, invece del file Jinja del repository originale. Di conseguenza, il livello raggiunge effettivamente il modello solo se il template incluso lo gestisce. Non bisogna darlo per scontato. La verifica richiede circa un minuto.
Come verificare se il livello è stato effettivamente applicato
Invia lo stesso prompt a più livelli con temperature impostato su 0, quindi confronta il numero di token. In questo caso jq costruisce il corpo della richiesta, così non devi fare manualmente l’escape delle virgolette.
for level in low medium max; do
body=$(jq -n --arg lvl "$level" '{
model: "qwen3.8:27b",
messages: [{role: "user", content: "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take? Answer in minutes."}],
think: $lvl,
stream: false,
options: {temperature: 0, num_ctx: 8192}
}')
echo "== $level"
curl -s http://localhost:11434/api/chat -d "$body" | jq '{
thinking_chars: (.message.thinking // "" | length),
answer_chars: (.message.content | length),
eval_count: .eval_count,
seconds: (.total_duration / 1e9),
tok_per_sec: (.eval_count / (.eval_duration / 1e9))
}'
doneeval_count rappresenta tutti i token generati, incluso il ragionamento, quindi la differenza tra due livelli corrisponde quasi interamente al ragionamento. thinking_chars fornisce direttamente la suddivisione. Devono verificarsi due condizioni: i valori devono cambiare tra i livelli e la risposta deve restare corretta anche al livello inferiore. Se eval_count rimane entro la variabilità normale in tutte e tre le esecuzioni, il livello viene ignorato. In questo caso devi usare un runtime che lo trasmetta, non un nome di livello diverso.
Il tempo totale rappresenta solo metà del problema. Misura quindi l’intervallo fino al primo token della risposta eseguendo lo streaming e interrompendo l’elaborazione al primo blocco content non vuoto. Per questo servono jq e bc.
start=$(date +%s.%N)
curl -sN http://localhost:11434/api/chat -d '{
"model": "qwen3.8:27b",
"messages": [{"role": "user", "content": "Explain what a reverse proxy does, in three sentences."}],
"think": "low",
"stream": true
}' |
while IFS= read -r line; do
if [ -n "$(printf '%s' "$line" | jq -r '.message.content // ""')" ]; then
echo "first answer token after $(echo "$(date +%s.%N) - $start" | bc)s"
break
fi
doneEsegui il test con low e poi con max. La differenza è il tempo di attesa aggiuntivo. In llama.cpp gli stessi valori vengono restituiti nella risposta, senza bisogno di eseguire calcoli aritmetici nella shell:
curl -s http://localhost:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model": "local", "temperature": 0,
"messages": [{"role": "user", "content": "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take?"}]}' | jq '{
reasoning_chars: (.choices[0].message.reasoning_content // "" | length),
answer_chars: (.choices[0].message.content | length),
predicted_n: .timings.predicted_n,
tok_per_sec: .timings.predicted_per_second
}'Esegui questa verifica sul tuo server. Un confronto pubblicato dello sforzo è stato misurato su hardware diverso dal tuo, mentre la tua velocità di decodifica è il parametro che converte il numero di token in secondi. Misurare i token al secondo sul proprio server fornisce questo parametro: i token di ragionamento divisi per la velocità di decodifica corrispondono al tempo di attesa aggiuntivo appena calcolato.
Cosa non funziona
La risposta viene troncata oppure content è vuoto mentre thinking è valorizzato. Il limite di generazione è stato consumato dal ragionamento. Il parametro num_predict di Ollama limita l’intera generazione, incluso il ragionamento, che viene eseguito per primo. Per questo, con un limite di 512 token e un livello di sforzo elevato, la risposta può terminare prima di iniziare. Ollama restituisce "done_reason": "length" per quella risposta. Aumenta il limite oppure riduci il livello di sforzo. La sezione Come num_predict conta i token descrive in dettaglio questa interazione.
Il livello non cambia nulla. Il numero di token è identico a ogni livello. Il runtime potrebbe non passare la variabile oppure il template potrebbe non leggerla. Controlla il template effettivamente utilizzato dal runtime, non quello presente nel repository originale. llama.cpp, con --jinja e --chat-template-kwargs, inserisce manualmente la variabile e costituisce quindi un buon termine di confronto. Se il livello funziona lì ma non altrove, il modello è corretto e l’altro runtime sta scartando la variabile.
Il nome di un livello viene rifiutato. Un errore del template al momento della richiesta, oppure un errore al primo messaggio con un server altrimenti funzionante, indica in genere che hai passato un livello non definito dal template. Ad esempio, potresti aver passato high a un modello la cui scheda elenca solo i livelli low, medium e xhigh.
Le chat con più turni diventano più lente a ogni turno. Il ragionamento precedente viene mantenuto nella cronologia. Imposta preserve_thinking su false se il modello lo supporta oppure rimuovi il campo thinking dai messaggi che invii nuovamente. In caso contrario, l’elaborazione del prompt aumenta a ogni turno, mentre la lunghezza delle risposte rimane invariata.
La qualità peggiora con un livello di sforzo basso durante un’attività che ritenevi semplice. Alcune operazioni di estrazione non sono vere estrazioni. Se l’input richiede una conversione di unità o l’applicazione ordinata di una regola, si tratta di un’attività di ragionamento con un output breve. Aumenta il livello per quella singola richiesta, invece di modificarlo per l’intero server.
Eseguire contemporaneamente due livelli
llama.cpp fissa il livello all'avvio, quindi un server che gestisce sia un editor sia un job batch notturno richiede due processi su due porte, ciascuno con il proprio --reasoning-effort. Due processi comportano anche due copie dei pesi in memoria, a meno di separare i job nel tempo. Su un VPS, la configurazione più economica consiste generalmente nell'usare un server a basso livello di sforzo per le attività per cui una persona è in attesa, e un'esecuzione pianificata a livello più elevato per le attività che nessuno sta osservando. Cosa succede quando più utenti condividono un modello locale si applica anche in questo caso: i token di ragionamento sono lavoro di decodifica, quindi aumentare il livello di sforzo riduce la concorrenza effettiva all'incirca dello stesso fattore con cui aumenta il numero di token.
FAQ
Quale livello di ragionamento devo usare per impostazione predefinita?
Inizia dal livello più basso offerto dal modello e aumentalo solo per le attività che hai verificato non funzionare. Diversi modelli con ragionamento vengono distribuiti con un livello predefinito elevato e, ad agosto 2026, Qwen3.8-27B usa xhigh come livello massimo predefinito. Questa impostazione è scelta per ottenere buoni risultati nelle tabelle dei benchmark, che non conteggiano il tempo di elaborazione. Sul tuo hardware, invece, paghi in secondi. Perciò considera il livello più alto un'opzione da attivare per singola attività, non l'impostazione ereditata da ogni richiesta.
I token di ragionamento vengono conteggiati nella finestra di contesto?
Sì. Sono token ordinari dell'output e occupano spazio nella finestra di contesto insieme a tutto il resto. La loro permanenza nel turno successivo dipende dal runtime e dal modello. La scheda di Qwen3.8 documenta preserve_thinking, attivo per impostazione predefinita. Questa opzione conserva nella cronologia il ragionamento precedente, quindi una conversazione lunga accumula ogni scratchpad prodotto dal modello. Impostala su false oppure rimuovi il campo thinking dai messaggi che riproponi. In questo modo l'elaborazione del prompt non continua a crescere.
Perché la modifica del livello di ragionamento non cambia il conteggio dei token?
L'impostazione non raggiunge il chat template. Il livello è una variabile del template, quindi funziona soltanto se il runtime la trasmette e il template incluso nel pacchetto la legge. Alcuni runtime distribuiscono un proprio template insieme al modello invece del file Jinja del repository originale. In questo caso la variabile viene scartata senza visualizzare alcun errore. Verificalo inviando lo stesso prompt al livello più basso e a quello più alto, con temperature impostato su 0, quindi confronta eval_count. Se i conteggi coincidono entro il margine di variazione, il livello viene ignorato.
Un livello di ragionamento più basso rende il modello meno accurato?
Dipende dall'attività. È meglio misurare l'effetto invece di dare per scontato che esista. Quando la risposta è già presente nell'input, ad esempio nelle attività di estrazione o riscrittura, uno scratchpad più breve di solito non cambia il risultato. Quando un passaggio intermedio deve essere corretto prima di poter produrre quello finale, ad esempio nell'aritmetica a più passaggi o nel codice che deve compilare, l'accuratezza diminuisce con uno scratchpad più breve. Prepara una serie di venti prompt tratti dal tuo carico di lavoro reale, eseguili a due livelli con temperature impostato su 0 e conta le risposte errate. Questo numero è specifico del tuo carico di lavoro e nessuna tabella pubblicata può fornirlo al posto tuo.