Comparación de la salida estructurada entre proveedores populares de LLM: OpenAI, Gemini, Anthropic, Mistral y AWS Bedrock

Las APIs ligeramente diferentes requieren un enfoque especial.

Índice

A continuación, se presenta una comparación de soporte lado a lado de salida estructurada (obtener JSON de forma confiable) entre los principales proveedores de LLM, además de ejemplos mínimos en Python

colorised bars standing

Ya hemos revisado cómo solicitar salida estructurada del LLM alojado en Ollama. Una vez que el JSON vuelve por la red, la validación de salida estructurada de LLM en Python que funciona explica cómo analizar, realizar comprobaciones con Pydantic, reintentos y pruebas en su servicio. Aquí revisamos cómo solicitar lo mismo de otros proveedores.

Matriz TL;DR

Proveedor Modo “JSON” nativo Aplicación de Esquema de JSON Parámetro típico Notas
OpenAI Sí Sí (de primer nivel) response_format={"type":"json_schema", ...} Funciona a través de la API de Respuestas o Completions de Chat; también puede hacer llamada de funciones.
Google Gemini Sí Sí (de primer nivel) response_schema= + response_mime_type="application/json" Devuelve JSON estrictamente validado cuando se establece un esquema.
Anthropic (Claude) Indirecto Sí (a través de Uso de Herramientas con esquema JSON) tools=[{input_schema=...}] + tool_choice Fuerza al modelo a “llamar” a su herramienta definida por el esquema; produce argumentos con forma de esquema.
Mistral Sí Parcial (solo JSON; sin esquema del servidor) response_format={"type":"json_object"} Asegura JSON, pero usted valida contra su esquema en el lado del cliente.
AWS Bedrock (plataforma) Varía según el modelo Sí (a través del esquema Tool/Converse) toolConfig.tools[].toolSpec.inputSchema La API Converse de Bedrock valida la entrada de la herramienta contra un esquema JSON.

Salida Estructurada de LLM - Información General

La salida estructurada de LLM se refiere a la capacidad de los modelos de lenguaje grandes (LLMs) para generar respuestas que se adhieren estrictamente a un formato o estructura predefinido y específico, en lugar de producir texto libre. Esta salida estructurada puede estar en formatos como JSON, XML, tablas o plantillas, lo que hace que los datos sean legibles por máquina, consistentes y fácilmente analizables por software para su uso en diversas aplicaciones.

Las salidas estructuradas difieren de las salidas tradicionales de LLM, que generalmente generan texto de lenguaje natural abierto. En cambio, las salidas estructuradas imponen un esquema o formato, como objetos JSON con claves y tipos de valores definidos, o clases específicas en la salida (p. ej., respuestas de opción múltiple, clases de sentimiento o formatos de filas de base de datos). Este enfoque mejora la confiabilidad, reduce errores e alucinaciones y simplifica la integración en sistemas como bases de datos, API o flujos de trabajo.

La generación de salidas estructuradas en LLMs a menudo involucra técnicas como:

  • Especificar instrucciones detalladas del prompt para guiar al modelo a producir salida en el formato deseado.
  • Utilizar herramientas de validación y análisis como Pydantic en Python para asegurar que la salida coincida con el esquema.
  • A veces, imponer restricciones de decodificación basadas en gramática o autómatas finitos de estado para asegurar el cumplimiento a nivel de tokens con el formato.

Los beneficios de las salidas estructuradas de LLM incluyen:

  • Legibilidad por máquina y facilidad de integración.
  • Reducción de variabilidad y errores.
  • Mejora de la predictibilidad y verificabilidad para tareas que requieren formatos de datos consistentes.

Los desafíos incluyen el diseño de esquemas efectivos, el manejo de datos anidados complejos y posibles limitaciones en las capacidades de razonamiento en comparación con la generación de texto libre.

En general, la salida estructurada permite que los LLMs sean más útiles en aplicaciones que requieren datos precisos y formateados, en lugar de únicamente texto legible por humanos.

Ejemplos de Salida Estructurada en Python

Todos los fragmentos extraen la información de evento como JSON: {title, date, location}. Reemplace las claves/modelos a su gusto.

1) OpenAI — Esquema JSON (estricto)

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": "Extrae el evento de: 'PyData Sydney es el 2025-11-03 en Darling Harbour.'"}
    ],
    response_format={"type": "json_schema", "json_schema": schema},
)

data = json.loads(resp.choices[0].message.content)
print(data)

La función de Salidas Estructuradas de OpenAI aplica este esquema en el lado del servidor.


2) Google Gemini — esquema de respuesta + MIME JSON

import google.generativeai as genai
from google.genai import types

# Configure con su clave de API
# genai.configure(api_key="su-clave-de-api")

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="Extrae el evento de: 'PyData Sydney es el 2025-11-03 en Darling Harbour.'",
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)

print(resp.text)  # ya es JSON válido según el esquema

Gemini devolverá JSON estricto que cumple con response_schema.


3) Anthropic (Claude) — Uso de Herramientas con esquema JSON

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Devuelve los detalles del evento.",
    "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"},  # fuerza el esquema
    messages=[{"role": "user", "content":
        "Extrae el evento de: 'PyData Sydney es el 2025-11-03 en Darling Harbour.'"}],
)

# Claude "llamará" a la herramienta; capture los argumentos (que coinciden con su esquema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))

Claude no tiene un interruptor de “modo JSON” genérico; en cambio, el Uso de Herramientas con un input_schema le da argumentos validados y con forma de esquema (y puede forzar su uso).


4) Mistral — modo JSON (validación en el lado del cliente)

from mistralai import Mistral
import json

client = Mistral()

resp = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role":"user","content":
        "Devuelve JSON con las claves title, date (YYYY-MM-DD), location para: "
        "'PyData Sydney es el 2025-11-03 en Darling Harbour.'"}],
    response_format={"type": "json_object"}  # garantiza JSON válido
)

data = json.loads(resp.choices[0].message.content)
print(data)
# Consejo: valide `data` contra su Pydantic/JSON Schema localmente.

json_object de Mistral aplica la forma JSON (no su esquema exacto) — valide en el lado del cliente.


5) AWS Bedrock — Esquema de Herramienta de API Converse (agnóstico al modelo)

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"}},  # fuerza el esquema
    messages=[{"role":"user","content":[{"text":
        "Extrae el evento de: 'PyData Sydney es el 2025-11-03 en Darling Harbour.'"}]}],
)

# Extrae el contenido de 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 la entrada de la herramienta contra su esquema JSON y muchos modelos alojados (p. ej., Claude) lo admiten a través de Converse.


Guía práctica y validación

  • Si desea las garantías más fuertes en el lado del servidor: salidas estructuradas de OpenAI o esquema de respuesta de Gemini.
  • Si ya usa Claude/Bedrock: defina una Herramienta con un esquema JSON y fuerce su uso; lea los argumentos de la herramienta como su objeto con tipo.
  • Si usa Mistral: habilite json_object y valide localmente (p. ej., con Pydantic).

Patrón de validación (funciona para todos)

from pydantic import BaseModel, ValidationError

class Event(BaseModel):
    title: str
    date: str
    location: str

try:
    event = Event.model_validate(data)  # `data` de cualquier proveedor
except ValidationError as e:
    # manejar / reintentar / pedir al modelo que corrija con e.errors()
    print(e)

Enlaces útiles

Suscribirse

Recibe nuevas publicaciones sobre sistemas, infraestructura e ingeniería de IA.