Di recente, l'industria AI è stata sorpresa dal rilascio di Jev da parte di TypeSafe AI, un modello chiamato decisionale, cioè in grado di prendere decisioni dato un input non strutturato e forzando una struttura in output con una decisione e la sua probabilità.

TypeSafe AI inserisce Jev nel contesto del System One, facendo riferimento ai lavori dello psicologo ed economista Daniel Kahneman e pubblicati nel suo iconico scritto Thinking Fast and Slow.

Secondo Kahneman, Il system one è quel pattern di pensiero rapido, automatico e intuitivo, e opera con uno sforzo minimo o nullo. Questa modalità di pensiero ci consente di prendere decisioni e formulare giudizi in modo veloce, basandoci su schemi ed esperienze.

Al contrario, il system two è lento, deliberato e consapevole, e richiede uno sforzo intenzionale. Questo tipo di pensiero viene impiegato per la risoluzione di problemi complessi e per attività analitiche che richiedono maggiore riflessione e ponderazione.

The automatic operations of System 1 generate surprisingly complex patterns of ideas, but only the slower System 2 can construct thoughts in an orderly series of steps.

Daniel Kahneman in Thinking, Fast and Slow

Jev quindi è addestrato per prendere decisioni velocemente, senza riflessione profonda interna.

Insieme a Jev sono stati di recente pubblicati altri modelli simili, sia open che closed source. Ne vedremo alcuni in questo articolo.

🎙️
Riassumendo, leggendo questo articolo imparerai

- Cosa è un modello decisionale e perché sono così importanti
- Metodologie di addestramento ed approcci open source
- Applicazioni pratiche di un modello decisionale vs LLM conversazionale

Cosa è un modello decisionale?

Un modello decisionale è un modello di IA generativa specializzato che non genera testo libero, ma invece riceve uno “stato” (testo, JSON o, in alcuni casi, immagini) più una o più domande con risposte predefinite, e restituisce output strutturato con probabilità/confidenza:

  • Scelta (choice): seleziona una tra le opzioni date dallo sviluppatore e assegna probabilità a ciascuna.
  • Sì/no (noul o predicate): restituisce la probabilità che una condizione sia vera.
  • Punteggio (score): valuta su una scala ordinata con media pesata.

Tutto avviene in un unico passaggio (non autoregressivo come gli LLM), senza possibilità di rompere lo schema di output.

Ma perché il suo rilascio ha suscitato così tanto interesse nello spazio AI?

Prima di Jev, ci sono stati tentativi, anche molto interessanti e sicuramente a grande impatto pratico, di raggiungere l'obiettivo che Jev raggiunge attraverso modelli come GliNER.

GLiNER ha dimostrato che non serve un LLM generativo da miliardi di parametri per estrarre entità arbitrarie da un testo. Basta un encoder bidirezionale compatto che riceve in input le etichette desiderate insieme al testo e valuta quali porzioni corrispondono a quali etichette. Niente generazione token per token, niente parsing di output fragili: il modello restituisce direttamente span e punteggi, gira comodamente anche su CPU e si adatta a nuove etichette senza riaddestramento.

Sulla stessa scia sono nati modelli dedicati alla classificazione zero-shot, che applicano lo stesso principio alla scelta tra categorie definite al momento dell’inferenza.

L’alternativa più diffusa resta però affidarsi a un LLM generativo. Si scrive un prompt che elenca le opzioni, si chiede al modello di rispondere con una sola etichetta e, nei casi più sofisticati, si leggono i logprobs dei token di risposta per ricavarne una sorta di confidenza. Funziona, ma con diversi compromessi.

  • La probabilità si disperde su token che non sono opzioni valide
  • Le etichette composte da più token complicano il calcolo
  • Molte API espongono solo i token più probabili, o non espongono affatto i logprobs.
  • Soprattutto, le probabilità di un modello addestrato a conversare raramente sono ben calibrate (cioè quando un modello addestrato a conversare tende a essere sicuro di sé anche quando sbaglia).

A questo si aggiungono latenza e costi pensati per generare testo, non per scegliere tra tre alternative.

Un modello decisionale come Jev o GliNER Decide, la nuova iterazione dello stesso modello da parte di Fastino Labs, si colloca esattamente in questo spazio. Lo spazio decisionale viene dichiarato nella richiesta come uno schema tipizzato, e il modello restituisce una distribuzione di probabilità su quelle sole opzioni, per costruzione e non per convenzione del prompt.

