Confronto dei output strutturati tra i principali provider di LLM: OpenAI, Gemini, Anthropic, Mistral e AWS Bedrock
API leggermente diverse richiedono un approccio speciale.
Ecco un confronto a fianco del supporto per l’output strutturato (ottenere JSON affidabili) presso i principali provider di LLM, oltre a esempi minimi in Python

Abbiamo già esaminato come richiedere l’output strutturato dall’LLM ospitato su Ollama. Una volta che il JSON è in transito, la validazione dell’output strutturato LLM in Python che regge analizza il parsing, i controlli Pydantic, i retry e i test nel tuo servizio. Qui esaminiamo come richiedere la stessa cosa da altri provider.
Matrice TL;DR
| Provider | “JSON mode” nativo | Applicazione Schema JSON | Impostazione tipica | Note |
|---|---|---|---|---|
| OpenAI | Sì | Sì (di prima classe) | response_format={"type":"json_schema", ...} |
Funziona tramite l’API Responses o Chat Completions; può anche effettuare function calling. |
| Google Gemini | Sì | Sì (di prima classe) | response_schema= + response_mime_type="application/json" |
Restituisce JSON rigorosamente validato quando è definito uno schema. |
| Anthropic (Claude) | Indiretto | Sì (tramite Tool Use con schema JSON) | tools=[{input_schema=...}] + tool_choice |
Costringe il modello a “chiamare” il tuo tool definito tramite schema; produce argomenti conformi allo schema. |
| Mistral | Sì | Parziale (solo JSON; nessuna schema lato server) | response_format={"type":"json_object"} |
Garantisce il formato JSON, ma tu validi contro il tuo schema lato client. |
| AWS Bedrock (piattaforma) | Varia per modello | Sì (tramite schema Tool/Converse) | toolConfig.tools[].toolSpec.inputSchema |
L’API Converse di Bedrock valida l’input del tool contro uno schema JSON. |
Output Strutturato LLM - Informazioni Generali
L’output strutturato degli LLM si riferisce alla capacità dei grandi modelli linguistici (LLM) di generare risposte che aderiscono strettamente a un formato o una struttura predefinita e specifica, anziché produrre testo libero. Questo output strutturato può assumere formati come JSON, XML, tabelle o template, rendendo i dati leggibili dalle macchine, coerenti e facilmente analizzabili dal software per l’uso in varie applicazioni.
Gli output strutturati differiscono dagli output tradizionali degli LLM, che tipicamente generano testo naturale aperto. Invece, gli output strutturati applicano uno schema o un formato, come oggetti JSON con chiavi e tipi di valore definiti, o classi specifiche nell’output (ad esempio, risposte a scelta multipla, classi di sentiment o formati di riga di database). Questo approccio migliora l’affidabilità, riduce errori e allucinazioni e semplifica l’integrazione in sistemi come database, API o flussi di lavoro.
La generazione di output strutturati negli LLM spesso coinvolge tecniche come:
- Specificare istruzioni dettagliate nel prompt per guidare il modello a produrre output nel formato desiderato.
- Utilizzare strumenti di validazione e parsing come Pydantic in Python per garantire che l’output corrisponda allo schema.
- A volte applicare vincoli di decodifica basati su grammatica o macchine a stati finiti per garantire la conformità a livello di token al formato.
I vantaggi degli output strutturati degli LLM includono:
- Leggibilità da parte delle macchine e facilità di integrazione.
- Ridotta variabilità e minor numero di errori.
- Migliore prevedibilità e verificabilità per task che richiedono formati di dati coerenti.
Le sfide includono la progettazione di schemi efficaci, la gestione di dati annidati complessi e potenziali limitazioni nelle capacità di ragionamento rispetto alla generazione di testo libero.
Nel complesso, l’output strutturato consente agli LLM di essere più utili in applicazioni che richiedono dati precisi e formattati, anziché solo testo leggibile dall’uomo.
Esempi Python per Output Strutturato
Tutti gli snippet estraggono le informazioni dell’evento come JSON: {title, date, location}. Sostituisci chiavi/modelli a piacere.
1) OpenAI — Schema JSON (rigoroso)
from openai import OpenAI
import json
client = OpenAI()
schema = {
"name": "Event",
"schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"date": {"type": "string", "description": "YYYY-MM-DD"},
"location": {"type": "string"}
},
"required": ["title", "date", "location"],
"additionalProperties": False
},
"strict": True
}
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}
],
response_format={"type": "json_schema", "json_schema": schema},
)
data = json.loads(resp.choices[0].message.content)
print(data)
La funzionalità Structured Outputs di OpenAI applica questo schema lato server.
2) Google Gemini — schema di risposta + MIME JSON
import google.generativeai as genai
from google.genai import types
# Configura con la tua chiave API
# genai.configure(api_key="your-api-key")
schema = types.Schema(
type=types.Type.OBJECT,
properties={
"title": types.Schema(type=types.Type.STRING),
"date": types.Schema(type=types.Type.STRING),
"location": types.Schema(type=types.Type.STRING),
},
required=["title", "date", "location"],
additional_properties=False,
)
resp = genai.generate_content(
model="gemini-2.0-flash",
contents="Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'",
generation_config=genai.GenerationConfig(
response_mime_type="application/json",
response_schema=schema,
),
)
print(resp.text) # già JSON valido secondo lo schema
Gemini restituirà JSON rigoroso conforme a response_schema.
3) Anthropic (Claude) — Tool Use con schema JSON
from anthropic import Anthropic
import json
client = Anthropic()
tool = {
"name": "extract_event",
"description": "Return event details.",
"input_schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"date": {"type": "string"},
"location": {"type": "string"}
},
"required": ["title", "date", "location"],
"additionalProperties": False
}
}
msg = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=256,
tools=[tool],
tool_choice={"type": "tool", "name": "extract_event"}, # forza lo schema
messages=[{"role": "user", "content":
"Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)
# Claude "chiamerà" il tool; recupera gli argomenti (che corrispondono al tuo schema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))
Claude non ha un interruttore generico per la “modalità JSON”; invece, l’Tool Use con uno input_schema ti fornisce argomenti validati e conformi allo schema (e puoi forzare il suo utilizzo).
4) Mistral — modalità JSON (validazione lato client)
from mistralai import Mistral
import json
client = Mistral()
resp = client.chat.complete(
model="mistral-large-latest",
messages=[{"role":"user","content":
"Return JSON with keys title, date (YYYY-MM-DD), location for: "
"'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
response_format={"type": "json_object"} # garantisce JSON valido
)
data = json.loads(resp.choices[0].message.content)
print(data)
# Suggerimento: valida `data` contro il tuo Pydantic/JSON Schema localmente.
json_object di Mistral applica la forma JSON (non il tuo schema esatto) — valida lato client.
5) AWS Bedrock — Schema Tool API Converse (indipendente dal modello)
import boto3, json
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0"
tools = [{
"toolSpec": {
"name": "extract_event",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"title": {"type": "string"},
"date": {"type": "string"},
"location": {"type": "string"}
},
"required": ["title","date","location"],
"additionalProperties": False
}
}
}
}]
resp = bedrock.converse(
modelId=model_id,
toolConfig={"tools": tools},
toolChoice={"tool": {"name": "extract_event"}}, # forza lo schema
messages=[{"role":"user","content":[{"text":
"Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)
# Estrai il contenuto toolUse
tool_use = next(
c["toolUse"] for c in resp["output"]["message"]["content"] if "toolUse" in c
)
print(json.dumps(tool_use["input"], indent=2))
Bedrock valida l’input del tool rispetto al tuo schema JSON e molti modelli ospitati (ad esempio, Claude) lo supportano tramite Converse.
Guida pratica e Validazione
- Se vuoi le garanzie lato server più forti: output strutturati di OpenAI o schema di risposta di Gemini.
- Se sei già su Claude/Bedrock: definisci un Tool con uno schema JSON e forzarne l’uso; leggi gli argomenti del tool come il tuo oggetto tipizzato.
- Se usi Mistral: abilita
json_objecte valida localmente (ad esempio, con Pydantic).
Modello di validazione (funziona per tutti)
from pydantic import BaseModel, ValidationError
class Event(BaseModel):
title: str
date: str
location: str
try:
event = Event.model_validate(data) # `data` da qualsiasi provider
except ValidationError as e:
# gestisci / riprova / chiedi al modello di correggere con e.errors()
print(e)
Collegamenti utili
- https://platform.openai.com/docs/guides/structured-outputs
- https://ai.google.dev/gemini-api/docs/structured-output
- https://docs.mistral.ai/capabilities/structured-output/json_mode/
- https://aws.amazon.com/blogs/machine-learning/structured-data-response-with-amazon-bedrock-prompt-engineering-and-tool-use
- https://github.com/aws-samples/anthropic-on-aws/blob/main/complex-schema-tool-use/README.md
- https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html
- Come richiedere l’Output Strutturato dall’LLM ospitato su Ollama
- Scheda Rapida Python