DEV Community

frontendfacile.it
frontendfacile.it

Posted on Originally published at frontendfacile.it

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.

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:

  1. scegli un modello compatto e open-weights
  2. costruisci dataset misti e ben normalizzati
  3. allena sul pattern case + question + options → single-token answer
  4. servi con un runtime serio (vLLM)
  5. 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.


Articolo originale: https://frontendfacile.it/blog/un-jev-personale-con-5-fine-tuning-di-un-llm-per-fare-classificazione-in-meno-di

Top comments (0)