De Ollama a Producción: Lecciones de un Año Corriendo LLMs en Casa
Hace exactamente un año desplegué mi primer modelo local con Ollama en un servidor casero. Era una prueba: Llama 2 7B, cuatro núcleos de un i5-10400, sin GPU, y la sensación de que esto no pasaba de experimento. Doce meses después, esa misma máquina (ya con una RTX 3060 12GB y 64GB de RAM) procesa centenares de consultas diarias para automatizaciones, análisis de documentos y un asistente de código interno. El camino entre esos dos puntos está lleno de decisiones técnicas que no encontrarás en los tutoriales de cinco minutos.
La ilusión del ollama run
Los tutoriales de inicio rápido mienten por omisión. No es que sean incorrectos: es que detallan el 5% del problema. Cuando ejecutas ollama run llama3 en tu portátil y obtienes una respuesta coherente, crees que el resto es pura escalada. No lo es. La diferencia entre un modelo ejecutándose y una infraestructura productiva es abismal, y cruza dimensiones que el desarrollador medio no anticipa: gestión de memoria GPU/CPU, concurrencia de peticiones, persistencia de contexto, seguridad del endpoint, actualización de modelos sin cortar servicio, y monitorización de algo que no emite métricas por defecto.
Mi primer error fue asumir que Ollama funcionaba como un servidor tradicional. No es un servidor: es un gestor de modelos con una API HTTP ligera. No tiene balanceo de carga, no tiene colas de peticiones inteligentes, no tiene autenticación nativa más allá de la básica, y su sistema de caché de modelos en VRAM es agresivo hasta el punto de bloquear peticiones cuando la memoria está saturada. En producción, eso se traduce en tiempos de respuesta que pasan de dos segundos a treinta sin explicación aparente.
Hardware: La matemática que nadie te explica
La regla generalizada es que necesitas 1GB de VRAM por cada mil millones de parámetros en cuantización Q4_K_M. Eso es cierto para cargar el modelo, pero no para operarlo. Cuando procesas una petición, la VRAM se consume en tres capas: los pesos del modelo (constante), el contexto activo (crece con la longitud de la conversación), y los tensores temporales de atención (pueden duplicar el consumo en modelos grandes). Un modelo de 7B que cabe en 4GB de VRAM puede requerir 8GB cuando procesa un prompt de 4.000 tokens con un contexto acumulado extenso.
Durante el primer mes, mi servidor con RTX 3060 12GB corría Mistral 7B, Llama 3 8B y una instancia de Stable Diffusion. Cada vez que alguien usaba el chat y otro usuario generaba una imagen, Ollama se veía forzado a descargar el modelo de VRAM a RAM, procesaba la petición de Stable Diffusion, y luego recargaba los pesos. El proceso tomaba entre quince y treinta segundos. La solución no fue más hardware: fue separar servicios en máquinas distintas. La GPU dedicada a LLMs no compite con otros workloads, punto.
La arquitectura que realmente funciona
Después de iterar cuatro veces, la arquitectura estable consta de cinco componentes separados. Primero, el backend de modelos propiamente dicho: en mi caso, Ollama ejecutándose en un servidor dedicado con una RTX 3060. Segundo, un proxy de enrutamiento (LiteLLM) que centraliza el acceso, maneja múltiples modelos como endpoints unificados, y añade autenticación por API key. Tercero, una interfaz de usuario para interacción humana (OpenWebUI) que consume el proxy en lugar de Ollama directamente. Cuarto, un sistema de RAG vectorial (Qdrant) para consultas sobre documentación interna. Quinto, una cola de procesamiento asíncrono (Celery con Redis) para tareas que no requieren respuesta inmediata, como resumen de documentos largos o generación de embeddings por lotes.
Esta separación no es over-engineering. Es la diferencia entre un sistema que se cae cuando dos personas lo usan simultáneamente y uno que soporta quince usuarios concurrentes sin degradación perceptible. Cuando Ollama está ocupado procesando una petición larga, el proxy responde con un error controlado o enruta a otro modelo disponible. La interfaz no se cuelga esperando. Las tareas pesadas van a la cola y notifican cuando terminan. Cada pieza tiene una responsabilidad única.
Seguridad: El agujero negro del self-hosting
Ollama expone su API en localhost:11434 por defecto. La mayoría de tutoriales explican cómo exponerlo al exterior con un simple reverse proxy. Eso es catastrófico. En mi primer mes, accidentalmente dejé el puerto 11434 abierto en el firewall durante una hora. Fue suficiente para que un escaneo automático lo detectara y comenzaran a llegar peticiones desde IPs de Rusia y China. Ninguna autenticación, sin rate limiting, con acceso directo a los modelos.
La configuración mínima de seguridad incluye tres capas. Primera: el proxy inverso (Nginx o Traefik) con autenticación JWT o API keys, nunca expongas Ollama directamente. Segunda: rate limiting agresivo, máximo diez peticiones por minuto por usuario para prevenir abuso. Tercera: red interna aislada, los contenedores de Ollama y las aplicaciones deben comunicarse a través de una red Docker interna, no mediante puertos publicados. Cuarta: monitorización de logs con alertas por patrones de uso anómalo. Un solo usuario haciendo mil peticiones en una hora es señal de compromiso o de bucle infinito en algún cliente.
El verdadero coste de mantener un LLM local
El cálculo económico del self-hosting de LLMs raramente es honesto. Se suma el coste del hardware y se divide por la vida útil esperada. Eso ignora la electricidad, el tiempo de mantenimiento, las actualizaciones, y el coste de oportunidad de no usar una API comercial. En mi caso, el servidor dedicado consume aproximadamente 150W bajo carga. A 0,15€/kWh, eso son unos 16€ mensuales solo en electricidad. Añade la amortización del hardware (800€ de servidor usado con GPU durante tres años: 22€/mes), backups, y un par de horas semanales de mantenimiento. El total real ronda los 45-50€ mensuales.
Comparado con APIs comerciales, el punto de equilibrio depende del volumen. Si procesas menos de dos millones de tokens al mes, es más barato usar Claude Haiku o GPT-4o-mini. El self-hosting solo tiene sentido económico a volumen alto, cuando necesitas privacidad absoluta de datos, o cuando requieres latencias bajas para integraciones locales. No es más barato por defecto: es más controlable.
Lo que cambiaría si empezara hoy
Con la perspectiva de doce meses, hay decisiones que tomaría diferente. Primero: empezar con vLLM en lugar de Ollama. Ollama es excelente para prototipos, pero vLLM ofrece batching continuo, chunked prefill, y throughput superior en producción. Segundo: invertir en una GPU con más VRAM desde el principio. Los 12GB de la RTX 3060 se quedan cortos rápidamente; una RTX 3090/4090 con 24GB habría evitado una migración completa a los seis meses. Tercero: automatizar el despliegue desde el día uno. Mi infraestructura actual está gestionada con Ansible y Docker Compose; los primeros tres meses fueron pura configuración manual repetida.
Cuarto: medir desde el principio. No tenía métricas de uso, latencia ni errores durante los primeros meses. Cuando surgieron problemas, diagnosticarlos era adivinación. Prometheus y Grafana deberían haber sido parte del stack inicial, no un añadido posterior.
Conclusión
Un año después, mantener LLMs locales sigue siendo un compromiso. No es más fácil que usar APIs comerciales. Requiere hardware dedicado, conocimiento de infraestructura, tiempo de mantenimiento, y tolerancia a problemas técnicos. Pero ofrece algo que ninguna API puede proporcionar: soberanía completa sobre los datos, latencia cero para integraciones locales, y la capacidad de experimentar con modelos sin depender de cuotas ni políticas de uso ajenas.
Si estás considerando el salto, hazlo con los ojos abiertos. No es un reemplazo drop-in de OpenAI. Es una arquitectura diferente con compensaciones propias. Empieza pequeño, mide todo, y escala solo cuando el uso real lo justifique. Los modelos locales son infraestructura, no magia. Y la infraestructura bien hecha siempre requiere trabajo.