# Claude Structured Outputs: JSON válido con output_config.format

> Pon tu JSON Schema en output_config.format y Claude responde con JSON parseable en el bloque text. Lo que el esquema no garantiza se valida en tu código.

- URL: https://blog.laozhang.ai/es/posts/claude-structured-output
- Published: 2026-10-30
- Updated: 2026-10-30
- Author: LaoZhang AI Team (https://blog.laozhang.ai/es/about)
- Topic: Guías de API
- Tags: Claude, Claude API, Structured Outputs, JSON Schema, Pydantic

---
Sí: Claude tiene structured outputs (salidas estructuradas) y, a 30 de octubre de 2026, son una función estable de la Messages API. Para recibir JSON que tu código pueda parsear sin retoques, envía tu JSON Schema en `output_config.format` con `"type": "json_schema"`: Claude escribe el JSON en el bloque `text` de la respuesta, y en Python `client.messages.parse()` lo devuelve ya validado en `parsed_output`. No hace falta cabecera beta y no existe un «modo JSON» aparte. Si lo que necesitas es que Claude llame a una función con argumentos del tipo correcto, la pieza es otra: `"strict": true` en la definición de la herramienta.

Los ejemplos antiguos usan un campo `output_format` en la raíz de la petición y la cabecera `anthropic-beta: structured-outputs-2025-11-13`. Ese campo está obsoleto: según la documentación de Anthropic, sin la cabecera la API devuelve un 400, pero en una prueba del 30 de octubre de 2026 a través de LaoZhang API devolvió 200 con un texto normal, como si el esquema no existiera. Por eso, cuando llames a Claude a través de un proxy, comprueba dos cosas en la primera respuesta: que el texto empiece por `{` y que `input_tokens` haya subido respecto a la misma petición sin esquema.

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

«Siempre válido» tiene límites. Palabras clave como `minimum` devuelven un 400, `minLength` se aceptó en esa misma pasarela sin aplicarse, y un rechazo o un corte por `max_tokens` llegan con código 200 y JSON incompleto. Los rangos, longitudes y reglas de negocio se validan en tu código después de la llamada.

## Petición mínima en cURL: output_config.format y dónde llega el JSON

La petición es un `POST /v1/messages` normal con un objeto `output_config.format` que contiene tu esquema. La respuesta no trae un campo especial: el JSON llega como cadena dentro de `content[0].text`, con `stop_reason: "end_turn"`, y tu código lo parsea con `json.loads` o `JSON.parse`.

Esta es la llamada directa a la API de Anthropic, con el esquema de contacto de cuatro campos que usa la [documentación de structured outputs de Claude](https://platform.claude.com/docs/en/build-with-claude/structured-outputs):

```bash
curl https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-haiku-5-5",
    "max_tokens": 1024,
    "messages": [{
      "role": "user",
      "content": "Extract the key information from this email: John Smith (john@example.com) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
    }],
    "output_config": {
      "format": {
        "type": "json_schema",
        "schema": {
          "type": "object",
          "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "plan_interest": {"type": "string"},
            "demo_requested": {"type": "boolean"}
          },
          "required": ["name", "email", "plan_interest", "demo_requested"],
          "additionalProperties": false
        }
      }
    }
  }'
```

Las pruebas citadas a partir de aquí se hicieron el 30 de octubre de 2026 a través de LaoZhang API, en su endpoint compatible con Anthropic `https://api.laozhang.ai/v1/messages`, con el mismo cuerpo y una clave de esa plataforma en lugar de la de Anthropic. Con `claude-haiku-5-5`, la petición anterior devolvió 200 en 3,61 segundos y esta respuesta (recortada):

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

```json
{
  "content": [{
    "type": "text",
    "text": "{\"demo_requested\": true, \"email\": \"john@example.com\", \"name\": \"John Smith\", \"plan_interest\": \"Enterprise\"}"
  }],
  "model": "claude-haiku-5-5",
  "stop_reason": "end_turn",
  "usage": {"input_tokens": 333, "output_tokens": 46}
}
```

![Petición con output_config.format, respuesta 200 con el JSON como cadena en el bloque text y stop_reason end_turn, y el paso de parseo con json.loads o messages.parse()](https://blog.laozhang.ai/posts/es/claude-structured-output/img/respuesta-json-content-text.webp)

Fíjate en dos detalles. El JSON es una cadena escapada dentro de `text`, no un objeto anidado, así que siempre hay un paso de parseo. Y las claves salieron en orden alfabético, no en el orden del esquema; más abajo se explica por qué no debes depender del orden. Los resultados de la pasarela pueden no coincidir con los de `api.anthropic.com`: la documentación de LaoZhang indica que parte de su tráfico de Claude pasa por un canal oficial de AWS que valida los campos de la petición con más rigor. Cuando la documentación de Anthropic describe otro comportamiento, se dan las dos versiones.

## messages.parse() en Python y TypeScript: el JSON ya validado

Los SDK oficiales hacen tres cosas por ti: convierten tu modelo de Pydantic o de zod en un esquema que Claude acepta, lo envían en `output_config.format` y validan la respuesta contra el modelo original. El resultado tipado está en `parsed_output`.

### Python: Pydantic, transform_schema y ValidationError

En Python, pasa la clase de Pydantic al argumento `output_format` de `client.messages.parse()`. Ese nombre es el del helper del SDK y es el actual; lo obsoleto es el campo `output_format` en la raíz del cuerpo JSON de la petición. Este ejemplo se ejecutó el 30 de octubre de 2026 con `anthropic` 2.3.0 y Pydantic 2.14:

```python
from typing import Literal, Optional

import anthropic
from pydantic import BaseModel, Field


class Lead(BaseModel):
    name: str = Field(min_length=2)
    email: str
    plan: Literal["Starter", "Team", "Enterprise"]
    seats: int = Field(ge=1, le=500)
    phone: Optional[str] = None


client = anthropic.Anthropic()  # lee ANTHROPIC_API_KEY

resp = client.messages.parse(
    model="claude-haiku-5-5",
    max_tokens=512,
    messages=[{"role": "user", "content": "John Smith (john@example.com) wants the Enterprise plan for 40 seats."}],
    output_format=Lead,
)
print(resp.parsed_output.model_dump())
# {'name': 'John Smith', 'email': 'john@example.com', 'plan': 'Enterprise', 'seats': 40, 'phone': None}
```

Para la prueba se creó el cliente con `anthropic.Anthropic(api_key=..., base_url="https://api.laozhang.ai")`; la llamada consumió 489 tokens de entrada. Lo interesante es lo que el SDK envió. `transform_schema(Lead)`, que devuelve el esquema transformado sin hacer ninguna llamada, muestra que `min_length`, `ge` y `le` no viajan como restricciones: el SDK los quita y los copia en la descripción del campo, y añade `additionalProperties: false` al objeto.

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

```json
"name":  {"type": "string",  "title": "Name",  "description": "{minLength: 2}"},
"seats": {"type": "integer", "title": "Seats", "description": "{maximum: 500, minimum: 1}"}
```

Claude ve esos límites como una pista de texto, no como una regla del muestreo. La prueba lo deja claro: con el mensaje «Jane Roe (jane@example.com) is on the Team plan but currently has 0 seats. Report seats exactly as stated.», la API devolvió `seats: 0` y fue el SDK, ya en tu proceso, quien lanzó un `pydantic.ValidationError` con el texto `Input should be greater than or equal to 1`. Si llamas a `messages.parse()`, captura esa excepción: es la forma en que una regla de negocio incumplida llega a tu código.

### TypeScript: zodOutputFormat()

En TypeScript el equivalente es envolver un esquema de zod con `zodOutputFormat()` y pasarlo en `output_config.format` a `client.messages.parse()`. Este fragmento es el de la documentación de Anthropic:

```typescript
import Anthropic from "@anthropic-ai/sdk";
import { z } from "zod";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

const ContactInfo = z.object({
  name: z.string(),
  email: z.string(),
  plan_interest: z.string(),
  demo_requested: z.boolean(),
});

const client = new Anthropic();

const response = await client.messages.parse({
  model: "claude-haiku-5-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Extract the key information from this email: ..." }],
  output_config: { format: zodOutputFormat(ContactInfo) },
});

console.log(response.parsed_output);
```

Si en lugar de zod tienes un JSON Schema suelto, `jsonSchemaOutputFormat()` lo transforma igual pero no valida la respuesta, así que la validación vuelve a ser cosa tuya. El SDK de Java se comporta al revés que los de Python y TypeScript: rechaza en local las restricciones no admitidas en vez de moverlas a la descripción.

## ¿JSON outputs o herramienta con strict: true? Cuándo usar cada uno

Usa JSON outputs cuando el JSON es la respuesta final (extraer datos, clasificar, devolver un informe), y una herramienta con `"strict": true` cuando tu código va a ejecutar una acción con los argumentos que elige Claude. Un agente que llama a herramientas y luego entrega un resultado estructurado usa las dos en la misma petición.

| Criterio | JSON outputs | Herramienta con `strict: true` |
| --- | --- | --- |
| Qué restringe | El texto de la respuesta de Claude | El nombre de la herramienta y su `input` |
| Cómo se activa | `output_config.format` en la petición | `"strict": true` en cada definición de herramienta |
| Dónde llega el JSON | Bloque `text`, con `stop_reason: "end_turn"` | Bloque `tool_use`, campo `input`, con `stop_reason: "tool_use"` |
| Caso típico | Extracción, clasificación, informe final | Reservar, escribir en una base de datos, llamar a otra API |
| Límites propios | Comparte el subconjunto de JSON Schema | Máximo 20 herramientas strict por petición |

La diferencia práctica está en qué pasa sin `strict`. Según la [guía de strict tool use de Anthropic](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use), una herramienta normal que espera `passengers` como entero puede recibir `"two"` o `"2"`; con `strict: true` siempre recibe `2`. En la prueba del 30 de octubre de 2026 a través de LaoZhang API, una herramienta `create_demo_booking` con `strict: true`, enums para el plan y el día, un entero `hour_24` y `"format": "email"`, forzada con `tool_choice`, devolvió `stop_reason: "tool_use"` y este `input` a partir del mismo correo de ejemplo:

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

```json
{"email": "john@example.com", "hour_24": 14, "plan": "Enterprise", "weekday": "Tue"}
```

«2pm» se convirtió en el entero 14 y «next Tuesday» en el valor de enum `Tue`, que es justo el tipo de normalización que te ahorra código. Cuando combines las dos funciones, recuerda que los límites de complejidad se suman entre todos los esquemas strict de la petición: 24 parámetros opcionales y 16 parámetros con uniones (`anyOf` o `"type": ["string", "null"]`) en total. Por eso Anthropic recomienda marcar como strict solo las herramientas en las que un argumento mal tipado rompe algo.

## Qué palabras del esquema dan 400 y cuáles se aceptan sin aplicarse

Claude solo admite un subconjunto de JSON Schema, y lo que queda fuera se comporta de tres maneras: la API lo rechaza con un 400 y un mensaje concreto, el SDK lo saca del esquema y lo comprueba en local, o (según la prueba en la pasarela) se acepta sin aplicarse. En los tres casos, la regla acaba en tu código.

Lo admitido, según la documentación a 30 de octubre de 2026: los tipos básicos, `enum` con valores primitivos, `const`, `anyOf`, `allOf` (sin `$ref` dentro), `$ref` y `$defs` internos, `default`, `required`, `additionalProperties: false`, `pattern` con expresiones sencillas y los formatos `date-time`, `time`, `date`, `duration`, `email`, `hostname`, `uri`, `ipv4`, `ipv6` y `uuid`. Lo que no está en esa lista es lo que recoge la tabla.

| Palabra clave | Documentación de Anthropic | LaoZhang API, 30/10/2026 | Qué hacer |
| --- | --- | --- | --- |
| `minimum`, `maximum`, `multipleOf` | No admitidas, 400 | `minimum: 1` → 400 `output_config.format.schema: For 'integer' type, property 'minimum' is not supported` | Quitarlas y validar el rango en código |
| `$ref` recursivo | No admitido | 400 `Invalid schema: Circular reference detected in schema definitions: node -> node. Self-referencing or mutually-referencing definitions are not supported.` | Aplanar a una profundidad fija |
| `minLength`, `maxLength` | No admitidas, 400 | Aceptadas con 200; con mínimo y máximo de 12 devolvió `{"code": "ABC"}` | No confiar en ellas: validar la longitud |
| Objeto sin `additionalProperties` | Debe ser `false` | Aceptado, salida correcta | Escribir `false` siempre |
| `enum` con objetos o arrays | No admitido | — | Usar `anyOf` o valores primitivos |
| `minItems` mayor que 1, `maxItems` | Solo `minItems` 0 o 1 | — | Contar los elementos en código |
| `pattern` con `\b`, lookahead o `\1` | No admitidos; patrones complejos pueden dar 400 | — | Simplificar la regex y revalidar |

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

Las dos filas con resultado distinto según la ruta son las peligrosas. Que `minLength` pase en una plataforma y dé 400 en otra significa que el mismo esquema puede funcionar en desarrollo y romperse al cambiar de proveedor, y que donde pasa no protege nada. Si usas los helpers de Python o TypeScript, este problema desaparece porque el SDK quita esas restricciones antes de enviar y las comprueba después; si envías el esquema a mano, quítalas tú.

Además de las palabras clave, hay límites de tamaño por petición: 20 herramientas strict, 24 parámetros opcionales y 16 parámetros con uniones, sumando todos los esquemas. Por encima de eso, o si la gramática compilada resulta demasiado grande, la API responde con un 400 `Schema is too complex for compilation`, y la compilación tiene un tiempo máximo de 180 segundos. Si llegas a ese error, Anthropic propone probar en este orden: marcar como strict solo las herramientas críticas, convertir parámetros opcionales en `required` (cada parámetro opcional duplica aproximadamente una parte de la gramática), aplanar los objetos anidados y repartir las herramientas entre varias peticiones.

## ¿Por qué Claude devuelve texto en vez de JSON?

Si la respuesta llega con 200 pero en prosa, casi siempre el esquema no ha llegado al modelo: el campo tiene el nombre antiguo, la plataforma lo ha descartado o la petición mezcla algo incompatible. La causa depende de por dónde pasa la llamada, así que la comprobación empieza por los tokens de entrada.

El caso más traicionero es el retroceso silencioso. El 30 de octubre de 2026, a través de LaoZhang API, la misma petición con el campo antiguo `output_format` en la raíz devolvió 200 y una lista en Markdown, tanto sin la cabecera `anthropic-beta: structured-outputs-2025-11-13` como con ella. Los tokens de entrada fueron 64, exactamente los de la petición sin esquema, frente a los 333 de la versión con `output_config.format`: el esquema se había descartado antes de llegar al modelo. En la API directa, la documentación de Anthropic dice que ese campo sin la cabecera beta devuelve un 400, y el SDK de Python 1.0 o posterior lanza un `TypeError` si pasas `output_format={...}` a `client.beta.messages.create()`.

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

![Comparación de la misma petición: con output_format en la raíz llega una lista en Markdown y 64 tokens de entrada; con output_config.format llega JSON y 333 tokens](https://blog.laozhang.ai/posts/es/claude-structured-output/img/retroceso-silencioso-output-format.webp)

Antes de tocar el prompt, revisa esta lista en orden:

1. El esquema va en `output_config.format`, no en `output_format`, y sin cabeceras beta copiadas de tutoriales de 2025.
2. `usage.input_tokens` sube cuando añades el esquema. Si da lo mismo con y sin esquema, el campo no está llegando.
3. Si recibes un 400 con `Extra inputs are not permitted` (por ejemplo, mencionando `output_config` o `output_config.effort`), la plataforma valida el cuerpo y rechaza ese campo. Pasa en Bedrock y en pasarelas que reenvían a canales de AWS; los mensajes típicos están en [Error 400 de Claude en AWS Bedrock: qué significa cada mensaje](https://blog.laozhang.ai/es/posts/aws-claude-400-error).
4. El modelo está en la lista compatible. Claude 3.x y las versiones de la época de Opus 4.1 no aparecen en ella.
5. La conversación termina en un mensaje de usuario. El prefill (empezar la respuesta del asistente con `{`) es incompatible con JSON outputs, y en Haiku 5.5 la petición devolvió un 400: `This model does not support assistant message prefill. The conversation must end with a user message.`
6. Citations no está activado: junto con `output_config.format` devuelve un 400.

## Rechazos, cortes por max_tokens y nulls: qué validar en tu código

Un JSON que cumple el esquema no es lo mismo que un JSON que tu aplicación puede usar. Hay casos en los que la respuesta llega con 200 y no encaja, y otros en los que encaja con el esquema pero no con lo que tu código espera; cada uno necesita una línea de defensa propia.

| Caso | Cómo se ve | Qué hace tu código |
| --- | --- | --- |
| Rechazo | `stop_reason: "refusal"`, código 200, tokens facturados, salida que puede no cumplir el esquema | No parsear; registrar y no reintentar igual |
| Corte por `max_tokens` | `stop_reason: "max_tokens"` y JSON a medias | Reintentar con más `max_tokens` |
| Regla de negocio incumplida | JSON válido con un valor fuera de rango, como `seats: 0` | Validar con Pydantic, zod o tu propio código |
| Orden de claves | Documentación: requeridas primero, en el orden del esquema; pasarela: orden alfabético | Leer por nombre, nunca por posición |
| Campo opcional | En la pasarela, `"phone": null` aunque el esquema decía `"type": "string"` | Tratar opcional como «ausente o null» |
| Mayúsculas en `enum` | Documentación: puede llegar `Conversation Topic 3` con el enum `Conversation topic 3` | Comparar sin distinguir mayúsculas |

El corte es fácil de provocar. Con `max_tokens: 30` y la petición de 15 ideas para artículos, la respuesta del 30 de octubre de 2026 a través de LaoZhang API terminó con `stop_reason: "max_tokens"` y este texto, que ningún parser acepta: `{"ideas": ["REST vs GraphQL vs gRPC: How to Choose the`. El rechazo tiene un disparador menos obvio: según la documentación, una propiedad que pide el razonamiento paso a paso puede provocar un rechazo de tipo `reasoning_extraction`, así que si quieres una justificación, pide un campo de explicación breve.

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

Las tres últimas filas son de forma, no de contenido. En la misma pasarela, todas las salidas JSON llegaron con las claves en orden alfabético, y en un esquema con `name` y `email` obligatorios y `notes` y `phone` opcionales, la respuesta incluyó `"phone": null` en lugar de omitir el campo. Las mayúsculas del enum, en cambio, no fallaron: en cinco llamadas pidiendo el tercer valor llegó siempre `Conversation topic 3` exacto, pero cinco intentos no prueban nada frente a lo que advierte Anthropic, y la comparación sin mayúsculas cuesta una línea.

Este patrón cubre los dos primeros casos con un reintento y deja la validación de contenido a Pydantic:

```python
import json

import anthropic
from pydantic import BaseModel, ValidationError


class Contact(BaseModel):
    name: str
    email: str
    plan_interest: str
    demo_requested: bool


SCHEMA = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "email": {"type": "string"},
        "plan_interest": {"type": "string"},
        "demo_requested": {"type": "boolean"},
    },
    "required": ["name", "email", "plan_interest", "demo_requested"],
    "additionalProperties": False,
}

client = anthropic.Anthropic()


def extract(text: str, max_tokens: int = 1024) -> Contact:
    for _ in range(2):
        resp = client.messages.create(
            model="claude-haiku-5-5",
            max_tokens=max_tokens,
            messages=[{"role": "user", "content": text}],
            output_config={"format": {"type": "json_schema", "schema": SCHEMA}},
        )
        if resp.stop_reason == "max_tokens":
            max_tokens *= 2  # JSON cortado: otro intento con más margen
            continue
        if resp.stop_reason == "refusal":
            raise RuntimeError("Claude rechazó la petición")
        raw = next(b.text for b in resp.content if b.type == "text")
        try:
            return Contact.model_validate(json.loads(raw))
        except (json.JSONDecodeError, ValidationError) as err:
            # aquí cae también el texto en prosa de un retroceso silencioso
            raise ValueError(f"Respuesta fuera de contrato: {raw[:200]}") from err
    raise RuntimeError("La respuesta sigue cortada por max_tokens")
```

## Coste del prompt de formato: 269 tokens más por petición

Activar `output_config.format` añade un prompt de sistema que explica el formato, y esos tokens se facturan como entrada. Con un esquema de 4 campos en Haiku 5.5, la diferencia medida el 30 de octubre de 2026 a través de LaoZhang API fue de 269 tokens por petición.

*Aviso: [laozhang.ai es un servicio propio](https://blog.laozhang.ai/es/about#laozhang). Sus precios son nuestra tarifa, no una comparación independiente.*

La cifra sale de comparar la misma petición con y sin esquema: 333 tokens de entrada con `output_config.format` y 64 sin él, así que 333 − 64 = 269 tokens de prompt de formato más esquema. Un millón de peticiones suma 269 millones de tokens extra, que se multiplican por el precio de entrada de cada modelo según la tabla de precios de Anthropic; el precio de Haiku 5.5 vale para prompts de hasta 100.000 tokens y por encima sube a 0,50 $:

| Modelo | Entrada por millón de tokens | Coste extra por millón de peticiones |
| --- | ---: | ---: |
| Haiku 5.5 | 0,10 $ | 26,90 $ |
| Sonnet 5.5 | 2 $ | 538 $ |
| Opus 5.5 | 4 $ | 1.076 $ |

Es una muestra con un esquema pequeño: cuantos más campos y descripciones tenga, más crece la diferencia. En esa misma muestra la salida bajó de 91 tokens en prosa a 46 en JSON; en Sonnet 5.5, a 10 $ por millón de tokens de salida, esos 45 tokens ahorrados valen 0,00045 $ por llamada frente a 0,000538 $ de entrada extra, así que el balance final depende de cuánto hablaría Claude sin formato. Para comparar el precio por modelo con OpenAI, mira [Precio de la API de Claude vs OpenAI: qué nivel sale más barato](https://blog.laozhang.ai/es/posts/claude-api-vs-openai-api-pricing).

Hay dos costes más que no son de tokens. Cambiar `output_config.format` invalida la caché de prompts de esa conversación, así que mantén el esquema estable entre llamadas que comparten prefijo. Y la primera vez que usas un esquema, la API compila la gramática, lo que añade latencia; la gramática se guarda 24 horas desde el último uso y solo se recompila si cambia la estructura, no si cambias nombres o descripciones. A través de la pasarela esa penalización no se distinguió del ruido de red: un esquema nuevo y dos repeticiones idénticas tardaron 4,23, 3,33 y 4,28 segundos.

## Preguntas frecuentes sobre Claude Structured Outputs

### ¿Claude Structured Outputs funciona con streaming y Batch?

Sí. Según la documentación de Anthropic a 30 de octubre de 2026, funciona con streaming (el JSON llega por fragmentos como cualquier texto, así que lo parseas al terminar), con el conteo de tokens y con la Message Batches API, que aplica su descuento del 50 %.

### ¿Se puede usar con extended thinking?

Sí. La gramática solo restringe la respuesta final, no los bloques de thinking ni las llamadas a herramientas, así que Claude puede razonar libremente y después escribir el JSON. En una prueba del 30 de octubre de 2026 a través de LaoZhang API, Sonnet 5.5 con `thinking: {"type": "adaptive"}` y `effort: "low"` devolvió solo el bloque de texto, con JSON válido; con esfuerzo bajo no generó bloque de thinking.

### ¿Está disponible en Amazon Bedrock y Google Cloud Vertex AI?

Sí. La documentación la marca como disponible de forma general en la Claude API, Claude Platform on AWS, Amazon Bedrock (incluido InvokeModel), Claude en Google Cloud (gestionado por Anthropic o por Google) y Microsoft Foundry. No está disponible en Managed Agents.

### ¿Qué modelos de Claude admiten structured outputs?

A 30 de octubre de 2026, la lista oficial incluye Fable 5.1 y 5, Mythos 5.1, 5 y preview, Opus 5.5, 5, 4.8, 4.7, 4.6 y 4.5, Sonnet 5.5, 5, 4.6 y 4.5, y Haiku 5.5 y 4.5. Los modelos Claude 3.x no figuran.

### ¿Qué pasa con los datos si uso ZDR o HIPAA?

Con retención cero (ZDR), los prompts y las respuestas no se guardan; solo el esquema JSON se almacena en caché hasta 24 horas desde su último uso. La función es apta para HIPAA, pero los datos de salud protegidos no pueden aparecer en el esquema: ni en nombres de propiedades, ni en valores de `enum` o `const`, ni en `pattern`.

### ¿Es lo mismo que los structured outputs de Claude Code o del Agent SDK?

No. En el Agent SDK pasas un JSON Schema a `query()` con `outputFormat` (TypeScript) u `output_format` (Python), y el propio SDK valida el resultado y vuelve a preguntar si no encaja; está explicado en la [guía de structured outputs del Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/structured-outputs).

### ¿En qué se diferencia de Structured Outputs de OpenAI?

La idea es la misma, pero los campos y la forma de elegir entre formato de respuesta y funciones son distintos; para el lado de OpenAI, consulta [Structured Outputs vs. function calling: qué usar en OpenAI](https://blog.laozhang.ai/es/posts/structured-outputs-vs-function-calling).

## Fuentes

Páginas externas que cita esta guía, en el orden en que aparecen. Última actualización: 2026-10-30.

- [documentación de structured outputs de Claude](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) (platform.claude.com)
- [guía de strict tool use de Anthropic](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use) (platform.claude.com)
- [guía de structured outputs del Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/structured-outputs) (code.claude.com)
