Structured outputs è una funzione delle LLM API che obbliga la risposta di un modello a rispettare un JSON Schema fornito dall’utente. Con la decodifica vincolata, l’API compila lo schema in una grammatica o macchina a stati che limita la generazione di token, evitando errori di sintassi e campi mancanti nelle API di OpenAI, Anthropic e Google.
Cosa sono gli Structured Outputs in una LLM API?
In una LLM API, structured outputs vincola i token generati dal modello affinché la risposta completa corrisponda a un JSON Schema fornito dallo sviluppatore. Anthropic e Google descrivono entrambi il meccanismo sottostante come decodifica vincolata: prima che inizi il campionamento, l’API compila lo schema in una grammatica o macchina a stati finiti che esclude ogni token successivo che violerebbe la struttura, i nomi delle chiavi o i tipi di valore dello schema.
Senza structured outputs, chiedere a un modello linguistico in un prompt di rispondere in JSON non funziona in modo costante in produzione. La documentazione di Anthropic evidenzia quattro modalità di errore comuni quando ci si affida solo alle istruzioni del prompt: errori di parsing dovuti a sintassi JSON non valida, campi obbligatori mancanti, tipi di dati incoerenti e violazioni dello schema che richiedono gestione degli errori e nuovi tentativi. In pratica, questi errori si presentano come nei seguenti esempi generici:
- Errori di parsing dovuti a sintassi JSON non valida: Per esempio, parentesi graffe non chiuse, virgole finali o testo Markdown attorno ai dati possono compromettere un parser JSON.
- Campi obbligatori mancanti: Per esempio, un modello può omettere una chiave attesa dal codice applicativo a valle.
- Tipi di dati incoerenti: Per esempio, un campo numerico può arrivare come stringa oppure un singolo valore può arrivare al posto di un array.
- Violazioni dello schema che richiedono gestione degli errori e nuovi tentativi: Per esempio, chiavi non richieste o valori fuori intervallo impongono cicli di ripetizione e codice di validazione difensiva.
La decodifica vincolata elimina la necessità di istruzioni di formattazione perentorie nel prompt. Per mantenere i tipi dell’applicazione allineati allo schema passato all’API, OpenAI e Google forniscono helper nativi degli SDK che accettano classi Pydantic BaseModel in Python e oggetti Zod in JavaScript, mentre l’SDK Python di Anthropic accetta un modello Pydantic tramite client.messages.parse() e analizza la risposta in quel tipo.
In cosa differiscono Structured Outputs, JSON mode e JSON richiesto solo tramite prompt?
Structured outputs garantisce l’aderenza esatta al JSON Schema, mentre JSON mode e le sole istruzioni nel prompt non possono imporre nomi di proprietà specifici, strutture annidate o campi obbligatori.
JSON mode era il passaggio intermedio precedente ai vincoli completi sullo schema. Con OpenAI, abilitare JSON mode tramite { "type": "json_object" } assicura che il modello produca JSON sintatticamente valido, a condizione che la richiesta non incontri un caso limite, come l’esaurimento dei token di output a metà di un oggetto. La documentazione di OpenAI riporta però avvertenze esplicite: occorre includere nel contesto della conversazione un’istruzione per produrre JSON, altrimenti l’API restituisce un errore se manca la parola JSON e il modello può altrimenti generare un flusso interminabile di spazi fino al limite dei token.
OpenAI descrive structured outputs come l’evoluzione di JSON mode e raccomanda di usare structured outputs ogni volta che è supportato, riservando JSON mode ai modelli più vecchi come gpt-4-turbo e precedenti.
| Funzione | JSON solo tramite prompt | JSON mode | Structured Outputs |
|---|---|---|---|
| Sintassi JSON valida garantita | No | Sì, salvo troncamento | Sì, salvo rifiuto o troncamento |
| Impone schema e tipi esatti | No | No | Sì |
| Richiede un’istruzione JSON nel prompt | Sì | Sì, richiesta da OpenAI | No |
| Elimina i nuovi tentativi di formattazione | No | In parte | Sì, per la struttura dello schema |
| Parsing nativo con Pydantic e Zod | Manuale | Manuale | Supportato dagli SDK dei fornitori |
Structured Outputs e Function Calling: quando usare ciascuno?
Structured outputs formatta la risposta finale del modello per l’applicazione o l’utente finale, mentre function calling collega il modello a strumenti, API e fonti di dati esterne durante l’esecuzione.
Gli sviluppatori spesso confondono le due funzioni perché entrambe si basano su definizioni JSON Schema. OpenAI e Google tracciano lo stesso confine architetturale:
- Usa structured outputs quando vuoi formattare chiaramente il messaggio finale dell’assistente per l’interfaccia, il database o la pipeline a valle, per esempio per l’estrazione di dati o la classificazione strutturata.
- Usa function calling (tool use) quando il modello deve richiedere un’azione, cercare dati aggiornati o invocare una routine backend prima di poter terminare la risposta. Per approfondire il ruolo delle definizioni degli strumenti nei protocolli moderni, consulta la nostra guida a tool calling e MCP.
OpenAI offre schemi rigorosi in due forme distinte: function calling con schemi rigorosi per collegare il modello a strumenti o dati e un formato di risposta json_schema per strutturare la risposta all’utente. Anthropic separa le due funzioni in output_config.format per la risposta finale di Claude e strict: true sui singoli strumenti per garantire nomi di strumenti e argomenti di input validi, e supporta esplicitamente l’uso di entrambe in un’unica richiesta. La combinazione è particolarmente pratica nei flussi di lavoro con agenti IA, in cui le chiamate intermedie agli strumenti e il riepilogo finale devono rispettare contratti rigorosi.
Come OpenAI, Anthropic e Google implementano Structured Outputs
A novembre 2026 OpenAI, Anthropic e Google implementano ciascuno structured outputs tramite compilazione dello schema, ma differiscono per parametri di richiesta, parole chiave JSON Schema supportate e limiti di complessità.
| Fornitore | Come abilitare | Helper SDK per gli schemi | Regole dello schema rilevanti | Limiti rilevanti |
|---|---|---|---|---|
| OpenAI | Responses API text.format o Chat Completions response_format con type: "json_schema" e strict: true |
Pydantic BaseModel (Python), Zod (JS) |
La radice deve essere un oggetto, non anyOf; tutti i campi in required; additionalProperties: false obbligatorio; chiavi emesse nell’ordine dello schema |
Fino a 5.000 proprietà, 10 livelli di annidamento, 120.000 caratteri tra nomi ed enum, 1.000 valori enum |
| Anthropic Claude | output_config.format con type: "json_schema", più strict: true sugli strumenti |
client.messages.parse() con Pydantic (Python) |
Supporta $ref/$defs, anyOf e allOf (con limiti); additionalProperties: false obbligatorio; nessun limite numerico o di lunghezza delle stringhe |
Massimo 20 strumenti rigorosi, 24 parametri facoltativi, 16 parametri di unione, timeout di compilazione di 180s; cache della grammatica di 24 ore |
| Google Gemini API | Configurazione della risposta con tipo testuale, mime_type: "application/json" e schema |
Pydantic (Python), Zod (JS) | Supporta minimum/maximum, minItems/maxItems, prefixItems; rimuove silenziosamente i limiti non supportati |
Gli schemi grandi o profondamente annidati falliscono con 400 INVALID_ARGUMENT |
OpenAI
OpenAI supporta structured outputs a partire da GPT-4o e raccomanda gpt-6-astra per i nuovi progetti. Chiamare l’API con strict: true e una parola chiave non supportata come allOf, not, if/then/else, dependentRequired o dependentSchemas restituisce un errore anziché fallire silenziosamente. OpenAI supporta formati di stringa come date-time, time, date, duration, email, hostname, ipv4, ipv6 e uuid, oltre a limiti numerici (minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf) e limiti per array (minItems, maxItems).
Anthropic Claude
Anthropic supporta structured outputs per tutti i modelli della Messages API, ma non all’interno di Managed Agents. Quando usi client.messages.parse() nell’SDK Python, i vincoli non supportati come minimum, maximum, minLength e maxLength vengono spostati automaticamente nelle descrizioni dei campi affinché Claude ne comprenda l’intento, e l’SDK convalida localmente i dati restituiti rispetto al modello Pydantic originale.
Claude memorizza nella cache le grammatiche compilate per 24 ore dall’ultimo utilizzo; modificare la struttura dello schema o l’insieme degli strumenti invalida tale cache, mentre modificare nomi o descrizioni dei campi non lo fa. Poiché Claude riceve anche un prompt di sistema automatico che spiega il formato JSON, il numero di token di input aumenta leggermente e modificare output_config.format invalida la cache dei prompt della conversazione. Le proprietà obbligatorie sono emesse per prime, seguite da quelle facoltative. Structured outputs funziona con streaming, conteggio dei token e Batch processing (con lo sconto del 50 percento di Anthropic). Tuttavia, combinare output JSON con Citations restituisce un errore 400 e structured outputs è incompatibile con il precompilamento dei messaggi.
Google Gemini API
Google indica estrazione dei dati, classificazione strutturata e flussi di lavoro con agenti come principali casi d’uso di structured outputs in Gemini. A differenza di OpenAI e Anthropic, Gemini rimuove e ignora silenziosamente diverse parole chiave senza generare errori, tra cui minLength, maxLength, minProperties, maxProperties, uniqueItems, contains, minContains e maxContains. Esegui sempre Pydantic model_validate_json() o Zod .parse() sulle risposte di Gemini per applicare tali vincoli nel codice dell’applicazione. Se Gemini restituisce 400 INVALID_ARGUMENT per uno schema troppo complesso, Google consiglia di appiattire gli annidamenti, ridurre i campi facoltativi o gli enum, abbreviare i nomi delle proprietà e spostare le regole non strutturali nelle descrizioni dei campi.
Come progettare un JSON Schema affidabile per gli LLM
Un JSON Schema affidabile per structured outputs degli LLM resta piatto, contrassegna i campi come obbligatori e usa tipi che ammettono null invece di chiavi facoltative. Progettare schemi secondo regole condivise tra fornitori aiuta a prevenire errori di compilazione e rifiuti inattesi durante l’esecuzione.
Usa questa checklist prima di distribuire uno schema per OpenAI, Claude o Gemini:
- Mantieni poco profondi gli annidamenti: Appiattisci gli oggetti molto annidati quando possibile per restare ben al di sotto del limite di 10 livelli di OpenAI ed evitare rifiuti di compilazione da parte di Gemini o Claude.
- Rendi obbligatorio ogni campo: Elenca ogni chiave dell’oggetto in
required, poiché OpenAI applica rigorosamente questa regola e Claude limita a 24 il totale dei parametri facoltativi per richiesta. - Usa unioni che ammettono null per i dati mancanti: Rappresenta i valori facoltativi con
"type": ["string", "null"]anziché omettere chiavi darequired. - Limita gli oggetti: Imposta
"additionalProperties": falsesu ogni definizione di oggetto, come richiesto sia da OpenAI sia da Anthropic. - Vincola le scelte fisse con gli enum: Sostituisci le categorie di stringhe libere con array
enumespliciti quando è valido solo un insieme noto di etichette. - Scrivi descrizioni chiare: Inserisci le regole del dominio e i vincoli ignorati, come le lunghezze desiderate dei caratteri o le istruzioni alternative, nella
descriptiondi ogni proprietà.
Di seguito trovi uno schema di esempio per classificare un ticket di assistenza clienti. Segue le regole comuni ai fornitori indicate sopra: una radice oggetto, tutti i campi obbligatori, un campo che ammette null per i metadati facoltativi, additionalProperties: false e un enum per l’instradamento.
{
"type": "object",
"additionalProperties": false,
"required": ["category", "urgency", "summary", "order_id"],
"properties": {
"category": {
"type": "string",
"enum": ["billing", "bug_report", "account_access", "other"],
"description": "Primary topic of the support message."
},
"urgency": {
"type": "string",
"enum": ["low", "normal", "high"],
"description": "Escalation priority based on user impact."
},
"summary": {
"type": "string",
"description": "One-sentence summary of the issue in 25 words or fewer."
},
"order_id": {
"type": ["string", "null"],
"description": "Order identifier if present in the message, otherwise null."
}
}
}
Cosa può ancora andare storto con Structured Outputs?
Structured outputs garantisce una sintassi valida rispetto allo schema, ma le applicazioni in produzione incontrano ancora rifiuti, troncamento dei token, valori allucinati, variazioni delle maiuscole negli enum, latenza alla prima richiesta e input utente non attendibili. Trattare la conformità allo schema come verifica della sintassi anziché della verità o della sicurezza previene errori silenziosi in produzione.
Rifiuti di sicurezza e troncamento al limite di token
I modelli possono ancora rifiutare richieste non sicure degli utenti o interrompersi durante la generazione quando raggiungono il limite dei token di output. In OpenAI, un rifiuto di sicurezza popola un campo separato refusal che non aderisce al JSON Schema. In Anthropic Claude, un rifiuto restituisce HTTP 200 con stop_reason impostato su "refusal" (che viene comunque fatturato) e prevale sullo schema; analogamente, il raggiungimento del limite di output restituisce stop_reason "max_tokens" con JSON incompleto. Controlla sempre gli indicatori di rifiuto e i motivi di arresto prima di chiamare JSON.parse() o un validatore.
Valori validi per lo schema ma fattualmente errati
La decodifica vincolata obbliga il modello a compilare lo schema anche quando il testo sorgente non contiene una risposta o contraddice le ipotesi dello schema. Una risposta può superare tutti i controlli di tipo e enum pur contenendo date inventate, categorie errate o supposizioni plausibili. OpenAI consiglia di indicare al modello nel prompt cosa restituire quando l’input è incompatibile con lo schema, per esempio null o campi vuoti, e Google invita gli sviluppatori a convalidare i valori nel codice rispetto alle regole aziendali. Per capire perché risposte sicure di sé possono essere errate, leggi la nostra guida sui tassi di allucinazione dell’IA.
Maiuscole negli enum di Claude e latenza di compilazione
Due particolarità operative colgono di sorpresa i team durante il rilascio:
- Maiuscole negli enum di Claude: Anthropic osserva che le maiuscole negli enum non sono garantite durante la decodifica vincolata, quindi confronta le stringhe enum restituite senza distinguere maiuscole e minuscole nella logica dell’applicazione.
- Ritardo di compilazione alla prima richiesta: Claude aggiunge latenza la prima volta che un nuovo schema viene compilato in una grammatica, prima di conservarla nella cache per 24 ore; OpenAI segnala un ritardo simile nell’elaborazione dello schema alla prima richiesta per i modelli sottoposti a fine-tuning.
Prompt Injection nei valori dei campi
Vincolare la struttura dell’output non neutralizza le istruzioni malevole nascoste in testo non attendibile che viene riassunto o estratto in un campo stringa JSON. Un modello può restituire correttamente JSON valido il cui campo summary o notes contiene istruzioni iniettate o contenuti ingannevoli rivolti a strumenti a valle o revisori umani. Tratta ogni valore di campo analizzato come input non attendibile e consulta la nostra introduzione su cosa sia la prompt injection prima di passare campi estratti ad azioni automatiche.
Domande frequenti
Structured outputs rallenta le risposte degli LLM?
Structured outputs può aggiungere latenza alla prima richiesta con un nuovo schema, mentre le richieste successive memorizzate nella cache vengono eseguite senza costi di compilazione. Anthropic conserva le grammatiche compilate di Claude per 24 ore dall’ultimo utilizzo, a meno che non si modifichino la struttura dello schema o le definizioni degli strumenti. OpenAI segnala latenza aggiuntiva nell’elaborazione dello schema alla prima richiesta solo per i modelli sottoposti a fine-tuning.
Un LLM può ancora allucinare usando structured outputs?
Sì, un LLM può ancora allucinare valori pur restituendo JSON conforme allo schema al 100 percento. La decodifica vincolata limita la sintassi dei token e i tipi dei campi, non l’accuratezza fattuale. Se nell’input mancano informazioni obbligatorie, il modello può inventare valori per soddisfare le chiavi richieste, a meno che non si consentano campi che ammettono null e non gli si indichi quando restituire null.
È meglio usare Pydantic o Zod con le API structured output?
Gli helper nativi degli SDK per gli schemi aiutano a mantenere allineati i tipi dell’applicazione e gli schemi API. OpenAI e Google supportano sia Pydantic in Python sia Zod in JavaScript, mentre l’SDK Python di Anthropic supporta Pydantic tramite client.messages.parse(). Questi helper convertono i modelli in JSON Schema, analizzano le risposte in oggetti tipizzati e convalidano vincoli come le lunghezze delle stringhe che Gemini rimuove o Anthropic sposta nelle descrizioni dei campi.
Cosa succede se un modello rifiuta una richiesta con structured outputs abilitato?
Quando un modello rifiuta una richiesta per motivi di sicurezza, il rifiuto prevale sul JSON Schema. OpenAI inserisce la spiegazione in un campo refusal dedicato anziché seguire lo schema, mentre Anthropic restituisce HTTP 200 con stop_reason impostato su "refusal". L’applicazione deve esaminare quei campi prima di tentare il parsing del JSON.
Perché Claude o Gemini rifiuta il mio JSON Schema con un errore 400?
Sia Claude sia Gemini rifiutano con un errore 400 gli schemi che superano i limiti interni di complessità della grammatica o della macchina a stati. Claude restituisce un errore 400 anche se includi funzioni dello schema non supportate, come schemi ricorsivi o limiti numerici, oppure se combini output JSON con Citations. Appiattire gli oggetti annidati, abbreviare i nomi e ridurre i parametri facoltativi o di unione risolve solitamente i rifiuti di compilazione.