0:00
/0:14

Video preso da TypeSafe.ai (https://typesafe.ai/blog/introducing-system-one-models-and-jev)

Più domande sullo stesso stato possono essere valutate in un unico passaggio, e le probabilità sono pensate per essere usate direttamente come soglie nel codice. È questo il cambio di prospettiva che ha attirato l’attenzione: il modello che scrive la risposta finale non è più quello che decide cosa deve succedere dopo (cioè al prossimo token, perché non è suo scopo generare conversazione!)

Ecco un esempio di input e output verso Jev.

{
  "model": "jev-latest",
  "state": "Customer: I was charged twice and nobody has replied for 3 days. I'm furious and thinking of cancelling.",
  "questions": {
    "route": {
      "type": "choice",
      "instructions": "Where should this ticket go?",
      "criteria": {
        "billing": "money, charges, refunds, invoices",
        "bug": "the product is broken",
        "account": "login or access problems"
      }
    },
    "urgency": {
      "type": "score",
      "instructions": "How urgent is this?",
      "criteria": ["routine", "today", "urgent", "critical"]
    },
    "escalate": {
      "type": "noul",
      "instructions": "Escalate to a human immediately?"
    }
  }
}

Output:

{
  "model": "jev-1.13.0",
  "answers": {
    "route": {
      "type": "choice",
      "choice": "billing",
      "confidence": 0.99,
      "probabilities": {
        "billing": 0.99,
        "bug": 0.0,
        "account": 0.01
      }
    },
    "urgency": {
      "type": "score",
      "score": 3.0,
      "confidence": 1.0,
      "legend": {
        "0": "routine",
        "1": "today",
        "2": "urgent",
        "3": "critical"
      },
      "probabilities": {
        "0": 0.0,
        "3": 1.0
      }
    },
    "escalate": {
      "type": "noul",
      "noul": 0.94
    }
  },
  "usage": {
    "input_tokens": 62,
    "output_tokens": 0
  }
}

Ecco cosa significano i campi:

Campo Significato
choice L’opzione vincente (la chiave che hai definito tu)
probabilities Distribuzione di probabilità su tutte le opzioni
confidence Quanto il modello è sicuro della sua scelta (utile per soglie)
score Punteggio ponderato (può essere frazionario, es. 2.3)
noul Probabilità (0–1) che la condizione sia vera
legend Mappa indice → etichetta per i score

(per il caso specifico di Jev, qui la documentazione di esempio).

Quick start - TypeSafe AI
Prefer to just dive in? Here’s everything you need to get started immediately.

Come viene addestrato un modello decisionale?

Le recenti pubblicazioni hanno evidenziato che questi modelli nascono tipicamente da un modello pre-addestrato (un LLM decoder o un encoder bidirezionale) e viene specializzato per un obiettivo diverso: restituire decisioni tipizzate e probabilità calibrate, non testo libero.

L’obiettivo: calibrazione e output tipizzato

La differenza fondamentale rispetto agli LLM conversazionali sta nel segnale di training e nel contratto di output.

  • RLHF (reinforcement learning from human feedback) ottimizza per preferenze umane → risposte fluide ma spesso overconfident.
  • RLVR (reinforcement learning with verifiable rewards) ottimizza per correttezza verificabile → buono per ragionamento, ma lento.
  • RLCD (reinforcement learning for calibrated decisions, introdotto da TypeSafe per Jev) ottimizza per probabilità epistemicamente oneste: quando il modello dice 0.8, in media quella risposta dovrebbe essere corretta circa l’80% delle volte.

TypeSafe ha dichiarato di aver addestrato Jev su dati sintetici. L’obiettivo è che le probabilità siano utilizzabili direttamente come soglie nel codice.

Due famiglie principali di approccio

  1. Decision head su base generativa

    Si parte da un LLM e si disabilita o si rimuove la testa di generazione linguistica e si aggiunge una decision head (pointer/scoring head). La testa valuta in parallelo le opzioni dello schema e produce una distribuzione di probabilità. Si fine-tuna con LoRA/QLoRA su esempi di decisioni etichettate, usando loss come cross-entropy.
  2. Encoder specializzati (linea GLiNER)

    Qui si parte da architetture encoder compatte e non generative, ispirate a GLiNER. Il modello processa insieme testo e schema delle domande, produce punteggi di compatibilità per ogni opzione ammessa, e un decoder vincolato cerca l’assegnazione congiunta più alta che rispetti eventuali regole tra domande.

GLiNER2.5-Decide, ad esempio, è un encoder post-trained specificamente per decision-making strutturato. Supporta fine-tuning completo o LoRA, gira su CPU, e oltre alle decisioni tipizzate può estrarre span, relazioni e applicare vincoli tra output (es. “se rilevi harm, allora safety deve essere unsafe”).

fastino/GLiNER2.5-Decide · Hugging Face
We’re on a journey to advance and democratize artificial intelligence through open source and open science.

Su un benchmark interno di 17 dataset di classificazione/routing/triage ottiene risultati competitivi (o superiori) rispetto a baseline più grandi basate su decoder da 4B.

Questa seconda famiglia dimostra che non serve sempre un backbone generativo da miliardi di parametri: un encoder specializzato, addestrato o fine-tunato su task di decisione schema-driven, può essere più efficiente e preciso su task bounded.

Schema tipico di training

  1. Base pre-addestrata: LLM decoder o encoder (GLiNER-style, ModernBERT, ecc.).
  2. Modifica dell’output: rimozione/disabilitazione della testa generativa + aggiunta di una decision head (o decoder vincolato).
  3. Dati: esempi di (state + schema di domande + risposte corrette). Spesso sintetici o etichettati su task di routing, classificazione, scoring.
  4. Loss: cross-entropy (o label-smoothed) sulle opzioni corrette + componenti di calibrazione (Brier, proper scoring rules). In alcuni casi un secondo stadio RL orientato alla calibrazione.
  5. Fine-tuning: LoRA/QLoRA sul backbone + training della testa, oppure full fine-tuning su modelli piccoli. Temperature scaling post-hoc per migliorare ulteriormente la calibrazione.
  6. Valutazione: accuratezza su label + metriche di calibrazione (expected calibration error) su set held-out.

Ad esempio, una riga di dataset usato per il training di un modello decisionale può essere simile a questa:

Parte Contenuto Usato come
Input state + questions Quello che il modello vede
Label (gold) gold Il target su cui si calcola la loss

Input:

{
  "state": "Hi, I was charged twice for invoice #4411. Please refund the duplicate today.",
  "questions": {
    "team": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": {
        "billing": "invoices, payments, refunds",
        "technical": "bugs, outages, errors",
        "sales": "pricing, new plans"
      }
    },
    "refund": {
      "type": "noul",
      "instructions": "Does the customer ask for a refund?"
    },
    "urgency": {
      "type": "score",
      "instructions": "How urgent is this?",
      "criteria": ["not urgent", "soon", "today"]
    }
  },
  "gold": {
    "team": {"choice": "billing"},
    "refund": {"noul": 0.98},
    "urgency": {"score": 2}
  }
}

