Para qué sirve la salida estructurada
Por defecto, el modelo devuelve texto libre. En muchas aplicaciones necesitas datos estructurados: por ejemplo un objeto con campos nombre, capital y idiomas para un país, o una lista de entidades con atributos fijos. Pedir "responde en JSON" en el prompt no garantiza que el resultado sea válido ni que respete un formato concreto. La salida estructurada de Ollama permite imponer un schema JSON a la respuesta: el modelo genera texto que se ajusta a ese schema, lo que facilita parsear y validar el resultado en tu código.
Puedes usar esto para extracción de datos a partir de texto o imágenes, respuestas de APIs internas, formularios generados por el modelo o cualquier flujo donde necesites un formato predecible. Se combina bien con modelos que soportan thinking y con vision: por ejemplo, describir una imagen con un schema que defina resumen, objetos y colores.
flowchart LR
A["Petición a /api/chat"] --> B{"Parámetro format"}
B -->|"sin format"| C["Texto libre"]
B -->|"'json'"| D["JSON sin esquema fijo"]
B -->|"JSON schema"| E["JSON que cumple<br/>el esquema definido"]
E --> F["Validar con<br/>Pydantic o Zod"]
Modo JSON libre y modo con schema
En la API de chat (y en generate) el parámetro format controla la forma de la salida:
format: "json": el modelo intenta responder con JSON válido, pero sin restricción de campos. Útil cuando solo te importa que sea JSON parseable.format: { ... }: pasas un objeto JSON schema (tipos, propiedades, required). La respuesta del modelo debe ajustarse a ese schema. El contenido devuelto sigue enmessage.content(oresponseen generate) como cadena, y tú la parseas y, si quieres, la validas con tu propia capa (Pydantic, Zod, etc.).
Ejemplo con curl usando solo "json":
curl -X POST http://localhost:11434/api/chat -H "Content-Type: application/json" -d '{
"model": "gpt-oss",
"messages": [{"role": "user", "content": "Dime en una línea algo sobre Canadá."}],
"stream": false,
"format": "json"
}'
Ejemplo con schema definido en la petición:
curl -X POST http://localhost:11434/api/chat -H "Content-Type: application/json" -d '{
"model": "gpt-oss",
"messages": [{"role": "user", "content": "Dime algo sobre Canadá."}],
"stream": false,
"format": {
"type": "object",
"properties": {
"name": {"type": "string"},
"capital": {"type": "string"},
"languages": {"type": "array", "items": {"type": "string"}}
},
"required": ["name", "capital", "languages"]
}
}'
La respuesta incluirá en message.content una cadena JSON que cumple ese schema. Conviene bajar la temperatura (por ejemplo options: { temperature: 0 }) para que la salida sea más determinista y coherente con el schema.
Incluir en el prompt una descripción breve del formato o del schema ayuda al modelo a rellenar bien los campos. No es obligatorio, pero suele mejorar el resultado.
Uso con Pydantic (Python) y Zod (JavaScript)
En Python puedes definir un modelo Pydantic y usar model_json_schema() como valor de format. Luego parseas response.message.content con Model.model_validate_json(...) para obtener un objeto tipado y validado:
from ollama import chat
from pydantic import BaseModel
class Country(BaseModel):
name: str
capital: str
languages: list[str]
response = chat(
model='gpt-oss',
messages=[{'role': 'user', 'content': 'Dime algo sobre Canadá.'}],
format=Country.model_json_schema(),
)
pais = Country.model_validate_json(response.message.content)
print(pais.name, pais.capital)
En JavaScript puedes usar Zod y zodToJsonSchema para generar el schema y luego parsear la respuesta con el mismo Zod schema:
import ollama from 'ollama'
import { z } from 'zod'
import { zodToJsonSchema } from 'zod-to-json-schema'
const Country = z.object({
name: z.string(),
capital: z.string(),
languages: z.array(z.string()),
})
const response = await ollama.chat({
model: 'gpt-oss',
messages: [{ role: 'user', content: 'Dime algo sobre Canadá.' }],
format: zodToJsonSchema(Country),
})
const pais = Country.parse(JSON.parse(response.message.content))
console.log(pais.name, pais.capital)
Así reutilizas el mismo schema para la petición y para la validación, y evitas errores si el modelo se desvía un poco del formato.
Visión y salida estructurada
Los modelos de visión aceptan el mismo parámetro format. Puedes pedir una descripción de imagen con un schema fijo (por ejemplo summary, objects, scene, colors) y obtener un JSON listo para procesar. Combinar temperature baja y un schema claro suele dar resultados más estables que pedir "responde en JSON" solo en el prompt.
from ollama import chat
from pydantic import BaseModel
class ObjectDetected(BaseModel):
name: str
confidence: float
attributes: str
class ImageDescription(BaseModel):
summary: str
objects: list[ObjectDetected]
scene: str
colors: list[str]
response = chat(
model='gemma3',
messages=[{
'role': 'user',
'content': 'Describe esta imagen y lista los objetos que detectes.',
'images': ['ruta/a/imagen.jpg'],
}],
format=ImageDescription.model_json_schema(),
options={'temperature': 0},
)
desc = ImageDescription.model_validate_json(response.message.content)
La API compatible con OpenAI también admite salida estructurada mediante response_format, y la idea es la misma: fijar el formato de la respuesta para integrarla de forma fiable en tu aplicación.
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, Ollama 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 Ollama
Explora más contenido relacionado con Ollama y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Obtener respuestas del modelo acotadas por un JSON schema usando el parámetro format en la API, y combinarlo con validación en Python (Pydantic) o JavaScript (Zod).
Cursos que incluyen esta lección
Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje