API de Ollama en Python y una alternativa alojada
La API de Ollama en Python requiere unas diez líneas, y la misma estructura de código también funciona contra un endpoint alojado. Este artículo muestra ambos casos y explica cuándo elegir cada uno.
Actualizado
Puntos clave
- Ollama escucha en el puerto 11434 y ofrece una API nativa más un endpoint /v1 estilo OpenAI.
- El paquete ollama, requests puro y el SDK de OpenAI funcionan; el SDK de OpenAI es el más portátil.
- Moverse a una API alojada implica cambiar la URL base, la clave y el nombre del modelo.
- La versión local es mejor para trabajo sin conexión y hardware fijo; el servicio alojado es más sencillo cuando no tienes GPU.

La versión corta
Si buscas ollama api python, normalmente quieres una de tres cosas: llamar a un modelo que se ejecuta en tu propia máquina, transmitir tokens desde él, o hacer que el mismo script funcione en otro lugar. Ollama te ofrece las tres. Ejecuta un servidor local, por defecto en http://localhost:11434, y te comunicas con él mediante el paquete Python ollama, con HTTP plano, o con cualquier cliente OpenAI apuntando a su ruta /v1.
La pega es que el modelo debe ejecutarse en tu hardware. Un portátil sin una GPU decente será lento con modelos grandes, y un servidor sin una es una mala opción. Para ese caso, una API compatible con OpenAI alojada es la ruta más fácil, y como el formato de petición es el mismo, cambiar te cuesta tres líneas de configuración. Ambas rutas se cubren a continuación, con código que puedes pegar.
Llamada a un modelo local con el paquete ollama
Instala Ollama, extrae un modelo y asegúrate de que el servidor esté en ejecución. Luego instala el cliente Python:
pip install ollama
ollama pull llama3.2
Una llamada básica de chat se ve así. El nombre del modelo es el que hayas extraído; llama3.2 es solo un ejemplo.
import ollama
response = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Explain DNS in two sentences."}],
)
print(response["message"]["content"])
Transmisión
Pasa stream=True y obtienes un iterador de fragmentos en lugar de una sola respuesta. Cada fragmento contiene una parte de la respuesta en message.content.
import ollama
stream = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Write a haiku about servers."}],
stream=True,
)
for chunk in stream:
print(chunk["message"]["content"], end="", flush=True)
print()
Apuntar el cliente a otra máquina
Si Ollama se ejecuta en un host diferente, crea un cliente con una dirección explícita, por ejemplo ollama.Client(host="http://192.168.1.20:11434"). Por defecto, el servidor solo escucha en la máquina local, por lo que el acceso remoto necesita una configuración deliberada en el lado del servidor. No lo expongas a internet público sin un proxy y autenticación delante, porque la API nativa no tiene su propia comprobación de clave.
HTTP plano con requests
No necesitas el paquete en absoluto. El endpoint de chat nativo es POST /api/chat. El streaming es el predeterminado allí, y el stream es JSON delimitado por saltos de línea, no SSE. Establece "stream": false si quieres un solo objeto de vuelta.
import requests
r = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.2",
"messages": [{"role": "user", "content": "Name three HTTP status codes."}],
"stream": False,
},
timeout=120,
)
r.raise_for_status()
print(r.json()["message"]["content"])
Establece un tiempo de espera generoso. La primera petición después de una extracción debe cargar el modelo en la memoria, y eso puede tardar mucho más que las peticiones posteriores.
Leer el stream manualmente son solo unas líneas más. Llama a requests.post(..., stream=True), itera sobre r.iter_lines(), omite las líneas vacías y ejecuta json.loads en cada una. Cada objeto contiene una pequeña parte de la respuesta, y el último tiene "done": true. Esto es útil en un contenedor mínimo donde prefieres no instalar otro paquete, y deja claro lo que la biblioteca hace por ti. La API alojada transmite de forma distinta, como líneas SSE que comienzan con data:, lo cual es otra razón para dejar que el SDK de OpenAI analice el stream por ti en código portátil.
Uso del SDK de OpenAI con Ollama
Ollama también expone un endpoint estilo OpenAI bajo /v1. Eso significa que el paquete oficial openai funciona, y también la mayoría del software que te permite establecer una URL base personalizada. La clave es requerida por el SDK pero ignorada por un Ollama local, así que cualquier cadena servirá.
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Give me a one-line summary of TCP."}],
)
print(resp.choices[0].message.content)
Esta es la forma más útil, porque desacopla tu código del servidor. La misma función puede hablar con un modelo local hoy y con otra cosa mañana, que es la siguiente sección.
El mismo código contra una API alojada
La opción alojada aquí es una API compatible con OpenAI con un único modelo, uncensored, gestionada por un proveedor independiente y ajustada para responder sin rechazos de contenido para uso adulto lícito. Es solo texto. La URL base es https://api.ollamaapi.cc/v1, y te autentificas con una clave Bearer desde la página de claves de API.
Aquí tienes una versión que lee su destino de variables de entorno, con los valores alojados como predeterminados. Para volver a tu servidor local, exporta dos variables y no cambies nada más.
import os
from openai import OpenAI
client = OpenAI(
base_url=os.getenv("LLM_BASE_URL", "https://api.ollamaapi.cc/v1"),
api_key=os.getenv("LLM_API_KEY", "YOUR_API_KEY"),
)
MODEL = os.getenv("LLM_MODEL", "uncensored")
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "List four uses of a message queue."},
],
temperature=0.7,
)
print(resp.choices[0].message.content)
Para ejecuciones locales, establece LLM_BASE_URL=http://localhost:11434/v1, LLM_API_KEY=ollama y LLM_MODEL=llama3.2. El inicio rápido tiene la misma configuración en curl y Node.
Streaming, modo JSON y herramientas en el lado alojado
El endpoint alojado admite streaming por SSE, modo JSON, llamadas a funciones y los parámetros de muestreo habituales (temperature, top_p, stop, seed y las penalizaciones). El streaming con el SDK es el mismo bucle que escribirías para cualquier servidor estilo OpenAI:
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Tell a two-paragraph story about a lighthouse."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
Para salida estructurada, establece response_format={"type": "json_object"} y di en el prompt que quieres JSON. Analiza siempre dentro de un bloque try de todos modos; un modelo aún puede devolver algo que no esperabas.
Una diferencia con el uso local importa en el código: los límites. Una clave completa permite 8 peticiones simultáneas y 300 peticiones por minuto, y una petición en streaming mantiene su espacio hasta que finalice el stream. Si distribuyes con hilos, limita la distribución a 8 y reintenta en HTTP 429 usando el encabezado Retry-After cuando esté presente.
Mantener una conversación
Ni el endpoint de chat local ni el alojado recuerdan nada entre llamadas. El servidor solo ve los mensajes que envías, por lo que un chatbot es una lista a la que añades y reenvías. El patrón es idéntico para ambos destinos, que es otra razón para mantener el cliente estilo OpenAI como tu cliente predeterminado.
history = [{"role": "system", "content": "You are a helpful assistant."}]
def ask(text):
history.append({"role": "user", "content": text})
resp = client.chat.completions.create(model=MODEL, messages=history)
answer = resp.choices[0].message.content
history.append({"role": "assistant", "content": answer})
return answer
print(ask("Pick a name for a hiking app."))
print(ask("Give me a tagline for it."))
Dos notas prácticas. Primero, los modelos locales tienen una longitud de ventana de contexto que tú defines y que la memoria debe contener; si el historial crece más allá de ese límite, los turnos antiguos se recortan o la petición falla, según la configuración. El modelo alojado acepta una ventana de 100.000 tokens que incluye el completado, lo cual es mucho más de lo que necesitan la mayoría de los chats, pero los historiales largos aún consumen tokens de entrada en cada turno. Segundo, una vez que un historial se hace largo, resume los turnos más antiguos en un solo mensaje corto en lugar de reenviarlos todos. Eso mantiene la latencia y el coste estables en ambos backends.
Reintento educado
En la API alojada, una sobrecarga temporal devuelve HTTP 429 con un encabezado Retry-After: 5. Un pequeño contenedor lo maneja:
import time
from openai import RateLimitError
def chat_with_retry(messages, tries=4):
for attempt in range(tries):
try:
return client.chat.completions.create(model=MODEL, messages=messages)
except RateLimitError:
time.sleep(5 * (attempt + 1))
raise RuntimeError("still rate limited")
Ollama local no te limita por velocidad, pero cola las peticiones cuando el modelo está ocupado, por lo que el mismo wrapper no hace daño allí.
Local o alojado: cómo decidir
Ninguna elección es mejor en general. Usa los puntos a continuación como una lista de verificación.
- Elige Ollama local si necesitas trabajar sin conexión, si los datos nunca deben salir de la máquina, si ya posees una GPU capaz, o si quieres probar muchos modelos abiertos diferentes rápidamente.
- Elige una API alojada si no tienes GPU, si ejecutas en un VPS pequeño o en integración continua, si varias personas o servicios comparten un backend, o si quieres una ventana de contexto larga sin dimensionar la memoria tú mismo. El modelo alojado acepta hasta 100 000 tokens de prompt más completado.
- Mezcla ambos durante el desarrollo: itera localmente, luego apunta la producción a la URL alojada a través de variables de entorno.
El uso alojado se factura por token, a $0,15 por 1M de tokens de entrada y $0,50 por 1M de tokens de salida, desde el crédito prepago. La página de precios muestra los montos de recarga, y las cuentas nuevas pueden reclamar un crédito de prueba de $0,50 con un clic, sin necesidad de tarjeta. Los prompts no se usan para entrenamiento.
Errores que encontrarás
| Síntoma | Causa probable | Solución |
|---|---|---|
| Conexión rechazada en el puerto 11434 | El servidor Ollama no está en ejecución | Inicia la aplicación o ejecuta ollama serve |
| Modelo no encontrado | El modelo nunca se descargó, o el nombre tiene un error tipográfico | Ejecuta ollama list, luego ollama pull el nombre que usas |
| La primera llamada se agota en tiempo de espera | El modelo aún se está cargando | Aumenta el tiempo de espera o envía una petición de calentamiento |
| Error de autenticación en la API alojada | Clave Bearer faltante o incorrecta | Comprueba LLM_API_KEY y la URL base |
HTTP 429 con código concurrency | Más de 8 peticiones en curso (2 en una clave de prueba) | Reduce el número de trabajadores |
HTTP 429 con código rate_limited | Superado el límite de peticiones por minuto | Espera y reintenta |
Las peticiones fallidas o rechazadas en el lado alojado no se cobran, por lo que la lógica de reintento no te cuesta por los intentos fallidos.
Más guías
Preguntas y respuestas
¿Cuál es la dirección predeterminada de la API de Ollama?
Un servidor Ollama local escucha en http://localhost:11434. Los endpoints nativos están bajo /api, como /api/chat, y el endpoint estilo OpenAI está bajo /v1.
¿Puedo usar el SDK de Python de OpenAI con Ollama?
Sí. Establece base_url a http://localhost:11434/v1 y pasa cualquier cadena como clave de API. El SDK entonces envía peticiones estándar de finalización de chat a tu modelo local.
¿Cómo cambio de Ollama a una API alojada?
Cambia la URL base, la clave y el nombre del modelo. Si tu código los lee de variables de entorno, no es necesario cambiar el código.
¿Funciona la API alojada sin una GPU en mi equipo?
Sí. El modelo se ejecuta en el proveedor, por lo que tu script solo necesita una conexión a internet y una clave Bearer. Pagas por token desde el crédito prepago.
Tu clave está a un formulario de distancia
Crea una cuenta, copia la clave, cambia la URL base. Esa es toda la configuración.