Output:

{
  "team": {"choice": "billing"},
  "refund": {"noul": 0.98},
  "urgency": {"score": 2}
}

Cosa cambia rispetto a un classificatore classico

A differenza di un classificatore tradizionale che va riaddestrato da zero per ogni set di etichette, un decision model eredita la comprensione del linguaggio della base.

Le etichette (criteria) vengono fornite a runtime. Questo consente adattamento a nuovi schemi senza riaddestramento completo, a patto che le descrizioni delle opzioni siano chiare. Modelli come GLiNER2.5-Decide estendono ulteriormente questa idea supportando vincoli inter-domanda e multi-task (decisioni + estrazione).

💡
Quali sono i vantaggi di un modello decisionale rispetto ad un LLM conversazionale?

- Output tipizzato e deterministico: non serve parsare JSON o gestire allucinazioni sul formato.

- Velocità: un forward pass invece di una generazione token-by-token.

- Costo e latenza bassi: modelli piccoli (300–500M) che girano anche su CPU.

- Probabilità utilizzabili: si può decidere in codice se fidarsi o escalare.

- Schema flessibile a runtime: le opzioni si definiscono nella chiamata, senza riaddestrare.

Applicazioni pratiche di un modello decisionale

Si capisce che un modello decisionale diventa molto utile quando il software deve prendere decisioni strutturate e deterministiche velocemente senza dover generare testo libero.

