Confronto dei output strutturati tra i principali provider di LLM - OpenAI, Gemini, Anthropic, Mistral e AWS Bedrock

API leggermente diverse richiedono un approccio specifico.

Indice

Ecco un confronto tra il supporto per output strutturati (ottenimento di JSON affidabili) tra i principali provider di LLM, insieme a esempi Python minimi.

colorised bars standing

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ì (first-class) response_format={"type":"json_schema", ...} Funziona tramite l’API Risposte o Chat Completions; supporta anche il function calling.
Google Gemini 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 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_object e 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)

Iscriviti

Ricevi nuovi articoli su sistemi, infrastruttura e ingegneria AI.