Confronto dei output strutturati tra i principali provider di LLM - OpenAI, Gemini, Anthropic, Mistral e AWS Bedrock
API leggermente diverse richiedono un approccio specifico.
Ecco un confronto tra il supporto per output strutturati (ottenimento di JSON affidabili) tra i principali provider di LLM, insieme a esempi Python minimi.

Abbiamo già esaminato come richiedere output strutturati dall’LLM ospitato su Ollama. Una volta che il JSON è disponibile sul canale, validazione degli output strutturati LLM in Python che regge illustra parsing, controlli Pydantic, retry e test nel tuo servizio. Qui esaminiamo come richiedere lo stesso risultato da altri provider.
Matrice TL;DR
| Provider | Modalità “JSON” nativa | Applicazione dello Schema JSON | Impostazione tipica | Note |
|---|---|---|---|---|
| OpenAI | Sì | Sì (first-class) | response_format={"type":"json_schema", ...} |
Funziona tramite l’API Risposte o Chat Completions; supporta anche il function calling. |
| Google Gemini | Sì | Sì (first-class) | response_schema= + response_mime_type="application/json" |
Restituisce JSON strettamente validato quando è impostata uno schema. |
| Anthropic (Claude) | Indiretta | Sì (tramite Tool Use con schema JSON) | tools=[{input_schema=...}] + tool_choice |
Forza il modello a “chiamare” il tuo strumento definito dallo schema; restituisce argomenti conformi allo schema. |
| Mistral | Sì | Parziale (solo JSON; nessun schema lato server) | response_format={"type":"json_object"} |
Garantisce JSON, ma la validazione rispetto allo schema avviene lato client. |
| AWS Bedrock (piattaforma) | Variabile in base al modello | Sì (tramite schema Tool/Converse) | toolConfig.tools[].toolSpec.inputSchema |
L’API Converse di Bedrock valida l’input degli strumenti rispetto a uno schema JSON. |
Output Strutturati LLM - Informazioni Generali
Gli output strutturati degli LLM si riferiscono alla capacità dei grandi modelli linguistici (LLM) di generare risposte che aderiscono strettamente a un formato o struttura predefiniti, anziché produrre testo libero. Questo output strutturato può essere in formati come JSON, XML, tabelle o template, rendendo i dati leggibili dalle macchine, coerenti e facilmente parsabili dal software per l’uso in varie applicazioni.
Gli output strutturati differiscono dagli output tradizionali degli LLM, che tipicamente generano testo in linguaggio naturale aperto. Invece, gli output strutturati impongono 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 righe di database). Questo approccio migliora l’affidabilità, riduce errori e allucinazioni e semplifica l’integrazione in sistemi come database, API o workflow.
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, l’imposizione di vincoli di decodifica basati su grammatica o macchine a stati finiti per garantire la conformità a livello di token rispetto al formato.
I vantaggi degli output strutturati degli LLM includono:
- Leggibilità dalle macchine e facilità di integrazione.
- Riduzione della variabilità e degli errori.
- Migliore prevedibilità e verificabilità per attività che richiedono formati di dati coerenti.
Le sfide includono la progettazione di schemi efficaci, la gestione di dati nidificati 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 Strutturati
Tutti i frammenti estraggono info sull’evento come JSON: {title, date, location}. Sostituisci chiavi/modelli come preferisci.
1) OpenAI — JSON Schema (strict)
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 funzione Structured Outputs di OpenAI applica questo schema lato server.
2) Google Gemini — response schema + JSON MIME
import google.generativeai as genai
from google.genai import types
# Configure with your API key
# 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) # already valid JSON per schema
Gemini restituirà JSON strettamente valido 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"}, # force schema
messages=[{"role": "user", "content":
"Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)
# Claude will "call" the tool; grab the args (which match your 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, Tool Use con un 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"} # guarantees valid JSON
)
data = json.loads(resp.choices[0].message.content)
print(data)
# Tip: validate `data` against your Pydantic/JSON Schema locally.
json_object di Mistral garantisce la forma JSON (non il tuo schema esatto) — valida lato client.
5) AWS Bedrock — Schema Tool API Converse (modello-agnostico)
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"}}, # force schema
messages=[{"role":"user","content":[{"text":
"Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)
# Pull toolUse content
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 degli strumenti rispetto al tuo schema JSON e molti modelli ospitati (es. Claude) lo supportano tramite Converse.
Linee Guida Pratiche e Validazione
- Se vuoi le garanzie lato server più forti: Output strutturati OpenAI o schema risposta Gemini.
- Se usi già Claude/Bedrock: definisci uno Strumento con uno schema JSON e forzane l’uso; leggi gli argomenti dello strumento come il tuo oggetto tipizzato.
- Se usi Mistral: abilita
json_objecte valida localmente (es. con Pydantic).
Pattern 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 / retry / chiedi al modello di correggere con e.errors()
print(e)
Link 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 Output Strutturati dall’LLM ospitato su Ollama
- Python Cheatsheet
- AWS SAM + AWS SQS + Python PowerTools
- Confronto prestazioni AWS Lambda: JavaScript vs Python vs Golang