Un tipico scenario in cui questo diventa evidente è il routing e il triage automatico di richieste (ticket di supporto, email, messaggi utente). Qui non serve una risposta articolata: serve capire dove mandare la richiesta e con quale priorità, in pochi millisecondi e in modo affidabile.

Immagina un sistema di customer support che riceve messaggi liberi. Prima di assegnare il ticket a un team o a un agente, il sistema deve rispondere a tre domande:

  1. Di che tipo di richiesta si tratta? (billing, technical, account…)
  2. Quanto è urgente?
  3. Va escalata immediatamente a un umano?

Un LLM potrebbe farlo, ma:

  • impiega più tempo,
  • può generare testo inutile o malformato,
  • costa di più a volume,
  • richiede comunque del codice per estrarre la decisione.

Un modello decisionale risolve esattamente questo problema: riceve il messaggio e restituisce direttamente le tre decisioni tipizzate.

Vediamo come implementarlo in Python con GliNER Decide, che è open source.

from gliner2 import AutoExtractor

# Caricamento del modello (una volta sola)
model = AutoExtractor.from_pretrained("fastino/GLiNER2.5-Decide")

def route_ticket(message: str) -> dict:
    """
    Prende un messaggio di un cliente e restituisce
    intent, urgenza e se serve escalation umana.
    """
    result = model.classify_text(
        message,
        {
            "intent": [
                "billing",
                "technical",
                "account",
                "shipping",
                "general"
            ],
            "urgency": ["low", "medium", "high", "critical"],
            "escalate": ["yes", "no"]
        }
    )
    return result


# Esempio
message = (
    "Hi, I was charged twice for invoice #4411. "
    "Please refund the duplicate today, this is urgent."
)

decision = route_ticket(message)
print(decision)


>>> {'intent': 'billing', 'urgency': 'critical', 'escalate': 'yes'}

In pratica, possiamo creare delle funzioni per l'assegnazione ai vari team dedicati:

decision = route_ticket(message)

# Routing automatico
if decision["intent"] == "billing":
    assign_to_team("billing")
elif decision["intent"] == "technical":
    assign_to_team("engineering")

# Escalation basata sulla decisione
if decision["escalate"] == "yes" or decision["urgency"] == "critical":
    escalate_to_human()
else:
    try_auto_resolve()

Le performance paragonate ad un LLM:

Aspetto Decision model (GLiNER2.5-Decide) LLM generativo
Tempo di risposta ~50–200 ms 1–5+ secondi
Formato output Tipizzato, sempre valido Testo da parsare
Affidabilità schema Garantita Può allucinare
Costo a volume Molto basso (locale) Alto
Facilità di integrazione Diretta nel codice Serve post-processing

Un altro scenario pratico può essere la classificazione di documenti

text = "INVOICE 1842\nBill to: Northstar QA\nAmount due: 2,400 USD\nDue: 30 April 2026"

decision = model.classify_text(
    text,
    {"document_type": ["invoice", "receipt", "contract", "resume", "support_email", "meeting_notes"]}
)
print(decision)


>>> {"document_type": "invoice"}

oppure la moderazione dei contenuti

content = "Post the customer's home address in the public thread so everyone can see where the package actually went."

decision = model.classify_text(
    content,
    {"policy": ["allow", "personal_data", "harassment", "scam", "violence", "spam"]}
)
print(decision)


>>> {"policy": "personal_data"}

Conclusioni

I modelli decisionali rappresentano un cambio di paradigma rispetto agli LLM generativi. Non sono progettati per produrre testo, ma per prendere decisioni tipizzate a partire da input non strutturati, restituendo direttamente una scelta, uno score o una probabilità calibrata.

Punti chiave:

  • Restituiscono decisioni tipizzate (choice, score, probabilità) invece di testo libero.
  • Sono più veloci, economici e deterministici degli LLM su task di routing, classificazione, triage e guardrail.
  • Le probabilità calibrate permettono di decidere in codice quando fidarsi o escalare.
  • Si adattano a nuovi schemi di etichette a runtime, senza riaddestramento completo.
  • Nascono tipicamente da un backbone pre-addestrato + decision head, fine-tunata su dati sintetici.

Man mano che le pipeline AI e gli agenti diventano più comuni, la necessità di componenti specializzati per le decisioni operative è destinata a crescere. I modelli decisionali sono una risposta concreta a questa esigenza, e aprono nuove opportunità per data scientist e AI engineer per ottimizzare soluzioni principalmente basate su LLM conversazionali.