Constrained Decoding
La decodifica vincolata esclude i token non validi a ogni passaggio di generazione, così un LLM può produrre solo etichette consentite, corrispondenze di espressioni regolari o JSON conforme allo schema.
La decodifica vincolata è una tecnica di generazione del testo che limita i token che un modello linguistico può produrre a ogni passaggio, garantendo che l'output finale corrisponda a un formato richiesto: una delle etichette di un insieme fisso, un'espressione regolare, una grammatica o uno schema JSON. Il modello continua ad assegnare un punteggio a ogni token del proprio vocabolario. Prima di scegliere un token, il decodificatore rimuove tutte le opzioni che violerebbero il formato. Le applicazioni che analizzano l'output del modello, come i backend API, gli agenti AI e le pipeline di estrazione dei dati, la usano per fare in modo che ogni risposta venga analizzata correttamente al primo tentativo.
Mascherare i token non validi#
Un modello linguistico di grandi dimensioni genera il testo un token alla volta. A ogni passaggio produce un punteggio, o logit, per ciascun token del proprio vocabolario e una funzione softmax trasforma quei punteggi in probabilità. La decodifica vincolata aggiunge un'operazione prima del campionamento: ai token che non possono portare a un output valido viene assegnato un logit pari a meno infinito, che assegna loro probabilità zero, e la probabilità rimanente viene rinormalizzata sui token validi.
import torch
# Raw next-token scores from a model over a toy vocabulary
vocab = ["approved", "rejected", "review", "maybe", "{", "}"]
logits = torch.tensor([1.2, 0.4, 0.9, 2.5, 0.1, 0.3])
# The schema allows only the three status labels at this position
allowed = torch.tensor([True, True, True, False, False, False])
masked_logits = logits.masked_fill(~allowed, float("-inf"))
# Softmax renormalizes probability over the valid tokens only
for name, raw, masked in zip(vocab, logits.softmax(-1), masked_logits.softmax(-1)):
print(f"{name:>9}: {raw:.2f} -> {masked:.2f}")Il modello senza vincoli assegna il 56% della propria probabilità a "maybe". Con la maschera applicata, "maybe" scende a zero e le tre etichette consentite si dividono la probabilità in proporzione ai punteggi originali, così "approved" sale dal 15% al 46%.
I motori di inferenza di produzione tengono traccia dello stato dei vincoli durante la generazione. Un elenco fisso di opzioni o un'espressione regolare viene compilato in una macchina a stati finiti. JSON e altri formati annidati richiedono una grammatica con uno stack, perché una parentesi graffa di chiusura è valida solo dopo la corrispondente parentesi graffa di apertura. Dopo ogni token, il decodificatore fa avanzare lo stato e ricalcola l'insieme di token consentiti. La tokenizzazione produce parti di parole di lunghezza variabile, quindi un singolo token come "}, può coprire più passaggi della grammatica. Per questo le librerie precalcolano quali voci del vocabolario sono legali in ciascuno stato, mantenendo basso il costo per token anche con vocabolari di oltre 100.000 token. Nel 2023 Brandon Willard e Rémi Louf hanno descritto questa indicizzazione per le espressioni regolari e le grammatiche libere dal contesto in Efficient Guided Generation for Large Language Models, il documento alla base della libreria Outlines.
Scegliere un vincolo#
Il vincolo giusto corrisponde all'output che l'applicazione utilizza davvero. Un elenco di opzioni è adatto alla classificazione e all'instradamento, dove la risposta deve essere una tra poche stringhe. Le espressioni regolari gestiscono valori strutturati brevi come date, ID e numeri di telefono. Le grammatiche libere dal contesto descrivono SQL, codice e linguaggi specifici di dominio; il formato grammaticale GBNF di llama.cpp è un esempio molto diffuso. Per i record con campi denominati, lo schema JSON specifica chiavi obbligatorie, tipi, enumerazioni e annidamenti. Le API ospitate come OpenAI Structured Outputs accettano uno schema e lo fanno rispettare durante la generazione, solitamente supportando un sottoinsieme documentato delle specifiche complete dello schema JSON.
La decodifica vincolata viene spesso confusa con tecniche affini:
- Output strutturati: l'obiettivo più ampio di ottenere risposte leggibili dalle macchine, raggiunto tramite decodifica vincolata durante la generazione oppure convalidando l'output in seguito e riprovando in caso di errore.
- Modalità JSON: vincola l'output a un JSON sintatticamente valido di qualsiasi forma, ma è comunque necessario verificare chiavi, tipi e valori.
- Prompt engineering: richiede un formato nelle istruzioni, che i modelli seguono nella maggior parte dei casi. Anche le richieste vincolate da uno schema di solito descrivono i campi nel prompt, così il modello sa cosa significa ciascuno.
- Chiamata di funzioni: nomi e argomenti degli strumenti sono tra gli obiettivi più comuni dei vincoli basati su schemi, perché il codice chiamante si aspetta nomi di campo esatti.
Compromessi nella pratica#
Un formato garantito non garantisce nulla sul contenuto. Uno schema può imporre che {"total": 1290.00} sia un numero, ma il numero può comunque essere sbagliato; inoltre, un modello vincolato può allucinare con disinvoltura all'interno di campi validi. Le applicazioni devono comunque convalidare le regole di business dopo la generazione.
I vincoli possono anche peggiorare la qualità delle risposte quando allontanano il modello dal testo che scriverebbe spontaneamente. Uno schema che impone di presentare la risposta finale come primo campo non lascia spazio al ragionamento intermedio, quindi spesso gli schemi collocano un campo di ragionamento o note in testo libero prima del campo della risposta. Anche la lunghezza dell'output richiede attenzione: se la generazione raggiunge il limite di token a metà di un oggetto, il risultato non è valido a prescindere dal vincolo; per questo le richieste strutturate impostano lunghezze massime con un margine sufficiente a contenere l'intera struttura. Schemi molto grandi o profondamente ricorsivi richiedono più tempo per essere compilati, un aspetto importante per i sistemi che creano un nuovo schema per ogni richiesta.
Le applicazioni di visione usano lo stesso meccanismo quando un modello multimodale deve restituire campi relativi a un'immagine. L'interfaccia LLM di Ultralytics inoltra senza modifiche gli argomenti delle richieste alle API compatibili con OpenAI, quindi uno schema JSON passato insieme a una richiesta con immagine limita la risposta di un modello visione-linguaggio a campi come hazard e severity, pronti per essere combinati con le rilevazioni di YOLO26 dello stesso fotogramma.










