Qué es Pydantic
Pydantic es una librería de Python que permite definir la estructura de los datos mediante clases y anotaciones de tipo, y validar automáticamente que cualquier valor que recibimos cumple ese esquema declarado. Gracias a esta validación basada en tipos, el código que consume datos externos (APIs, bases de datos o modelos de lenguaje) resulta más fiable y sencillo de razonar.
En el contexto de las salidas estructuradas de OpenAI, Pydantic actúa como un contrato entre lo que promete el modelo y lo que realmente entregamos a nuestro código de negocio, evitando errores silenciosos cuando falta un campo, llega con un tipo incorrecto o tiene un valor fuera de rango. De esta manera, el modelo sigue generando texto, pero nuestra aplicación recibe siempre objetos Python bien formados.
Para usar Pydantic con el SDK de Python de OpenAI basta con instalar ambas dependencias en el entorno de trabajo:
pip install openai pydantic
El concepto central de Pydantic es el modelo (clase que hereda de BaseModel), donde definimos atributos tipados que describen la forma de los datos que esperamos recibir. Cada atributo tiene un tipo (por ejemplo, str, int o listas y modelos anidados) y Pydantic se encarga de convertir y validar valores de entrada contra esa definición.
Por ejemplo, si queremos representar los datos de una persona que podrían llegar en formato JSON desde un servicio externo, podemos definir un modelo sencillo con BaseModel:
from pydantic import BaseModel
class Persona(BaseModel):
nombre: str
edad: int
email: str
Cuando construimos una instancia de este modelo, Pydantic convierte y valida automáticamente los tipos, lanzando una excepción clara si algo no encaja:
datos = {"nombre": "Ana", "edad": "30", "email": "ana@example.com"}
persona = Persona(**datos)
print(persona.edad) # 30, convertido a int automáticamente
Si un campo obligatorio falta o tiene un tipo incompatible, Pydantic genera un mensaje de error estructurado que resulta especialmente útil cuando la fuente de datos es un modelo de lenguaje cuyo output podría variar. Esta combinación (modelo bien definido + errores claros) es lo que lo hace tan adecuado para trabajar con salidas estructuradas.
Además, Pydantic ofrece varias capacidades muy útiles cuando lo combinamos con el SDK de OpenAI:
- 1. Validación de tipos: asegura que cada campo tenga el tipo correcto (
int,str, listas, enumeraciones, etc.), reduciendo errores en tiempo de ejecución. - 2. Modelos anidados: permite componer estructuras complejas (por ejemplo, listas de pasos, cada uno con su propio modelo) de manera declarativa.
- 3. Valores por defecto: facilita que ciertos campos tengan valores definidos incluso cuando el modelo de lenguaje no los envía de forma explícita.
- 4. Errores estructurados: devuelve información de validación en forma de diccionario, lo que simplifica registrar, depurar o mostrar problemas al usuario.
Pydantic en Chat Completions
La API de Chat Completions incluye el método client.chat.completions.parse, que combina generación de texto con validación automática usando un modelo de Pydantic como formato de salida. En lugar de recibir texto libre o JSON sin validar, indicamos al modelo qué estructura debe seguir y el SDK se encarga de convertir la respuesta en una instancia del modelo Pydantic.
Esto nos permite tratar la salida del modelo como datos tipados desde el primer momento: accedemos a atributos, listas y campos anidados directamente, y dejamos que Pydantic se ocupe de comprobar que todo cumple el contrato. El resultado es un flujo más predecible y sencillo de integrar con el resto de la aplicación (servicios, controladores HTTP, lógica de dominio, etc.).
En el siguiente ejemplo definimos un pequeño tutor de matemáticas que devuelve el razonamiento paso a paso y la respuesta final en un modelo MathReasoning:
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
completion = client.chat.completions.parse(
model="gpt-5-nano",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format=MathReasoning,
)
math_reasoning = completion.choices[0].message
# If the model refuses to respond, you will get a refusal message
if math_reasoning.refusal:
print(math_reasoning.refusal)
else:
print(math_reasoning.parsed)
Las clases Step y MathReasoning describen exactamente la forma de la respuesta: una lista de pasos, cada uno con una explicación y un resultado parcial, y un campo final_answer con la solución final. El modelo de lenguaje genera texto que encaja con esa estructura, y el cliente de OpenAI lo convierte automáticamente en instancias de Pydantic.
Al pasar response_format=MathReasoning indicamos al modelo que debe generar una salida que pueda transformarse en ese modelo; si la respuesta no cumple el esquema, la validación fallaría y podríamos detectarlo de forma temprana. Además, el propio mensaje devuelto incluye la propiedad parsed con el modelo ya instanciado y refusal para manejar de forma estructurada los casos en los que el modelo decide no responder.
Este patrón evita tener que interpretar manualmente cadenas de texto o JSON ambiguo, y hace que el consumo de la respuesta desde el resto de la aplicación sea tan sencillo como acceder a atributos (math_reasoning.parsed.steps, math_reasoning.parsed.final_answer, etc.), manteniendo el código limpio y fácil de probar.
Pydantic en API Responses
La API de Responses generaliza el concepto de salidas estructuradas y es especialmente adecuada cuando queremos combinar texto, herramientas y formatos estructurados en una misma llamada. Con client.responses.parse seguimos utilizando modelos de Pydantic, pero ahora el modelo se pasa mediante el parámetro text_format y el resultado ya parseado está disponible en response.output_parsed.
Podemos reutilizar el mismo ejemplo de razonamiento matemático, esta vez usando responses.parse en lugar de chat.completions.parse para obtener una respuesta estructurada:
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
response = client.responses.parse(
model="gpt-5",
input=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
text_format=MathReasoning,
)
math_reasoning = response.output_parsed
Aquí text_format=MathReasoning cumple el mismo papel que response_format en Chat Completions: define la estructura esperada de la salida y hace que el SDK la valide y la convierta en un objeto Pydantic. Si la respuesta del modelo no pudiera mapearse al esquema, obtendríamos un error de validación en lugar de propagar datos inconsistentes por la aplicación.
El atributo response.output_parsed contiene directamente la instancia de MathReasoning, de modo que podemos trabajar con tipos fuertes sin preocuparnos del formato intermedio (response.output[0].content[0].text u otras variantes). Esto simplifica tanto el código de negocio como los tests automatizados, que se centran en objetos Python conocidos en lugar de en estructuras dinámicas.
En la práctica, combinar Responses con Pydantic aporta varias ventajas adicionales en aplicaciones reales:
- 1. Tipado explícito: el modelo Pydantic documenta de forma precisa qué información esperamos de la llamada, actuando como contrato compartido entre equipo de backend, frontend y prompts.
- 2. Menos errores en producción: la validación automática reduce problemas difíciles de depurar causados por pequeños cambios en el comportamiento del modelo.
- 3. Modelos reutilizables: los mismos modelos de Pydantic pueden emplearse en pruebas, tareas de migración de datos o validación de configuraciones, favoreciendo la reutilización.
- 4. Migración progresiva: es posible comenzar con un modelo sencillo (unos pocos campos) e ir enriqueciéndolo a medida que la aplicación necesita más información estructurada del modelo de lenguaje.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en OpenAI
Documentación oficial de OpenAI
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, OpenAI es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de OpenAI
Explora más contenido relacionado con OpenAI y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender cómo definir modelos básicos con Pydantic usando clases Python.
- Aprender a crear modelos anidados y estructuras de datos complejas.
- Conocer las capacidades de validación automática y tipos avanzados en Pydantic.
- Manejar campos opcionales y valores por defecto en modelos Pydantic.
- Valorar las ventajas de Pydantic frente a esquemas JSON manuales en términos de legibilidad, mantenimiento y reutilización.
Cursos que incluyen esta lección
Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje