Si estás usando Ollama en producción para servir modelos LLM, seguramente ya te habrás dado cuenta de que no es solo “instalar y tirar”. Entre la elección del modelo, la cuantización, la VRAM justa, el número de peticiones simultáneas y los agentes multietapa, es muy fácil acabar con respuestas lentas, errores 503 o incluso cuelgues por falta de memoria.
La buena noticia es que, conociendo cómo gestiona Ollama la concurrencia, las colas y la memoria, y aplicando unas cuantas buenas prácticas de arquitectura y de sistema, se puede exprimir muchísimo más el rendimiento, tanto en GPU como en CPU. Además, se puede hacer sin renunciar a la privacidad de los datos ni a la flexibilidad de los modelos locales.
Ollama y llama.cpp en producción: piezas y roles
Antes de afinar nada, conviene entender bien quién hace qué. llama.cpp es el motor de inferencia, extremadamente optimizado en C++ para sacar el máximo partido al hardware (CPU, Apple Silicon, NVIDIA, AMD). Ollama es la “envoltura” de alto nivel que orquesta ese motor y otros backends (como vLLM en algunos casos), exponiendo un CLI sencillo y una API REST lista para usar.
En la práctica, cuando lanzas un modelo con Ollama, lo que ocurre es que la aplicación (escrita en Go) levanta un proceso hijo que ejecuta llama.cpp (u otro runtime compatible), gestiona la descarga de pesos, la configuración de GPU/CPU, el tamaño de contexto y la vida útil del modelo en memoria. Esto simplifica mucho la operación en producción frente a usar llama.cpp a pelo, donde tendrías que compilarlo, gestionar rutas, parámetros como –n-gpu-layers, cuantización, etc.
Si pensamos en analogías, llama.cpp es el quirófano de tensores: minimalista, afinado para sacar cada ciclo de CPU/GPU. Ollama es el “IKEA” de la IA local: te da un sistema ya empaquetado con gestión de modelos, API estándar, cola de peticiones y autoajuste de hardware, ideal para entornos productivos donde no se quiere pelear con cada bandera de compilación.

Requisitos de hardware y selección de modelos para producción
Una parte clave para que la cosa vaya fluida es no pasarse de ambicioso con el tamaño del modelo respecto a tu hardware. La combinación parámetros del modelo + tipo de cuantización + longitud de contexto determina RAM, VRAM y tiempos de inferencia.
De forma orientativa, para producción con Ollama en una sola máquina, se suele trabajar con estas franjas:
- 8 GB de RAM: modelos pequeños (1B, 3B, 7B cuantizados). Válidos para prototipos y pequeños servicios, pero la fluidez puede resentirse con cargas serias.
- 16 GB de RAM: punto razonable para modelos de 7B y 13B cuantizados tipo Q4_K_M. Se puede dar servicio real si se controla bien la concurrencia.
- 32 GB o más: recomendado si quieres jugar con modelos de 30B, 40B o 70B, o si piensas servir varios modelos en paralelo.
En GPU, el patrón es similar: a mayor VRAM, más capas puedes descargar a la gráfica y más throughput lograrás. Con una GPU de 16 GB se pueden servir cómodamente modelos de 7B-13B bien cuantizados, mientras que para 70B ya hablas de hardware de gama muy alta o varias GPUs.
En cuanto a almacenamiento, hay que tener en mente que los modelos cuantizados “pequeños” pueden ocupar 2 GB, los medianos 5 GB o más y los muy grandes decenas o incluso cientos de gigas. Un SSD NVMe marca la diferencia al cargar o intercambiar modelos.
Por último, la CPU sigue importando, sobre todo si haces inferencia solo con procesador o combinada con GPU. 4 núcleos es el mínimo aceptable; para un servicio estable con varias peticiones concurrentes, lo ideal son 8 núcleos o más.
Cuantización y formatos de modelo: cómo ganar rendimiento sin matar la calidad
Para que un LLM sea utilizable en producción, casi siempre necesitas alguna forma de cuantización. Es el proceso de pasar de pesos en coma flotante (FP16, FP32) a representaciones en enteros de menos bits (4, 8, etc.), reduciendo el tamaño del modelo y la memoria que consume, a costa de una ligera pérdida de precisión.
Una regla práctica muy repetida en la comunidad es que Q4_K_M es el estándar razonable para local: reduce el tamaño a roughly la mitad frente a FP16, la pérdida de calidad es de alrededor de 1-2 % en métricas como la perplexity y la velocidad de inferencia sube bastante. Si necesitas aún más compresión, puedes bajar a Q3 o Q2, pero a costa de más alucinaciones y peor razonamiento.
Para usar modelos con Ollama, el formato rey es GGUF, que empaqueta pesos, metadatos y tokenizador de forma optimizada para runtimes tipo llama.cpp. Muchos modelos de la biblioteca de Ollama ya vienen en GGUF y cuantizados, así que basta un ollama pull. Si traes modelos externos (por ejemplo, desde Hugging Face), puedes:
- Convertir de formatos como Safetensors a GGUF usando las herramientas de llama.cpp (scripts como convert_hf_to_gguf.py).
- Cuantizarlos con el binario quantize de llama.cpp eligiendo el esquema (Q4_K_M, Q5_K_S, etc.).
- Crear un Modelfile en Ollama apuntando al .gguf y definiendo plantilla, parámetros por defecto y sistema.
Este flujo de descargar → convertir → cuantizar → registrar en Ollama permite integrar modelos de nicho en producción, como LLMs jurídicos (ej. uno tipo Jurema-7B) o específicos de dominio, manteniendo el mismo pipeline de despliegue.
Parámetros internos del modelo: num_ctx, temperatura y control de salida
Una vez elegido el modelo, toca domar su comportamiento. En producción, no te vale con que “responda bonito”; tiene que ser predecible, acotado y eficiente. Los parámetros clave que expone Ollama (heredados de llama.cpp) son:
Por un lado está num_ctx, la ventana de contexto. Define cuántos tokens puede tener en cuenta el modelo simultáneamente: mensajes de sistema, historial de chat y prompt actual. Ventanas más grandes permiten conversaciones largas y análisis de documentos extensos, pero disparan el consumo de RAM/VRAM y el tiempo de cálculo. Además, si pones un valor por encima de lo que el modelo fue entrenado para manejar, pueden aparecer comportamientos raros o degradación.
También es crucial controlar la generación con num_predict (máximo de tokens de salida), listas de stop y temperatura. Un valor de temperatura bajo (0,2-0,5) produce respuestas más estables y menos creativas, ideal para RAG, codificación o verificaciones. Valores altos se dejan para usos creativos, que rara vez son escenarios de producción serios.
Además, opciones como top_p y top_k ayudan a limitar la aleatoriedad. Reducir top_p a valores moderados (por ejemplo, 0,8-0,9) restringe el espacio de tokens posibles, algo útil para disminuir alucinaciones y conseguir salidas más repetibles.
Todos estos parámetros se pueden fijar de forma persistente en el Modelfile mediante instrucciones PARAMETER, sobreescribir puntualmente con la CLI (comando /set en modo interactivo) o pasar dinámicamente por API REST en el campo options del JSON.
Concurrencia, colas y batching en Ollama: exprimir la máquina sin matarla
El verdadero salto de “juguete local” a servicio en producción llega cuando empiezas a tener varias solicitudes al mismo tiempo. Ollama incorpora su propio sistema de concurrencia y colas para gestionar esto sin que tengas que montar un servidor adicional.
La pieza central es la variable de entorno OLLAMA_NUM_PARALLEL, que define cuántas peticiones puede procesar en paralelo un modelo cargado. Por defecto suele ser 4 (o 1 si la memoria es limitada). Valores más altos aumentan el throughput si tienes margen de CPU/GPU y VRAM, pero también suben la presión sobre la memoria y pueden empeorar la latencia de cada request individual.
Cuando varias solicitudes entran para el mismo modelo, Ollama intenta hacer batching: agrupa peticiones y las procesa juntas, aprovechando mejor las operaciones de matrices en GPU. Desde fuera, los usuarios ven cómo las respuestas se empiezan a transmitir al mismo tiempo. Si llegan más peticiones de las que permite OLLAMA_NUM_PARALLEL, entran en una cola FIFO regulada por OLLAMA_MAX_QUEUE, que por defecto es 512.
Si la cola se llena, Ollama devuelve errores 503 (“Servidor sobrecargado”). Y si la memoria está al límite, entra en juego otro límite, OLLAMA_MAX_LOADED_MODELS, que indica cuántos modelos pueden estar cargados simultáneamente. Cuando se necesita cargar uno nuevo y no hay memoria suficiente, se descargan modelos inactivos y la solicitud espera hasta que el nuevo modelo está listo.
En despliegues reales, una receta habitual es empezar con OLLAMA_NUM_PARALLEL=1 o 2 para priorizar estabilidad, monitorizar uso de CPU, VRAM y latencia p95, e ir subiendo poco a poco mientras no aparezcan errores de falta de memoria ni picos de cola.
Estrategias de gestión de memoria en Ollama
La memoria (RAM y VRAM) es el recurso crítico en cualquier servicio de LLM local. Ollama combina varias estrategias para evitar reventar el sistema cuando llegan más solicitudes de las que caben en memoria o cuando pretendes usar modelos demasiado grandes para tu máquina.
Por un lado, usa una cola FIFO controlada por OLLAMA_MAX_QUEUE para no rechazar de golpe todas las solicitudes cuando no hay memoria inmediata disponible. Si la cola se satura, devuelve 503 de forma explícita en vez de dejar que el proceso muera sin más.
Por otro, mantiene un número acotado de modelos cargados en memoria mediante OLLAMA_MAX_LOADED_MODELS (por defecto, 3 por cada GPU o 3 en CPU). Los modelos inactivos durante cierto tiempo se pueden descargar automáticamente, liberando VRAM y RAM para solicitudes posteriores.
También entra en juego el parámetro OLLAMA_KEEP_ALIVE, que define cuánto tiempo permanece un modelo en memoria tras la última petición. Con valores como 5 minutos, se evita recargar el modelo en cada request, pero no se eterniza en RAM. Con 0, el modelo se descarga inmediatamente al terminar, ahorrando memoria pero penalizando tiempo de arranque; con -1, se mantiene de forma indefinida mientras el servidor esté activo.
En situaciones extremas de presión de memoria, el sistema operativo puede recurrir a swap en disco, lo que degrada muchísimo el rendimiento, o incluso provocar errores “out of memory” y caída de la instancia. Por eso es vital ajustar: tamaño del modelo, cuantización, longitud de contexto, número de solicitudes paralelas y modelos simultáneos cargados.
CPU vs GPU en entornos de producción con Ollama
No todo el mundo dispone de GPUs potentes en producción, especialmente si se despliega en servidores económicos o portátiles. De ahí el interés creciente en optimizar la inferencia solo con CPU, escogiendo modelos ligeros y bien cuantizados que permitan latencias razonables.
Para CPU pura, las mejores prácticas pasan por elegir modelos de 2B, 3B o 7B cuantizados (Q4_K_M, Q5, etc.), usar tamaños de contexto moderados y limitar el número de peticiones en paralelo. Ajustar OLLAMA_NUM_THREADS al número de núcleos físicos (o un poco menos) ayuda a equilibrar rendimiento y uso de recursos, evitando saturar el sistema.
Si dispones de GPU, es fundamental comprobar, mediante ollama ps, que el modelo está realmente usando la gráfica (idealmente “100% GPU” en el campo PROCESSOR). Configuraciones que mezclan demasiadas capas en CPU y GPU tienden a dar rendimientos pobres; en entornos con VRAM suficiente, interesa descargar tantas capas como sea posible a la GPU.
Para activar explicitamente la aceleración, en algunos entornos hay que exportar variables como OLLAMA_CUDA=1 o configurar correctamente los controladores de NVIDIA/AMD. Si ves errores tipo “CUDA error” o “ROCm error” en los logs, probablemente haya un problema de drivers o de compatibilidad de hardware.
Configuración avanzada: variables de entorno y despliegue estable
Más allá de los parámetros de inferencia, Ollama se puede afinar con un buen puñado de variables de entorno que definen red, rutas, CORS, logging y comportamiento de carga de modelos. En producción es habitual tocar al menos las siguientes:
Por un lado, OLLAMA_HOST define en qué interfaz y puerto escucha la API. Por defecto es 127.0.0.1:11434, es decir, solo accesible en local. Si quieres exponerlo a la red interna, puedes cambiarlo a 0.0.0.0:11434 o a una IP concreta, siempre protegida con firewall o proxy inverso.
Otro ajuste muy útil es OLLAMA_MODELS, que permite mover la carpeta donde se almacenan los modelos a otro disco o volumen (por ejemplo, un SSD grande). Eso te da flexibilidad para gestionar espacio y backups, siempre que el usuario que ejecuta el servicio tenga permisos de lectura y escritura en esa ruta.
Para integrar frontends web como Open WebUI u otras GUIs, necesitas ajustar OLLAMA_ORIGINS, que controla los orígenes permitidos en CORS. Puedes especificar dominios concretos (http://localhost:3000, etc.) o usar “*” para permitir todos, algo que solo tiene sentido si el servicio no está expuesto más allá de una red muy controlada.
Durante el despliegue y la resolución de problemas, resulta muy útil habilitar OLLAMA_DEBUG=1 para ver logs detallados: detección de GPUs, carga de blobs de modelo, tiempos de respuesta, errores específicos, etc. En Linux, esos logs se consultan cómodamente con journalctl -u ollama, pudiendo redirigirlos a ficheros o filtrarlos por fecha.
La forma concreta de establecer estas variables depende del entorno: en Linux se hace típicamente con un override de systemd para el servicio ollama.service, en macOS vía launchctl, en Windows con las variables de entorno del sistema, y en Docker a través de la opción -e en docker run.
Gestión de modelos, Modelfiles y flujos con varios LLM
Tras la parte de sistema, toca pensar en cómo organizar los modelos. Ollama ofrece un catálogo propio que se maneja con comandos como ollama pull, ollama list, ollama rm y ollama push. Esto último permite subir modelos personalizados a su registry, facilitando distribución y versionado dentro de equipos o empresas.
Para personalizar el comportamiento de un modelo (tono, plantilla de prompt, parámetros por defecto), se utiliza el sistema de Modelfiles. En estos ficheros se define, por ejemplo, la instrucción FROM con la ruta al .gguf, las líneas PARAMETER (temperatura, num_ctx, num_predict, top_p, etc.) y una plantilla (TEMPLATE) que especifica cómo se estructura el prompt (mensajes de sistema, usuario, asistente, delimitadores).
Con ollama create puedes compilar un Modelfile y registrar un nuevo modelo lógico en el sistema, sin duplicar físicamente los pesos en disco. Esto es muy útil para generar múltiples variantes de un mismo modelo base (por ejemplo, una para uso general, otra optimizada para código, otra para estilo formal, etc.).
En arquitecturas con agentes o flujos multietapa (RAG + guardarraíl + evaluación de documentos + expansión de consultas + verificación de alucinaciones), es habitual combinar varios modelos: uno generalista, uno pequeño y rápido para clasificación/guardrails, y quizá uno especializado en dominio. Aquí vuelve a ser fundamental ajustar bien OLLAMA_MAX_LOADED_MODELS y KEEP_ALIVE para evitar cargar y descargar modelos constantemente.
Por último, la API REST de Ollama expone endpoints para chat, generación, embeddings y gestión de modelos, lo que permite integrarlo fácilmente con orquestadores de agentes como LangGraph, así como con aplicaciones backend en Python, JavaScript, PHP, etc., añadiendo reintentos con jitter y conexiones keep-alive en el lado cliente para esquivar picos puntuales de cola.
Con todo esto, se puede pasar de un simple “juguete” de IA local a una plataforma robusta de LLMs en producción, con control fino de rendimiento, memoria y comportamiento, manteniendo los datos bajo tu propia infraestructura y sin depender completamente de proveedores cloud externos, algo especialmente valioso en escenarios con requisitos de privacidad, costes ajustados o necesidad de personalización profunda.