Comparación de salida estructurada entre proveedores populares de LLM - OpenAI, Gemini, Anthropic, Mistral y AWS Bedrock
Las APIs ligeramente diferentes requieren un enfoque especial.
Aquí tienes una comparación de soporte lado a lado de salida estructurada (obtener JSON confiable) entre proveedores populares de LLM, más ejemplos mínimos en Python
Ya hemos visto cómo solicitar salida estructurada del LLM alojado en Ollama. Aquí revisamos cómo solicitar lo mismo de otros proveedores.
TL;DR matriz
Proveedor | Modo “JSON” nativo | Cumplimiento de esquema JSON | Knob típico | Notas |
---|---|---|---|---|
OpenAI | Sí | Sí (primera clase) | response_format={"type":"json_schema", ...} |
Funciona a través de la API de Respuestas o Completions de Chat; también se puede hacer llamadas a funciones. |
Google Gemini | Sí | Sí (primera clase) | response_schema= + response_mime_type="application/json" |
Devuelve JSON validado estrictamente cuando se establece el esquema. |
Anthropic (Claude) | Indirecto | Sí (a través de Uso de Herramienta con esquema JSON) | tools=[{input_schema=...}] + tool_choice |
Obliga al modelo a “llamar” a su herramienta definida por el esquema; genera argumentos con forma de esquema. |
Mistral | Sí | Parcial (solo JSON; sin esquema en el servidor) | response_format={"type":"json_object"} |
Asegura JSON, pero validas contra tu esquema en el lado del cliente. |
AWS Bedrock (plataforma) | Varía según el modelo | Sí (a través del esquema de Herramienta/Converse) | toolConfig.tools[].toolSpec.inputSchema |
La API de 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 estrictamente se adhieran a un formato o estructura predefinida, 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áquinas, coherentes y fácilmente analizables por software para su uso en diversas aplicaciones.
Las salidas estructuradas difieren de las salidas tradicionales de LLM, que normalmente generan texto natural abierto. En cambio, las salidas estructuradas imponen un esquema o formato, como objetos JSON con claves y tipos de valor definidos, o clases específicas en la salida (por ejemplo, respuestas de opción múltiple, clases de sentimiento o formatos de filas de base de datos). Este enfoque mejora la confiabilidad, reduce errores y alucinaciones, y simplifica la integración en sistemas como bases de datos, APIs o flujos de trabajo.
La generación de salidas estructuradas en LLM a menudo implica técnicas como:
- Especificar instrucciones detalladas en el prompt para guiar al modelo para que produzca la salida en el formato deseado.
- Usar 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 máquinas de estado finito para asegurar el cumplimiento del formato a nivel de token.
Ventajas de las salidas estructuradas de LLM incluyen:
- Legibilidad por máquinas y facilidad de integración.
- Reducción de variabilidad y errores.
- Mejor predictibilidad y verificabilidad para tareas que requieren formatos de datos consistentes.
Los desafíos incluyen diseñar esquemas efectivos, manejar 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 LLM sean más útiles en aplicaciones que requieren datos precisos y formateados, en lugar de solo texto legible por humanos.
Ejemplos de salida estructurada en Python
Todos los fragmentos extraen información de evento como JSON: {título, fecha, ubicación}
. Reemplaza las claves/modelos según tus necesidades.
1) OpenAI — Esquema JSON (estricto)
from openai import OpenAI
import json
client = OpenAI()
schema = {
"name": "Evento",
"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 Salidas Estructuradas de OpenAI impone 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
# Configura con tu clave API
# genai.configure(api_key="tu-clave-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 se ajusta a response_schema
.
3) Anthropic (Claude) — Uso de herramienta con esquema JSON
from anthropic import Anthropic
import json
client = Anthropic()
tool = {
"name": "extract_event",
"description": "Devolver 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"}, # forzar esquema
messages=[{"role": "user", "content":
"Extrae el evento de: 'PyData Sydney es el 2025-11-03 en Darling Harbour.'"}],
)
# Claude "llamará" a la herramienta; obtén los argumentos (que coinciden con tu 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” general; en su lugar, Uso de Herramienta con un input_schema
te da argumentos validados con forma de esquema (y puedes 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 claves título, fecha (YYYY-MM-DD), ubicación 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: valora `data` contra tu esquema Pydantic/JSON localmente.
El json_object
de Mistral impone forma JSON (no tu esquema exacto) — valora en el lado del cliente.
5) AWS Bedrock — esquema de herramienta de API Converse (modelo-agnostic)
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"}}, # forzar esquema
messages=[{"role":"user","content":[{"text":
"Extrae el evento de: 'PyData Sydney es el 2025-11-03 en Darling Harbour.'"}]}],
)
# Extraer contenido de uso de herramienta
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 entrada de herramienta contra tu esquema JSON y muchos modelos alojados (por ejemplo, Claude) lo admiten a través de Converse.
Guía práctica y validación
- Si deseas las garantías más fuertes del lado del servidor: Salidas estructuradas de OpenAI o esquema de respuesta de Gemini.
- Si ya estás en Claude/Bedrock: define una Herramienta con un esquema JSON y fuerza su uso; lee los argumentos de la herramienta como tu objeto tipado.
- Si usas Mistral: habilita
json_object
y valora localmente (por ejemplo, con Pydantic).
Patrón de validación (funciona para todos ellos)
from pydantic import BaseModel, ValidationError
class Evento(BaseModel):
title: str
date: str
location: str
try:
evento = Evento.model_validate(data) # `data` de cualquier proveedor
except ValidationError as e:
# manejar / reintentar / pedir al modelo que lo corrija con e.errors()
print(e)
Enlaces útiles
- 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
- Cómo solicitar salida estructurada del LLM alojado en Ollama
- Hoja de trucos de Python
- AWS SAM + AWS SQS + Python PowerTools
- Comparación de rendimiento de AWS Lambda: JavaScript vs Python vs Golang