Conceptos básicos de salidas estructuradas
10 ejemplos para empezar con Salidas Estructuradas: 7 básicos y 3 intermedios.
Prerrequisitos
- Instala el SDK oficial:
pip install anthropic. - Configura tu clave API en el entorno:
export ANTHROPIC_API_KEY=sk-ant-.... - Opcional pero recomendado para definiciones de esquemas:
pip install pydantic. - Todos los ejemplos a continuación asumen
from anthropic import Anthropicyclient = Anthropic()a menos que se indique lo contrario.
Ejemplos básicos
1. Una solicitud mínima con esquema restringido
La llamada output_config.format más pequeña posible: un campo de cadena, garantizado como JSON válido.
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
output_config={
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {"greeting": {"type": "string"}},
"required": ["greeting"],
"additionalProperties": False,
},
}
},
messages=[{"role": "user", "content": "Di hola en francés."}],
)
print(response.content[0].text)output_config.formates lo que aplica la forma; el prompt en sí no necesita una instrucción de "devolver JSON".requiredyadditionalProperties: Falseson partes necesarias de un esquema bien formado, no extras opcionales.- El texto de la respuesta está garantizado como JSON válido que coincide con este esquema, pero sigue siendo una cadena; todavía llamas a
json.loads()en él aquí.
2. Usar client.messages.parse en lugar de create
Omite el paso manual json.loads() usando la utilidad de análisis del SDK.
from anthropic import Anthropic
client = Anthropic()
schema = {
"type": "object",
"properties": {
"language": {"type": "string"},
"greeting": {"type": "string"},
},
"required": ["language", "greeting"],
"additionalProperties": False,
}
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Di hola en francés."}],
)
print(response.parsed_output)client.messages.parsevalida la respuesta contra tu esquema y devuelve un valor analizado enresponse.parsed_output.- No se necesita ninguna llamada a
json.loads()en ningún lugar de este fragmento. - Este es el punto de entrada recomendado para la mayoría de las cargas de trabajo de salida estructurada en Python.
3. Definir el esquema con un modelo Pydantic
Usa Pydantic para definir la forma de destino una vez y reutilízala tanto para el esquema como para el tipo de resultado analizado.
from pydantic import BaseModel
from anthropic import Anthropic
class Greeting(BaseModel):
language: str
greeting: str
client = Anthropic()
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={
"format": {"type": "json_schema", "schema": Greeting.model_json_schema()}
},
messages=[{"role": "user", "content": "Di hola en francés."}],
)
greeting: Greeting = response.parsed_output
print(greeting.language, greeting.greeting)Greeting.model_json_schema()genera el Esquema JSON a partir del modelo Pydantic, por lo que no lo escribes a mano dos veces.response.parsed_outputaquí es una instancia real deGreeting, no un diccionario simple.- Este par (modelo Pydantic +
parse) es el patrón más común para la extracción estructurada en Python.
4. Solicitar una matriz de objetos
Los esquemas no se limitan a un solo objeto plano; solicita una lista de elementos estructurados en una sola llamada.
from anthropic import Anthropic
client = Anthropic()
schema = {
"type": "object",
"properties": {
"todos": {
"type": "array",
"items": {
"type": "object",
"properties": {
"task": {"type": "string"},
"done": {"type": "boolean"},
},
"required": ["task", "done"],
"additionalProperties": False,
},
}
},
"required": ["todos"],
"additionalProperties": False,
}
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Dame 3 elementos de tarea de ejemplo."}],
)
for item in response.parsed_output["todos"]:
print(item["task"], item["done"])- La respuesta de nivel superior sigue siendo un único objeto JSON; envuelve las matrices en un campo con nombre en lugar de devolver una matriz desnuda.
- Cada objeto anidado necesita su propio
requiredyadditionalProperties: False, no solo el exterior. - Este patrón es común para tareas de extracción del tipo "dame N elementos".
5. Usar una enumeración para restringir los valores de un campo
Restringe un campo a un conjunto fijo de valores en lugar de aceptar cualquier cadena.
from anthropic import Anthropic
client = Anthropic()
schema = {
"type": "object",
"properties": {
"sentiment": {"type": "string", "enum": ["positive", "neutral", "negative"]},
},
"required": ["sentiment"],
"additionalProperties": False,
}
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Clasifica: '¡Este producto superó mis expectativas!'"}],
)
print(response.parsed_output["sentiment"])enumgarantiza que el valor devuelto sea una de las cadenas enumeradas; no se necesita validación posterior de texto libre.- Este es el patrón estándar para respuestas de tipo clasificación.
- Las enumeraciones son una de las construcciones bien soportadas; consulta la referencia de tipos de campo antes de confiar en palabras clave de esquema menos comunes.
6. Comprobar stop_reason antes de confiar en la salida
Confirma siempre que la respuesta se haya completado realmente antes de tratarla como JSON completo.
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=256,
output_config={
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {"summary": {"type": "string"}},
"required": ["summary"],
"additionalProperties": False,
},
}
},
messages=[{"role": "user", "content": "Resume la trama de una novela de 300 páginas en detalle."}],
)
if response.stop_reason == "max_tokens":
print("La respuesta fue truncada - inténtalo de nuevo con un max_tokens mayor.")
else:
print(response.content[0].text)stop_reason == "max_tokens"significa que el modelo se quedó sin espacio antes de terminar; el JSON puede estar cortado a mitad de la estructura.- Una garantía de esquema solo se mantiene para una respuesta que realmente completó la generación.
- Comprobar
stop_reasonantes de analizar es un seguro económico contra unJSONDecodeErrorconfuso posterior.
7. Establecer un max_tokens generoso por adelantado
Reduce el riesgo de truncamiento para respuestas estructuradas más grandes dimensionando max_tokens a la salida esperada.
from anthropic import Anthropic
client = Anthropic()
schema = {
"type": "object",
"properties": {
"bullet_points": {"type": "array", "items": {"type": "string"}},
},
"required": ["bullet_points"],
"additionalProperties": False,
}
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=4096, # margen generoso para una respuesta de matriz con varios elementos
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Enumera 10 notas de lanzamiento detalladas para un lanzamiento v2.0."}],
)
print(response.parsed_output["bullet_points"])- Campos más grandes o más numerosos necesitan más margen de
max_tokensque una sola cadena corta. - Un
max_tokensdemasiado ajustado es la causa más común de salida estructurada truncada en la práctica. - Esta es una heurística inicial, no una garantía; combínala con la comprobación de
stop_reasondel Ejemplo 6 en código de producción.
Ejemplos intermedios
8. Un esquema de extracción de varios campos con objetos anidados
Combina varios tipos de campos, incluido un objeto anidado, en un único esquema de extracción.
from pydantic import BaseModel
from anthropic import Anthropic
class Address(BaseModel):
city: str
country: str
class Contact(BaseModel):
name: str
email: str
is_customer: bool
address: Address
client = Anthropic()
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=1024,
output_config={"format": {"type": "json_schema", "schema": Contact.model_json_schema()}},
messages=[{
"role": "user",
"content": (
"Extrae información de contacto: Jane Doe, jane@example.com, cliente "
"existente, vive en Austin, EE. UU."
),
}],
)
contact: Contact = response.parsed_output
print(contact.name, contact.address.city)- Los modelos Pydantic pueden anidarse entre sí, y
model_json_schema()los aplana en entradas$ref/$defque la API entiende. response.parsed_outputdevuelve un objetoContactcompletamente anidado y tipado, incluido elAddressanidado.- Se admiten esquemas anidados, pero el anidamiento muy profundo o recursivo no; mantén las estructuras poco profundas para mayor fiabilidad.
9. Reintentar en caso de truncamiento con un límite de tokens mayor
Detecta una respuesta estructurada truncada y reintenta automáticamente con más espacio.
from anthropic import Anthropic
client = Anthropic()
schema = {
"type": "object",
"properties": {"report": {"type": "string"}},
"required": ["report"],
"additionalProperties": False,
}
def get_report(max_tokens: int = 512) -> str:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=max_tokens,
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": "Escribe un informe de incidente detallado."}],
)
if response.stop_reason == "max_tokens" and max_tokens < 4096:
return get_report(max_tokens=max_tokens * 2)
return response.content[0].text
print(get_report())- El reintento duplica
max_tokenscada vez, limitado por un techo, en lugar de reintentar indefinidamente. - Este patrón pertenece a cualquier lugar donde el tamaño de una respuesta estructurada sea difícil de predecir de antemano.
- Consulta la página dedicada al manejo de truncamiento para obtener una versión más completa y lista para producción de este patrón.
10. Salida estructurada combinada con una definición de herramienta estricta
Empareja output_config.format con strict: true en una herramienta para que tanto la respuesta final como los parámetros de cualquier llamada a herramienta estén garantizados como válidos.
from anthropic import Anthropic
client = Anthropic()
tools = [{
"name": "log_ticket",
"description": "Registra un ticket de soporte en el sistema de seguimiento.",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"priority": {"type": "string", "enum": ["low", "medium", "high"]},
"summary": {"type": "string"},
},
"required": ["priority", "summary"],
"additionalProperties": False,
},
}]
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "El servidor está caído, los clientes no pueden realizar compras. Regístralo."}],
)
for block in response.content:
if block.type == "tool_use":
print(block.input) # garantizado que coincide con el input_schema estrictostrict: Trueen una definición de herramienta es el equivalente de uso de herramientas deoutput_config.formaten una respuesta de mensaje.- Ambas características se pueden usar en la misma solicitud cuando un flujo de trabajo necesita una respuesta final validada y parámetros de herramienta validados.
- Los esquemas
strictsiguen las mismas reglas derequired/additionalProperties: falseque los esquemasoutput_config.format.
Versiones de pila: Escrito contra la línea de modelos Claude actual a partir de ~junio de 2026: Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado) y Claude Haiku 4.5, y el SDK oficial de Python
anthropic(última versión 0.x). Los nombres de los modelos, las versiones del SDK y los precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.