Ollama API en la práctica: guía de clientes con Python y Node.js

Escribes ollama run gemma3 en la terminal y aparece la primera respuesta. El modelo local ya está corriendo.
La pregunta natural: ¿puedo integrarlo en mi proyecto? Sin API Key, sin pagar, todo en local — suena bien.
Revisando la documentación, Ollama ofrece SDK oficiales para Python y JavaScript, e incluso puedes usar el SDK de OpenAI cambiando dos líneas. Más sencillo de lo que parece.
Pero sencillo no significa sin trampas. ¿Cómo acumular streaming? ¿Cómo escribir el Agent Loop para tool calling? ¿Cómo separar razonamiento y respuesta en modo thinking? Son errores que ya cometí.
Este artículo cubre esas trampas. Comparativa Python y Node.js, SDK nativo y compatibilidad OpenAI — una guía completa de clientes.
Si aún no tienes Ollama instalado, empieza por el primer capítulo de la serie: Integración LangChain + Ollama y pon el modelo local en marcha.
Capítulo 1: Fundamentos de la API de Ollama
Primero, cómo funciona la API.
Ollama levanta por defecto un servicio REST en local, en http://localhost:11434/api. Si abres esa URL en el navegador verás el lacónico “Ollama is running” — señal de que todo va bien.
Endpoints principales
Dos endpoints que conviene memorizar:
| Endpoint | Uso | Características |
|---|---|---|
/api/chat | Conversación multi-turn | Acepta array messages y contexto |
/api/generate | Generación simple | Directo, ideal para tareas puntuales |
También está /v1/chat/completions, el endpoint compatible con OpenAI. Si ya tienes un proyecto OpenAI, cambia base_url y listo; lo veremos más adelante.
Probar con curl
Prueba la API de la forma más cruda:
curl http://localhost:11434/api/chat -d '{
"model": "gemma3",
"messages": [
{ "role": "user", "content": "¿Por qué el cielo es azul?" }
]
}'
La terminal devuelve un montón de JSON. Fíjate en message.content: ahí está la respuesta del modelo.
La estructura de respuesta es algo así:
{
"model": "gemma3",
"created_at": "2026-04-18T01:23:45.678Z",
"message": {
"role": "assistant",
"content": "El cielo se ve azul principalmente porque..."
},
"done": true
}
El campo done importa. En streaming, cada chunk tiene done: false hasta el último, que lleva true. Lo usarás al procesar streaming.
Respuesta en streaming
Por defecto la API espera a que el modelo termine y devuelve todo de golpe. Para efecto máquina de escribir, añade stream: true:
curl http://localhost:11434/api/chat -d '{
"model": "gemma3",
"messages": [{ "role": "user", "content": "¿Por qué el cielo es azul?" }],
"stream": true
}'
Esta vez salen líneas JSON una a una. Cada línea es un chunk; hay que acumularlos para la respuesta completa.
Procesar chunks a mano es tedioso. Por eso existen los SDK — encapsulan esos detalles.
Capítulo 2: SDK de Python al completo
El SDK de Python lo mantiene el equipo oficial. Instalación trivial:
pip install ollama
Listo para usar. Soporta Python 3.8+, bastante accesible.
Llamada básica
La forma más simple, en una línea:
from ollama import chat
response = chat(
model='gemma3',
messages=[{'role': 'user', 'content': '¿Por qué el cielo es azul?'}]
)
print(response.message.content)
Así de simple. chat() es un atajo del SDK que crea un Client por defecto contra Ollama local.
Si Ollama corre en otra máquina, crea tu propio Client:
from ollama import Client
client = Client(host='http://192.168.1.100:11434')
response = client.chat(model='gemma3', messages=[...])
Streaming
El streaming es clave: el usuario ve el texto aparecer poco a poco, no un bloque tras una espera larga.
from ollama import chat
stream = chat(
model='gemma3',
messages=[{'role': 'user', 'content': '¿Por qué el cielo es azul?'}],
stream=True,
)
for chunk in stream:
print(chunk['message']['content'], end='', flush=True)
Trampa habitual: chunk es un diccionario, no un objeto. Usa chunk['message']['content'], no chunk.message.content. Me costó un rato verlo.
Cliente asíncrono
En arquitectura async — FastAPI, aiohttp — usa el cliente asíncrono:
import asyncio
from ollama import AsyncClient
async def main():
client = AsyncClient()
# Sin streaming
response = await client.chat(
model='gemma3',
messages=[{'role': 'user', 'content': 'Hola'}]
)
print(response.message.content)
# Con streaming
stream = await client.chat(
model='gemma3',
messages=[{'role': 'user', 'content': '¿Por qué el cielo es azul?'}],
stream=True,
)
async for chunk in stream:
print(chunk['message']['content'], end='', flush=True)
asyncio.run(main())
El streaming async devuelve un async generator; recórrelo con async for. Misma lógica que la versión síncrona, con await y async.
Cloud Models
El SDK también soporta modelos en la nube. Algunos modelos grandes — p. ej. gpt-oss 120B — no caben en local, pero sí en cloud.
from ollama import chat
response = chat(
model='gpt-oss:120b-cloud',
messages=[{'role': 'user', 'content': 'Hola'}]
)
El sufijo -cloud en el nombre del modelo usa la API cloud. Necesitas cuenta Ollama cloud y API Key; la configuración difiere de local. Consulta la documentación oficial si te interesa.
Modelos pequeños en local ahorran dinero; grandes en cloud ahorran hardware. Un híbrido razonable.
Capítulo 3: SDK de Node.js al completo
El SDK de Node.js es igual de conciso:
npm i ollama
Soporta Node.js y navegador. En el navegador importa aparte:
// Node.js
import ollama from 'ollama'
// Navegador
import ollama from 'ollama/browser'
Llamada básica
En Node.js todo es async por defecto:
import ollama from 'ollama'
const response = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '¿Por qué el cielo es azul?' }],
})
console.log(response.message.content)
Comparado con Python: messages como objetos en JS, diccionarios en Python. Mismos nombres de parámetro; cambiar de lenguaje no exige reaprender conceptos.
Streaming
En Node.js el streaming es un async generator nativo:
import ollama from 'ollama'
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: '¿Por qué el cielo es azul?' }],
stream: true,
})
for await (const chunk of stream) {
process.stdout.write(chunk.message.content)
}
Usa process.stdout.write en lugar de console.log: console.log añade salto de línea y no quieres uno por token.
Configuración personalizada
Puedes definir host y headers:
import ollama from 'ollama'
// Host personalizado
const client = new ollama.Ollama({ host: 'http://192.168.1.100:11434' })
// O configuración global
ollama.setDefaultHost('http://192.168.1.100:11434')
// Headers (p. ej. autenticación)
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: 'Hola' }],
headers: { Authorization: 'Bearer xxx' },
})
Útil si delante de Ollama hay un proxy con autenticación.
Cancelar generación en streaming
abort() cancela un stream en curso:
import ollama from 'ollama'
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: 'Escribe un artículo largo...' }],
stream: true,
})
// El usuario pulsa detener
ollama.abort()
for await (const chunk of stream) {
// Tras abort, el bucle termina antes
process.stdout.write(chunk.message.content)
}
Imprescindible en interfaces de chat: el usuario puede parar sin esperar al final.
Versión navegador
Uso similar, con matices:
import ollama from 'ollama/browser'
// En el navegador solo streaming: la API no streaming falla en CORS
const stream = await ollama.chat({
model: 'gemma3',
messages: [{ role: 'user', content: 'Hola' }],
stream: true,
})
for await (const chunk of stream) {
document.getElementById('output').textContent += chunk.message.content
}
Restricción: obligatorio streaming. Las peticiones no streaming devuelven JSON grande; CORS y timeouts son frecuentes. El streaming por chunks reduce el problema.
Razonable para UI de chat, donde ya quieres efecto streaming.
Capítulo 4: Tool calling en la práctica
El tool calling es la base de los agentes. Ollama permite que el modelo invoque funciones que defines y continúe con el resultado.
En Python puedes pasar funciones directamente; el SDK parsea docstring y tipos de parámetros.
Parseo automático de funciones Python
def get_weather(city: str) -> str:
"""Obtiene el tiempo de una ciudad concreta
Args:
city: Nombre de la ciudad, p. ej. Madrid, Barcelona
Returns:
Descripción del tiempo
"""
# Datos simulados
weather_data = {
'Madrid': 'Soleado, 18°C',
'Barcelona': 'Nublado, 22°C',
'Valencia': 'Lluvia, 26°C',
}
return weather_data.get(city, f'Sin datos de tiempo para {city}')
from ollama import chat
response = chat(
model='qwen3',
messages=[{'role': 'user', 'content': '¿Qué tiempo hace hoy en Madrid?'}],
tools=[get_weather],
)
print(response.message.content)
El SDK convierte la función al formato de herramienta: nombre desde la función, descripción desde el docstring, parámetros desde las anotaciones. Sin escribir JSON Schema a mano.
Patrón Agent Loop
No siempre basta una invocación: el modelo puede llamar varias herramientas o encadenarlas. Hace falta un bucle.
Eso es el Agent Loop:
from ollama import chat
def add(a: int, b: int) -> int:
"""Suma dos números"""
return a + b
def multiply(a: int, b: int) -> int:
"""Multiplica dos números"""
return a * b
tools = [add, multiply]
tool_map = {'add': add, 'multiply': multiply}
messages = [{'role': 'user', 'content': 'Calcula (3 + 5) * 2'}]
while True:
response = chat(model='qwen3', messages=messages, tools=tools)
if response.message.tool_calls:
# El modelo quiere usar herramientas
for call in response.message.tool_calls:
func_name = call.function.name
func_args = call.function.arguments
result = tool_map[func_name](**func_args)
# Añadir resultado al historial
messages.append({
'role': 'tool',
'content': str(result),
'tool_name': func_name,
})
else:
# Sin tool_calls: terminado
print(response.message.content)
break
La lógica:
- Enviar mensaje con definición de herramientas
- Si hay
tool_calls, ejecutar las funciones - Meter resultados en el historial y volver a llamar al modelo
- Repetir hasta que no haya más tool_calls
Patrón imprescindible para agentes: defines herramientas y el modelo decide cuándo y cuáles usar.
Modo thinking
Algunos modelos — p. ej. qwen3 — soportan thinking: primero razonan, luego responden.
from ollama import chat
stream = chat(
model='qwen3',
messages=[{'role': 'user', 'content': '¿Por qué el cielo es azul?'}],
stream=True,
think=True,
)
thinking = ''
content = ''
for chunk in stream:
if chunk.message.thinking:
thinking += chunk.message.thinking
elif chunk.message.content:
content += chunk.message.content
print('=== Proceso de razonamiento ===')
print(thinking)
print('=== Respuesta final ===')
print(content)
En modo thinking, el chunk incluye el campo thinking. Acumula razonamiento y respuesta por separado.
Útil para ver cómo el modelo llega a la respuesta; apps educativas o depuración de prompts.
Capítulo 5: SDK nativo vs API compatible OpenAI
Tienes dos caminos:
- SDK nativo de Ollama (lo anterior)
- SDK de OpenAI apuntando a Ollama
La elección depende de tu contexto.
Compatibilidad OpenAI
Si ya tienes un proyecto OpenAI, lo más barato es cambiar base_url:
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1',
api_key='ollama', # Obligatorio pero ignorado
)
response = client.chat.completions.create(
model='gemma3',
messages=[{'role': 'user', 'content': '¿Por qué el cielo es azul?'}],
)
print(response.choices[0].message.content)
Así de simple. El SDK de OpenAI no sabe que detrás está Ollama; cree hablar con una “API OpenAI”.
En Node.js igual:
import OpenAI from 'openai'
const client = new OpenAI({
baseURL: 'http://localhost:11434/v1',
apiKey: 'ollama',
})
const completion = await client.chat.completions.create({
model: 'gemma3',
messages: [{ role: 'user', content: '¿Por qué el cielo es azul?' }],
})
console.log(completion.choices[0].message.content)
Comparación
| Aspecto | SDK nativo | Compatible OpenAI |
|---|---|---|
| Instalación | pip install ollama | Basta el SDK OpenAI |
| Tool calling | Parseo automático de docstring | JSON Schema manual |
| Streaming | Chunks en formato diccionario | Formato OpenAI estándar |
| Cloud Models | Sí | No |
| Coste migración | Ninguno en proyecto nuevo | Mínimo en proyecto existente |
Recomendación
Proyecto nuevo: SDK nativo.
Motivos:
- Tool calling más cómodo: pasas funciones Python directamente
- Más funciones (Cloud Models, thinking)
- Documentación y ejemplos oficiales
Migrar proyecto OpenAI existente: compatibilidad OpenAI.
Motivos:
- Dos líneas y funciona
- Sin reescribir lógica
- Volver a OpenAI es trivial
En resumen: SDK nativo más completo; compatibilidad OpenAI migración más rápida. Depende de lo que necesites.
He probado ambos. El tool calling nativo ahorra trabajo — no hace falta JSON Schema si el docstring está claro. Pero si el proyecto ya corre sobre OpenAI, no tiene sentido reescribir todo solo por Ollama.
Cierre
Puntos clave:
Llamadas básicas: los SDK de Python y Node.js están bien hechos; pocas líneas bastan. Para streaming, stream=True.
Tool calling: Agent Loop es el patrón central — procesar tool_calls en bucle hasta que el modelo pare. En Python puedes pasar funciones directamente.
Modo thinking: modelos como qwen3 muestran el razonamiento. Trata por separado los campos thinking y content en cada chunk.
Elección de enfoque: proyecto nuevo, SDK nativo; proyecto OpenAI, compatibilidad con un cambio de URL.
Próximos pasos:
- Si aún no tienes Ollama, empieza por el primer capítulo de la serie
- Elige nativo u OpenAI según tu proyecto y pruébalo
- La documentación oficial evoluciona; conviene echarle un vistazo de vez en cuando
Ejecutar LLM en local cada vez es más accesible. Ollama esconde la complejidad tras una API simple. Tú solo necesitas saber llamarla.
Este es el segundo artículo de la serie. El siguiente tratará Modelfile — cómo adaptar el modelo a lo que necesitas.
Desarrollo de clientes Ollama API
Guía completa para llamar la API de modelos locales de Ollama con los SDK de Python o Node.js
⏱️ Estimated time: 45 min
- 1
Step 1: Instalar el SDK y probar una llamada básica
En Python ejecuta `pip install ollama`; en Node.js, `npm i ollama`.
Tras instalar, prueba la conexión con el código más simple:
```python
from ollama import chat
response = chat(model='gemma3', messages=[{'role': 'user', 'content': 'Hola'}])
print(response.message.content)
```
Asegúrate de que Ollama esté en marcha (puerto 11434 por defecto) y de haber descargado el modelo correspondiente. - 2
Step 2: Implementar respuesta en streaming
Activa el streaming para mostrar la salida token a token:
```python
from ollama import chat
stream = chat(model='gemma3', messages=[...], stream=True)
for chunk in stream:
print(chunk['message']['content'], end='', flush=True)
```
Ten en cuenta que chunk es un diccionario; accede con `chunk['message']['content']`. - 3
Step 3: Configurar tool calling (opcional)
Define funciones Python como herramientas; el SDK parsea docstring y anotaciones de tipo:
```python
def get_weather(city: str) -> str:
"""Obtiene el tiempo de una ciudad"""
return f'{city}: soleado'
response = chat(model='qwen3', messages=[...], tools=[get_weather])
```
Implementa un Agent Loop para gestionar múltiples invocaciones hasta la respuesta final. - 4
Step 4: Elegir SDK nativo o compatibilidad OpenAI
Proyectos nuevos: SDK nativo (más funciones: Cloud Models, modo thinking).
Proyectos OpenAI existentes, solo dos líneas:
```python
client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')
```
Coste de migración mínimo; volver a OpenAI cuando quieras.
FAQ
¿Cuál es el puerto y la dirección por defecto de la API de Ollama?
¿Qué tipo devuelve el streaming del SDK de Python?
¿Qué limitaciones tiene el SDK de Node.js en el navegador?
¿Qué es el patrón Agent Loop?
¿Cómo obtener por separado razonamiento y respuesta en modo thinking?
¿SDK nativo o compatibilidad OpenAI?
10 min de lectura · Publicado el: 18 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
Llamadas a la API de Ollama: de curl a la interfaz compatible con OpenAI SDK
Aprende dos formas de llamar la API de Ollama: REST API nativa (curl) e interfaz compatible con OpenAI SDK. Incluye ejemplos de código completos, manejo de respuestas en streaming y guía de buenas prácticas
Parte 12 de 18
Siguiente
Integración LangChain + Ollama: guía completa de desarrollo con LLM local
Métodos completos de integración LangChain y Ollama: ejemplos de Chat, RAG y Agent, estrategia de cambio entre OpenAI y Ollama, y cómo construir aplicaciones LLM locales de nivel empresarial.
Parte 14 de 18



Comentarios
Inicia sesión con GitHub para dejar un comentario