Articolo
Output strutturati: contratti, non patch ai parser
Un output strutturato non è affidabile perché in una demo assomiglia a JSON. È affidabile quando il team ha deciso cosa significa quell’output, chi lo valida, cosa succede quando è incompleto e quale decisione a valle può fidarsi del risultato.
Questa è la differenza tra una patch al parser e un contratto di output.
Molte automazioni basate su LLM partono con un prompt generoso e un parser ottimista. Il primo test funziona. Il secondo restituisce un campo mancante. Il terzo inventa una categoria che il sistema a valle non riconosce. Qualcuno aggiunge una regex. Qualcun altro aggiunge un retry. Poi un product manager chiede se l’automazione è pronta per un processo reale, e il team risponde con esempi favorevoli invece che con un contratto.
La tesi è semplice: gli output strutturati hanno bisogno di contratti, non di patch ai parser. Quando un workflow LLM entra in un processo ripetibile, lo schema di output non è un dettaglio tecnico. È l’interfaccia tra generazione probabilistica e lavoro responsabile.
Gli strumenti stanno rendendo questa astrazione più concreta. La documentazione di BAML presenta i prompt come funzioni capaci di produrre output strutturati type-safe, essere provati nell’editor e vivere in workflow più manutenibili rispetto a stringhe sparse nel codice. È un segnale importante, ma lo strumento non è il punto. Il punto è l’abitudine operativa: definire il contratto prima di irrobustire il parser.
Le patch ai parser nascondono l’ownership
Una patch al parser dà soddisfazione perché trasforma un errore visibile in una run che passa. L’automazione non si rompe più se un campo arriva come stringa invece che come enum. Fa retry quando il modello avvolge il JSON in una spiegazione. Taglia un prefisso, normalizza una data, oppure mappa un valore quasi corretto su una categoria ammessa.
Una parte di questa tolleranza serve davvero. I sistemi di produzione hanno bisogno di bordi robusti. Il problema nasce quando le patch assorbono decisioni che dovrebbero essere esplicite. Se un workflow di lead scoring riceve confidence: null, il task commerciale va creato, messo in revisione o scartato? Se un workflow di triage supporto restituisce urgency: high senza evidenza, deve avvisare una persona? Se un’estrazione da documenti restituisce un valore fuori dalle tipologie previste, il caso va corretto, rifiutato o escalato?
Queste non sono domande di parsing. Sono domande di prodotto, operations e rischio.
È lo stesso principio discusso in L’automazione AI ha bisogno di classi di errore: un retry è utile solo dopo aver capito quale tipo di errore si sta provando a recuperare. Gli output strutturati richiedono la stessa disciplina. Una nota opzionale mancante non equivale a un identificativo cliente mancante. Un enum non valido non equivale a un output formalmente valido ma privo di evidenza.
Quando l’ownership resta nascosta nel codice del parser, il workflow diventa difficile da auditare. Gli ingegneri sanno quali eccezioni vengono assorbite. Le operations sanno quali casi sembrano strani. Il prodotto conosce l’esperienza desiderata. Però nessuno condivide un artefatto unico che dica cosa l’automazione può produrre.
Cosa deve contenere un contratto di output?
Un contratto di output deve essere abbastanza piccolo da essere letto e abbastanza concreto da essere testato. Non è un documento di governance da venti pagine. È l’interfaccia concordata per un singolo output dell’automazione.
Si parte dallo schema. Ogni campo deve avere un nome, un tipo e una regola su obbligatorietà o opzionalità. Meglio evitare contenitori vaghi come metadata, a meno che il consumer a valle li tratti davvero come opachi. Se il workflow deve prendere una decisione, la decisione va modellata direttamente. Se servono prove, l’evidenza deve avere un campo proprio. Se serve esprimere incertezza, va definito come rappresentarla.
Poi bisogna definire gli stati ammessi. I campi nullable non sono un segno di debolezza se sono intenzionali. Un null può significare sconosciuto, non applicabile, non fornito o non estratto. Sono stati diversi. Se lo stesso valore vuoto può significare quattro cose, prima o poi qualcuno a valle tirerà a indovinare. Il contratto deve rendere leggibile lo stato.
Servono regole di validazione. Alcune sono sintattiche: la data deve essere in formato ISO, la categoria deve appartenere a cinque valori, l’importo deve essere numerico. Altre sono semantiche: una raccomandazione di rimborso deve citare una clausola, una classificazione ad alto rischio deve includere l’evidenza che l’ha generata, un riassunto destinato al cliente non deve contenere note interne. È nel secondo gruppo che molti workflow LLM falliscono in modo silenzioso.
Va aggiunto anche il fallback. Se la validazione fallisce, dove finisce il lavoro? Un retry con prompt più stretto? Una coda umana? Un default sicuro? Una richiesta di informazioni mancanti all’utente? Il fallback deve seguire la conseguenza di business. Un arricchimento interno fallito può essere saltato. Una classificazione di compliance fallita non dovrebbe essere indovinata.
Infine serve un owner. Non è sempre l’ingegnere che ha scritto l’integrazione. Il prodotto può possedere il significato dei campi. Le operations possono possedere la coda di revisione. Legal o security possono possedere alcuni stati bloccanti. Engineering può possedere validatore e telemetria. Il contratto deve dire chi modifica lo schema, chi approva nuovi enum e chi riceve alert quando la validazione inizia a fallire.
Quali campi meritano più attenzione?
I campi che meritano più attenzione sono quelli che attivano un’azione.
Un riassunto generato può essere imperfetto e restare utile se una persona lo legge prima di agire. Uno stato generato che chiude un ticket, manda una email al cliente, approva un rimborso, cambia uno stage nel CRM o chiama un altro tool ha un peso diverso. Il contratto deve essere più severo dove il workflow diventa meno reversibile.
Per questo progettazione dell’output e osservabilità dovrebbero stare insieme. In L’osservabilità degli agenti AI vuole contratti, il punto centrale è che le trace devono mostrare il lavoro, non solo il fatto che un modello sia stato chiamato. Il contratto di output dà a quelle trace qualcosa da ispezionare. Il modello ha fornito evidenza per la decisione? Il validatore ha respinto un campo richiesto? Il fallback è partito per errore di schema, errore di policy o bassa confidenza?
Un buon contratto separa quattro casi che spesso vengono confusi.
Primo, il modello non ha rispettato il formato. Questo è un fallimento dell’output strutturato.
Secondo, il modello ha rispettato il formato ma ha lasciato incompleto un lavoro richiesto. Questo è un fallimento di validazione.
Terzo, il modello ha prodotto un output valido che il business non si fida ancora ad automatizzare. Questa è una soglia di revisione.
Quarto, il modello ha prodotto un output valido ma il sistema a valle non lo accetta. Questo è un disallineamento tra contratti di integrazione.
Ogni caso richiede una risposta diversa. Trattarli tutti come problemi di parser produce automazioni fragili.
Dove dovrebbe fallire la validazione?
La validazione dovrebbe fallire il più vicino possibile al confine dell’output, prima che il risultato possa creare effetti operativi.
Sembra ovvio, ma molti workflow validano troppo tardi. Lasciano che l’output LLM entri in un foglio, in un sistema di ticketing, in un CRM o in una dashboard interna, e scoprono l’ambiguità solo dopo che una persona ha agito. A quel punto il costo non è solo tecnico. Diventa anche sociale: bisogna capire se l’automazione ha sbagliato, se il processo era ambiguo o se una persona ha interpretato male il risultato.
Il pattern migliore è creare un gate stretto subito dopo la generazione. Il gate controlla struttura, campi richiesti, valori ammessi, requisiti di evidenza e soglie di confidenza. Poi emette pochi stati operativi: accettato, da revisionare, servono più informazioni, fallito in modo sicuro, bloccato.
Questi stati dovrebbero essere noiosi. Noioso è positivo. Stati noiosi rendono più semplici le dashboard, più chiare le code e meno teatrali gli incidenti. L’obiettivo non è far sembrare certo il modello. L’obiettivo è rendere instradabile l’incertezza.
Qui gli strumenti con tipizzazione aiutano. BAML è un esempio perché la sua documentazione enfatizza output tipizzati, funzioni di prompt, preview nell’editor e client generati per più linguaggi. Ma lo stesso contratto operativo può essere implementato con altri validator di schema, interfacce di function calling, JSON schema, test interni o motori di workflow. La parte importante è che schema, validatore, fallback e owner esistano prima dell’ennesima regola furba di recupero.
Audita un’automazione prima di aggiungere un retry
La mossa pratica non è riscrivere tutti i workflow LLM questa settimana. Scegli una sola automazione il cui output produce già piccoli momenti di sfiducia.
Prendi un output reale. Mettilo accanto all’azione a valle che attiva. Poi fai cinque domande.
Quali campi servono davvero per quell’azione?
Quali campi sono obbligatori, opzionali, nullable o vietati?
Quale validazione dimostra che l’output è utilizzabile, non solo ben formato?
Cosa succede quando l’output è incompleto, non supportato da evidenza o fuori dagli stati ammessi?
Chi possiede le modifiche al contratto?
Se il team non sa rispondere, un altro retry farà soltanto fallire l’automazione più tardi e in modo meno visibile.
Gli output strutturati non sono un trucco di formattazione. Sono una superficie di coordinamento. Permettono al prodotto di definire il significato, alle operations di definire la gestione sicura e all’engineering di far rispettare il confine. Nel momento in cui un output LLM sposta lavoro da un sistema a un altro, al team non basta un parser che di solito sopravvive. Serve un contratto che dica cosa può essere fidato, cosa deve essere revisionato e cosa deve fermarsi.