26 settembre 2026
Un “Jev” personale con 5$: fine-tuning di un LLM per fare classificazione in meno di un secondo
Come trasformare un modello generalista (Qwen 3.5 4B) in un classificatore ultra-rapido: dataset, formato prompt, LoRA, serving con vLLM e scelte hardware sensate.
Creare un modello che prenda un contesto, una domanda e una lista di opzioni e restituisca una singola scelta in tempi sub-secondo non è fantascienza, né richiede budget importanti. Con un fine-tuning mirato di Qwen 3.5 (4B) e una pipeline pragmatica (LoRA + vLLM) si ottiene un classificatore solido, economico e abbastanza veloce da stare dietro a casi d’uso real-time. In questo articolo vediamo l’impostazione: quali dataset usare, come formattare gli esempi, come organizzare training/val/test, cosa aspettarsi in termini di latenza e perché una GPU “più grossa” non è sempre la scelta migliore.
Perché costruire un “Jev”: decisioni veloci, output controllato
Molti flussi frontend e di prodotto hanno bisogno di decisioni classificatorie immediate:
- instradare un ticket all’helpdesk corretto
- scegliere la “intent” di un messaggio utente
- validare se un testo soddisfa una policy
- fare true/false su affermazioni (NLI, BoolQ-like)
In questi casi non serve un modello che scriva paragrafi: serve un componente che, dato contesto + domanda + opzioni, restituisca una scelta in modo ripetibile.
L’idea è semplice: prendere un LLM compatto e open-weights (qui: Qwen 3.5 da 4B parametri) e addestrarlo a comportarsi come un classificatore. Il risultato pratico è un endpoint che risponde tipicamente in centinaia di millisecondi quando “caldo”, con costi di training sorprendentemente bassi.
Scelta del modello base: perché Qwen 3.5 4B
Un 4B è un buon punto di equilibrio per:
- costi e tempi di training gestibili
- dimensioni degli artifact contenute (pochi GB)
- latenza migliore rispetto a modelli molto più grandi
- licenza e pesi aperti, quindi deploy e sperimentazione più semplici
Per un classificatore in produzione, spesso conta più la latenza/throughput e la prevedibilità dell’output che la “creatività”. Un modello compatto è una scelta strategica.
Dataset: cosa serve davvero per insegnare “decisioni”
Per ottenere un comportamento affidabile, conviene mescolare dataset “classici” e dataset sintetici orientati a policy/routing. Un set ragionevole può includere:
- MultiNLI: entailment / contradiction / neutral
- BoolQ: domande sì/no
- Banking77: intent classification in ambito supporto (77 classi)
- Dataset sintetici per policy, routing, decision making
- Classificazione di testi tecnici (es. paper) per “tipo di contributo”
Split e volumi (ordine di grandezza)
Una configurazione efficace è:
- ~38.000 esempi per training (≈ 17M token)
- ~5.000 esempi per validation/dev (≈ 2M token)
- ~4.000 esempi per test hold-out (solo per valutazione finale)
Il test “non toccato” è fondamentale: quando il task è decisionale, basta poco overfitting sul formato per avere numeri belli ma inutili.
Il formato che fa la differenza: contesto + domanda + opzioni → una lettera
Per trasformare un LLM in classificatore, il punto chiave è il formato degli esempi.
Invece di chiedere al modello di “spiegare”, lo si allena a:
- leggere una situazione (case)
- leggere una domanda
- leggere un elenco di opzioni
- restituire una sola scelta, idealmente un token minimo (es. una lettera: A/B/C/D)
Esempio concettuale:
- Case: “Ho inserito la carta nel bancomat e l’ATM l’ha trattenuta…”
- Channel: “mobile support”
- Question: “Cosa sta chiedendo il cliente?”
- Options: A) commissioni prelievo B) recupero carta ATM C) …
- Answer:
B
Questo approccio riduce:
- ambiguità dell’output
- lunghezza della generazione
- variabilità di stile
E “null” o “score”?
È possibile estendere il formato per supportare:
- risposta null (nessuna opzione valida)
- valutazione o score
Ma non è magia: se non hai esempi con quei valori nel training set, non aspettarti che il modello li produca in modo affidabile. Qui la regola è sempre la stessa: è una questione di dati + formato.
Training: LoRA + stack snello
Per contenere tempi e costi, la strada più pratica è:
- fine-tuning con LoRA
- librerie ottimizzate per training di LLM (es. Unsloth con Transformers/Datasets)
- esecuzione su container CUDA con Python moderno
Smoke test prima del training completo
Un passaggio spesso sottovalutato: prima del training “vero”, conviene fare un smoke test su un sottoinsieme minuscolo.
Obiettivi:
- validare che i dati siano normalizzati correttamente
- verificare che il loss scenda (anche solo un po’)
- controllare che i checkpoint vengano scritti e ricaricati
Quando tutto fila, si lancia il training completo.
Tempi e costi (ordine di grandezza)
Su una GPU di fascia data-center “media” (es. L40S), un training completo può stare nell’ordine di ~2 ore. In uno scenario simile il costo del solo training può aggirarsi intorno ai 4–5$.
Non è “gratis”, ma è abbastanza economico da rendere iterativo il lavoro sul dataset: ed è qui che si vince davvero.
Serving: vLLM e la battaglia vera è la latenza
Il training accade una volta; il serving è ciò che paghi e misuri ogni giorno.
Per l’inferenza, una scelta pragmatica è vLLM:
- ottimizzato per serving
- open source
- buona ergonomia per endpoint stile Chat Completions via HTTP
Warm vs cold: il problema reale in produzione
Se spegni la GPU quando non ci sono richieste, risparmi — ma paghi in cold start:
- caricamento runtime
- allocazione GPU
- caricamento pesi modello
Risultato: la prima request può richiedere minuti. In produzione, per casi real-time, spesso conviene tenere istanze “calde” o usare strategie di pre-warming e autoscaling più intelligenti.
L40S vs H100: più grande non significa più veloce
Un dato interessante quando il modello è piccolo (4B): una GPU enorme come H100 non garantisce automaticamente latenza migliore rispetto a una L40S. In alcuni test pratici, L40S può risultare:
- più conveniente
- con cold start più rapido
- con latenza warm comparabile o persino migliore
Morale: dimensiona l’hardware sul carico e sulla taglia del modello, non sul prestigio della GPU.
Metriche: cosa aspettarsi
In un setup simile, un risultato ragionevole può essere:
- accuratezza complessiva ~88% su test non visto (dipende tantissimo dai task inclusi)
- latenza “warm” spesso < 1s per decisione (con variazioni dovute a caching e carico)
Per un classificatore decisionale, oltre all’accuracy guarderei sempre:
- confusion matrix per classi (Banking77 è spietato)
- robustezza a opzioni rimescolate
- stabilità dell’output (sempre una lettera, mai testo extra)
LLM fine-tuned vs classificatore “puro”: come decidere
Ha senso usare un LLM fine-tuned come classificatore quando ti serve:
- flessibilità (stesso modello per più compiti)
- contesto lungo (Qwen può arrivare a contesti molto ampi)
- capacità di spiegare la scelta (se ti serve davvero)
Un classificatore puro (architetture dedicate) vince quando vuoi:
- latenza ultra-bassa e costante
- output probabilistici affidabili (confidence calibrata)
- pipeline rigidissima e deterministica
In pratica, una regola utile:
- Se ti serve interpretazione, flessibilità o contesto lungo → LLM fine-tuned.
- Se ti serve decisione real-time con output minimale → modello decisionale/classificatore.
Sintesi: il valore sta nel formato e nel serving
Creare un “Jev” personale non è tanto un esercizio di potenza di calcolo, quanto di ingegneria del formato e di deploy:
- scegli un modello compatto e open-weights
- costruisci dataset misti e ben normalizzati
- allena sul pattern case + question + options → single-token answer
- servi con un runtime serio (vLLM)
- misura cold start, latenza warm e costo orario GPU
Il risultato è un componente che può rendere più reattive molte esperienze frontend (routing, form assistant, ticket triage) senza trasformare ogni decisione in una generazione lunga e costosa. La parte “magica” non è l’LLM: è la disciplina nel definire input/output e nel progettare la latenza come requisito di prodotto.