Llamadas a la API de Ollama: de curl a la interfaz compatible con OpenAI SDK

Ese curl en la terminal devolvió un JSON con media palabra: tardé dos horas en darme cuenta de que era respuesta en streaming. Ollama, por defecto, va soltando el contenido poco a poco; cada objeto JSON solo trae unos pocos caracteres.
En despliegue local de LLM, Ollama baja mucho la barrera: descargar, instalar y ejecutar, tres pasos. Pero las llamadas a la API confunden: ¿qué diferencia hay entre la REST API nativa y la interfaz compatible con OpenAI SDK? ¿Cómo se maneja el streaming?
Este artículo recoge los tropiezos que ya pasé: de curl a migración casi sin tocar código con OpenAI SDK, y detalles que la documentación no deja del todo claros.
Ollama tiene dos interfaces de API
Esto me lió un buen rato. Ollama ofrece dos interfaces de API completamente distintas:
REST API nativa: http://localhost:11434/api/*
- Endpoints:
/api/generate(generación de texto),/api/chat(chat),/api/tags(lista de modelos) - Respuesta en streaming por defecto (el problema de las tres de la mañana)
- Llamada HTTP directa, sin SDK
Interfaz compatible con OpenAI: http://localhost:11434/v1/*
- Endpoints:
/v1/chat/completions,/v1/completions,/v1/models - Totalmente compatible con OpenAI SDK (Python y JavaScript)
- Soporta el ecosistema de herramientas OpenAI existente
¿Por qué dos? Cada una tiene su utilidad. La API nativa es más ligera y directa, ideal si escribes tu propio cliente HTTP; la compatible con OpenAI te permite reutilizar código OpenAI casi sin cambios: solo cambias base_url.
Es un diseño inteligente: cubre a quien quiere algo simple y a equipos que ya tienen código sobre el ecosistema OpenAI.
REST API nativa: empezando con curl
La API nativa es bastante directa: una interfaz REST estándar.
Llamada curl básica
El ejemplo más simple — generación de texto:
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Why is the sky blue?",
"stream": false
}'
Fíjate en stream: false. Por defecto Ollama devuelve contenido en streaming; si quieres JSON completo, desactívalo explícitamente. Si no, verás algo así:
{"model":"llama3.2","response":"That","done":false}
{"model":"llama3.2","response":"'","done":false}
{"model":"llama3.2","response":"s","done":false}
{"model":"llama3.2","response":" a","done":false}
...
{"model":"llama3.2","response":"!","done":true}
Cada objeto JSON solo trae unos pocos caracteres, token a token. Eso es NDJSON (Newline-Delimited JSON): una línea, un objeto JSON. Aquella noche a las tres, no lo vi y parseé como JSON normal; solo obtuve “That” del primer objeto.
El modo chat es más práctico
La generación única sirve para tareas simples; el chat es lo que más usarás:
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [
{ "role": "user", "content": "Hello!" }
],
"stream": false
}'
Puedes mantener un array messages con el historial para que el modelo recuerde el contexto. Clave para apps de chat.
Ver modelos instalados
A veces quieres saber qué modelos tienes en local:
curl http://localhost:11434/api/tags
El JSON lista todos los modelos descargados, con tamaño, fecha de modificación y nivel de cuantización. Muy práctico.
Manejo del streaming
Merece un apartado. El streaming de Ollama no devuelve todo de golpe: va token a token.
Streaming en Python
Con requests:
import requests
import json
url = "http://localhost:11434/api/chat"
payload = {
"model": "llama3.2",
"messages": [{"role": "user", "content": "Write a short poem"}],
"stream": True
}
response = requests.post(url, json=payload, stream=True)
for line in response.iter_lines():
if line:
chunk = json.loads(line)
print(chunk.get("message", {}).get("content", ""), end="", flush=True)
La clave es response.iter_lines(): lee el flujo NDJSON línea a línea. Cada chunk puede traer solo unos caracteres; hay que acumularlos.
Streaming en JavaScript
En el frontend, con fetch, es similar:
const response = await fetch('http://localhost:11434/api/chat', {
method: 'POST',
body: JSON.stringify({
model: 'llama3.2',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true
})
});
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
// procesar cada chunk...
}
El streaming es más trabajo que el modo no streaming, pero la UX mejora: ves al modelo «pensar» y escribir en tiempo real, en lugar de esperar y recibir un bloque de texto.
Interfaz compatible con OpenAI SDK: migración casi sin código
Esta parte me gusta especialmente. Ollama ofrece compatibilidad completa con la API de OpenAI; puedes migrar código existente casi sin fricción.
Ejemplo con OpenAI SDK en Python
Usa el SDK oficial de OpenAI:
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1/',
api_key='ollama' # en local no se valida; cualquier valor vale
)
response = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
El único cambio: base_url y un api_key cualquiera. El resto igual.
Cambiar entre desarrollo y producción
Muy útil: Ollama local en desarrollo, OpenAI en producción:
# .env desarrollo
OPENAI_API_KEY=anyrandomtext
LLM_ENDPOINT="http://localhost:11434/v1"
MODEL=llama3.2
# .env producción
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXXXX
LLM_ENDPOINT="https://api.openai.com/v1"
MODEL=gpt-3.5-turbo
En el código, lee variables de entorno:
import os
from openai import OpenAI
client = OpenAI(
base_url=os.getenv('LLM_ENDPOINT'),
api_key=os.getenv('OPENAI_API_KEY')
)
Desarrollas sin pagar llamadas a OpenAI; al desplegar, cambias variables y listo.
Endpoints soportados
La interfaz compatible de Ollama cubre:
| Endpoint | Función | Soporte |
|---|---|---|
/v1/chat/completions | Generación en chat | Completo |
/v1/completions | Completado de texto | Completo |
/v1/models | Lista de modelos | Completo |
/v1/embeddings | Embeddings de texto | Completo |
/v1/responses | Nueva API de respuestas | Completo |
También hay /v1/images/generations en experimental; la estabilidad aún no es suficiente.
Alias de modelos
Un truco: puedes aliasar modelos. Si quieres que el código parezca llamar a GPT-3.5:
ollama cp llama3.2 gpt-3.5-turbo
Así, model="gpt-3.5-turbo" usa en realidad llama3.2 local. Muy útil al migrar.
¿Cuál elegir?
Cuándo usar la REST API nativa
Encaja si:
- Quieres la forma más ligera de llamar
- No necesitas el ecosistema OpenAI SDK
- Escribes tu propio cliente HTTP (dispositivos embebidos, entornos especiales)
- Necesitas control fino del streaming
Es más directa y de bajo nivel. Si dominas HTTP, te resultará natural.
Cuándo usar la interfaz compatible con OpenAI SDK
Encaja si:
- Ya tienes código con OpenAI SDK
- Quieres migrar rápido a despliegue local
- Usas herramientas del ecosistema OpenAI (LangChain, LlamaIndex, etc.)
- Necesitas alternar desarrollo y producción
En resumen: si prefieres no tocar código, usa la interfaz compatible con OpenAI.
Mi recomendación
En desarrollo suelo usar la compatible con OpenAI SDK: pocos cambios, herramientas disponibles, depuración sencilla. En algunos casos la API nativa gana — un CLI mínimo o un entorno sin OpenAI SDK.
Fragmentos de código útiles
Algunos snippets que uso a menudo.
Chat en streaming con OpenAI SDK (Python)
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1/',
api_key='ollama'
)
stream = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Write a poem"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
Conversación completa en JavaScript (API nativa)
async function chat(messages) {
const response = await fetch('http://localhost:11434/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama3.2',
messages: messages,
stream: false
})
});
return await response.json();
}
// mantener historial
let conversation = [
{ role: 'user', content: 'Hello!' }
];
const result = await chat(conversation);
conversation.push({
role: 'assistant',
content: result.message.content
});
console.log(result.message.content);
Ejemplo con tool calling
Ollama también soporta Function Calling:
from openai import OpenAI
client = OpenAI(base_url='http://localhost:11434/v1/', api_key='ollama')
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
}
]
response = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
tools=tools
)
if response.choices[0].message.tool_calls:
print("Model wants to call:", response.choices[0].message.tool_calls[0].function.name)
En resumen
El diseño de la API de Ollama equilibra bien: REST nativa ligera y directa, y comodidad del ecosistema OpenAI SDK. Cada vía tiene su escenario; depende de lo que necesites.
Si empiezas con Ollama, prueba primero la compatible con OpenAI SDK: arranque rápido, pocos cambios. Cuando domines el terreno, decide si la API nativa encaja mejor.
Y ojo con el streaming: por defecto está activo. Si no lo necesitas, pon stream: false explícitamente — o te quedarás mirando media palabra a las tres de la mañana, como yo.
Referencias
- Ollama API Introduction
- Ollama OpenAI Compatibility
- Ollama Streaming Guide
- KodeKloud OpenAI Compatibility Guide
Dos formas de llamar la API de Ollama
Flujo completo de llamada, de la API nativa con curl a la interfaz compatible con OpenAI SDK
⏱️ Estimated time: 10 min
- 1
Step 1: Confirmar que Ollama está instalado y en marcha
Primero comprueba que Ollama funciona correctamente:
• En la terminal: ollama list (ver modelos descargados)
• O visita: http://localhost:11434 (debería devolver Ollama is running)
• Puerto por defecto: 11434 - 2
Step 2: Elegir el método de llamada
Elige según tu escenario:
• REST API nativa: ideal para llamadas ligeras y clientes personalizados
• Compatible con OpenAI SDK: ideal si ya tienes código OpenAI y quieres migrar rápido - 3
Step 3: Usar la REST API nativa (con curl)
La llamada curl más básica:
• Generación de texto: curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "...", "stream": false}'
• Modo chat: curl http://localhost:11434/api/chat -d '{"model": "llama3.2", "messages": [...], "stream": false}'
• Nota: responde en streaming por defecto; hay que poner stream: false para desactivarlo - 4
Step 4: Usar la interfaz compatible con OpenAI SDK
Llamada con OpenAI SDK en Python:
• Configura base_url='http://localhost:11434/v1/'
• api_key puede ser cualquier valor (en local no se valida)
• El resto del código es idéntico a OpenAI
• Cambio de entorno: solo modifica base_url (local en desarrollo, OpenAI en producción) - 5
Step 5: Manejar respuestas en streaming
Puntos clave del streaming:
• Python: response.iter_lines() lee NDJSON línea a línea
• JavaScript: response.body.getReader() para lectura en streaming
• Cada chunk solo trae unos pocos caracteres; hay que acumular la respuesta completa
• Sin streaming: pon stream: false para obtener JSON completo
FAQ
¿Qué diferencia hay entre la API nativa de Ollama y la interfaz compatible con OpenAI SDK?
¿Por qué la API de Ollama solo me devolvió media palabra?
• Pon stream: false para desactivar el streaming y obtener JSON completo
• O procesa bien el flujo NDJSON: lee línea a línea y acumula el contenido
¿Cómo usar Ollama local en desarrollo y OpenAI en producción?
¿Qué endpoints de OpenAI soporta Ollama?
¿Puedo poner alias a los modelos de Ollama?
¿Ollama soporta tool calling (Function Calling)?
7 min de lectura · Publicado el: 3 abr 2026 · Actualizado el: 21 ago 2026
Guía de Ollama local LLM
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Ollama + Open WebUI: monta una interfaz local tipo ChatGPT (guía completa)
Guía paso a paso para montar en local una interfaz de chat con IA al estilo ChatGPT usando Ollama y Open WebUI: instalación, elección de modelos, base de conocimiento RAG, integración API y optimización del rendimiento en 30 minutos
Parte 11 de 18
Siguiente
Ollama API en la práctica: guía de clientes con Python y Node.js
Métodos de llamada a la API de Ollama: SDK nativos en Python y Node.js, respuestas en streaming, Agent Loop con tool calling, modo thinking y comparación con la compatibilidad OpenAI
Parte 13 de 18



Comentarios
Inicia sesión con GitHub para dejar un comentario