DEV Community

Cover image for Cómo usar salidas estructuradas de OpenAI
Roobia
Roobia

Posted on • Originally published at apidog.com

Cómo usar salidas estructuradas de OpenAI

Al final de esta guía, podrás llamar a las salidas estructuradas de OpenAI desde tu propio código: pasar un esquema JSON al modelo, activar strict: true y recibir una respuesta que coincida con la forma solicitada. También verás cómo enviar la primera solicitud, leer la respuesta, manejar rechazos o truncamientos y generar colecciones de pruebas de API en Apidog para validar que la carga útil cumple el contrato.

Prueba Apidog hoy

Lo que necesitas antes de empezar

Las salidas estructuradas restringen la generación del modelo para que la respuesta se ajuste a un esquema JSON que tú defines. Cuando envías un esquema con strict: true, el modelo no puede devolver campos fuera de ese contrato: las claves requeridas están presentes, los tipos coinciden y los valores enumerados pertenecen a la lista permitida.

Esto evita depender de prompts como “responde solo con JSON”. Ese enfoque puede funcionar, pero también puede romperse con texto adicional, tipos incorrectos o campos faltantes. Con salidas estructuradas, el contrato pasa de ser una instrucción en lenguaje natural a una restricción aplicada durante la generación.

Para seguir los ejemplos necesitas:

  • Una clave API de OpenAI configurada como OPENAI_API_KEY.
  • Un modelo que admita aplicación estricta del esquema.
  • Un esquema JSON con la forma exacta que esperas recibir.

Elige el modelo adecuado

Las salidas estructuradas están disponibles en modelos recientes de OpenAI, empezando por la familia GPT-4o y continuando con la serie GPT-5. La documentación de OpenAI recomienda iniciar nuevos proyectos con su modelo insignia actual (gpt-5.5 al momento de escribir esto).

Los modelos más antiguos, incluidos los de la era gpt-3.5, pueden admitir modo JSON, pero no necesariamente aplicación estricta del esquema. Si dependes de strict: true, confirma que el ID exacto del modelo lo soporta antes de llevarlo a producción.

Hay dos opciones relacionadas que conviene distinguir:

  • Modo JSON: response_format: { "type": "json_object" }

    • Garantiza JSON sintácticamente válido.
    • No valida campos, tipos ni claves requeridas.
  • Salidas estructuradas estrictas: response_format con type: "json_schema" y strict: true

    • Garantizan JSON válido.
    • También garantizan que la salida coincida con tu esquema.
Modo JSON Salidas estructuradas estrictas
Parámetro response_format: {"type":"json_object"} response_format con type: "json_schema" y strict: true
JSON válido
Coincide con tu esquema No
Campos requeridos aplicados No
Tipos y enumeraciones aplicados No
Validación descendente Siempre necesaria Recomendable

Nota: Chat Completions usa response_format. La API de Responses expresa lo mismo bajo text.format con type: "json_schema". Las reglas del esquema son las mismas; cambia el envoltorio del endpoint.

Haz tu primera solicitud

Supongamos que quieres extraer un ticket de soporte desde texto libre y convertirlo en un registro tipado.

Ejemplo con Chat Completions:

curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [
      { "role": "system", "content": "Extract the ticket into the schema." },
      { "role": "user", "content": "My checkout 500s every time I use a saved card. Started today. Account: acct_8842." }
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "support_ticket",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "summary":  { "type": "string" },
            "category": { "type": "string", "enum": ["billing", "bug", "account", "other"] },
            "severity": { "type": "integer" },
            "account_id": {
              "anyOf": [ { "type": "string" }, { "type": "null" } ]
            }
          },
          "required": ["summary", "category", "severity", "account_id"],
          "additionalProperties": false
        }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Lee la respuesta

El modelo devuelve un mensaje cuyo content es una cadena JSON que coincide con el esquema:

{
  "summary": "Checkout returns HTTP 500 when paying with a saved card",
  "category": "bug",
  "severity": 3,
  "account_id": "acct_8842"
}
Enter fullscreen mode Exit fullscreen mode

Observa account_id: usa anyOf con null. Esa es la forma práctica de modelar un campo que puede no tener valor.

Mantente dentro del subconjunto compatible de JSON Schema

Las salidas estructuradas aceptan un subconjunto de JSON Schema. OpenAI limita el conjunto para poder aplicar las restricciones de forma confiable y cachear el esquema compilado.

Reglas importantes:

  • La raíz debe ser un objeto. No uses un array o string como nivel superior. Si necesitas una lista, envuélvela:
  {
    "items": []
  }
Enter fullscreen mode Exit fullscreen mode
  • Cada propiedad debe estar en required.

    No existe un campo opcional clásico. Para representar ausencia, usa anyOf con null.

  • Usa additionalProperties: false en cada objeto.

    Esto impide que el modelo invente claves adicionales.

  • Evita esquemas demasiado grandes o profundos.

    Un esquema puede contener aproximadamente 100 propiedades de objeto y hasta 5 niveles de anidamiento. Aplana cuando sea posible.

  • No todas las palabras clave de validación se aplican.

    Palabras como pattern, format, minLength o minimum no están garantizadas por el modelo. Si necesitas validar una expresión regular, un rango numérico o un formato concreto, hazlo después de recibir la respuesta.

  • La primera llamada puede ser más lenta.

    El primer uso de un esquema nuevo requiere compilación. Después se cachea y las siguientes llamadas suelen ser más rápidas.

“JSON garantizado” no significa “dato de negocio garantizado”. La estructura está bloqueada, pero los valores internos aún deben validarse. Si ya has trabajado con campos opcionales o uniones con oneOf/anyOf/allOf, el modelo mental es el mismo: el esquema restringe la forma; tus pruebas validan los valores.

Maneja rechazos y truncamientos

Hay casos donde la respuesta no coincidirá con tu esquema de forma intencional.

Si el modelo rechaza una solicitud insegura, devuelve un campo refusal en el mensaje en lugar del contenido con la forma esperada. Tu código debe comprobarlo antes de parsear JSON.

Ejemplo en Python:

import json

msg = response.choices[0].message

if msg.refusal:
    handle_refusal(msg.refusal)
else:
    ticket = json.loads(msg.content)
Enter fullscreen mode Exit fullscreen mode

También debes contemplar estos casos:

  • Truncamiento por max_tokens: el JSON puede quedar incompleto.
  • Llamadas a herramientas paralelas: las salidas estructuradas no las admiten. Si combinas herramientas con salidas estructuradas, configura parallel_tool_calls en false.

Cómo probarlo en Apidog

El modo estricto aplica el esquema durante la generación, pero no reemplaza tus pruebas. Los modelos cambian, los prompts se editan, los esquemas evolucionan y las rutas de rechazo pueden modificarse.

Ahí es donde Apidog encaja: valida la respuesta recibida contra el esquema esperado para detectar desviaciones antes de producción.

Un equipo discutiendo un problema de la API de OpenAI

División de responsabilidades:

  • OpenAI produce JSON válido según el esquema cuando usas strict: true.
  • Apidog valida la respuesta real contra tu contrato esperado.
  • Tus pruebas fallan si la carga útil deja de cumplir el esquema.

Flujo recomendado:

  1. Crea la solicitud.

    Construye la llamada a Chat Completions en Apidog, incluyendo el bloque response_format. Guárdala en una colección para repetirla.

  2. Añade aserciones.

    Verifica que:

    • category esté dentro de los valores permitidos.
    • severity sea un entero.
    • account_id sea string o null.
    • No existan propiedades inesperadas.

También puedes validar la respuesta contra un esquema JSON y reutilizar el mismo contrato que pasas a OpenAI.

  1. Ejecútalo en CI.

    Incluye la colección en tu pipeline. Cada cambio de prompt, modelo o esquema vuelve a comprobar la conformidad.

  2. Simula el contrato.

    Antes de conectar la llamada real, crea una API simulada que devuelva respuestas válidas según el esquema. Así puedes probar frontends, workers o consumidores descendentes sin gastar tokens.

Este último punto es especialmente útil: puedes desarrollar todo lo que consume la salida estructurada contra un mock estable y reemplazarlo por la llamada real cuando la integración esté lista. Descarga Apidog para construir la solicitud, las aserciones y el mock en un solo lugar.

Preguntas frecuentes

¿El modo JSON está obsoleto ahora que existen las salidas estructuradas?

No. El modo JSON sigue funcionando y garantiza JSON válido. Simplemente no aplica un esquema. Para código nuevo, las salidas estructuradas con strict: true son una opción más robusta cuando tienes una forma fija.

¿La raíz de mi esquema puede ser un array?

No. El nivel superior debe ser un objeto. Si necesitas devolver una lista, envuélvela en una propiedad:

{
  "items": []
}
Enter fullscreen mode Exit fullscreen mode

Luego incluye items en required.

¿Cómo hago que un campo sea opcional?

No uses opcionales clásicos. En salidas estructuradas, todas las propiedades deben estar en required. Modela la ausencia con null:

{
  "account_id": {
    "anyOf": [
      { "type": "string" },
      { "type": "null" }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

La clave siempre existe; el valor puede ser null.

¿Puedo omitir la validación si uso strict: true?

Puedes reducir validaciones de forma, pero no deberías eliminar todas las pruebas. El modelo no garantiza reglas como pattern, format o rangos numéricos, y aún debes manejar rechazos o truncamientos.

Si necesitas repasar los fundamentos, esta introducción a JSON Schema cubre los bloques principales.

¿Qué modelos debo usar?

Usa modelos que soporten salidas estructuradas estrictas. Funcionan en GPT-4o y posteriores, incluida la serie GPT-5. Confirma siempre el ID exacto del modelo antes de confiar en strict: true.

Conclusión

El flujo completo queda así:

  1. Elige un modelo compatible con salidas estructuradas.
  2. Envía una solicitud con json_schema y strict: true.
  3. Mantén tu esquema dentro del subconjunto soportado.
  4. Maneja refusal, truncamientos y límites de herramientas.
  5. Valida la respuesta en tus pruebas y CI.

El modelo promete la forma. Tus pruebas demuestran que esa forma se mantiene. Puedes hacerlo en Apidog: construye la solicitud, valida la respuesta contra tu esquema y crea mocks para que el resto de tu sistema avance mientras la integración se estabiliza.

Top comments (0)