latentSource

Self-Hosting de IA: Ejecutando LLMs en tu propio hardware

Las APIs en la nube son convenientes pero costosas. Explora cómo ejecutar LLMs de código abierto en tus propios servidores, desde la selección de hardware hasta la optimización de la inferencia.

·7 min read
Compartir
Self-Hosting de IA: Ejecutando LLMs en tu propio hardware

La nube hizo que la IA fuera accesible. El self-hosting la hace tuya.

He estado ejecutando modelos localmente desde hace un tiempo, en parte por curiosidad y en parte porque me cansé de ver cómo las facturas de las APIs subían cada mes. La respuesta honesta es que, para muchas cargas de trabajo (workloads), el self-hosting ahora tiene sentido. No para todo, pero sí para más de lo que la gente asume.

Por qué molestarse

Hay tres razones por las que la gente termina aquí.

La primera es el costo a escala. Si haces unos pocos cientos de llamadas a la API al día, la nube gana sin duda alguna. Si haces cientos de miles, las matemáticas cambian. Una sola GPU de consumo de 24GB puede ejecutar un modelo de 32B cuantizado (quantized) con un rendimiento decente. Amortizado en un año, resulta más barato que el mismo volumen en una API de vanguardia (frontier API), y la brecha se amplía rápidamente a medida que crece tu tráfico.

La segunda es la privacidad de los datos. Hay cargas de trabajo que no quiero enviar a un tercero, punto. Documentos de clientes, repositorios internos, cualquier cosa bajo un acuerdo de confidencialidad (NDA). Ejecutar el modelo en hardware que yo controlo elimina esa preocupación. El proceso de cumplimiento (compliance) también es más sencillo cuando nada sale de la red.

La tercera es la independencia del "API drift". Los proveedores deprecian endpoints. Cambian los precios. Endurecen los límites de tasa (rate limits). A veces, intercambian silenciosamente un modelo más pequeño bajo el mismo nombre. Cuando controlas los pesos (weights), el modelo se comporta igual el martes que el lunes.

El cuello de botella del hardware es la VRAM

Olvida el cómputo, olvida los núcleos, olvida el ancho de banda por un momento. La pregunta que determina qué puedes ejecutar es: ¿cuánta memoria de GPU tienes?

Reglas generales con cuantización de 4 bits:

  • Modelo 7B → cabe en 6GB
  • Modelo 13B → cabe en 10GB
  • Modelo 32B → cabe en 20GB
  • Modelo 70B → cabe en 40GB (necesita 2x GPUs de consumo o una A6000)
  • Modelo 405B → necesita un cluster serio

Las tarjetas de 24GB (RTX 3090, 4090, A5000) son el punto ideal para el trabajo serio actualmente. Ejecutan un modelo 32B cuantizado cómodamente con espacio para el contexto. Una 3090 usada en 2024 todavía hace este trabajo perfectamente. No necesitas una H100.

La inferencia en CPU existe. Funciona. Pero es lo suficientemente lenta como para que solo la use en tareas por lotes (batch jobs) donde la latencia no importa. Para uso interactivo, la GPU es la única respuesta honesta.

El enfoque de laboratorio en casa (home-lab)

Ejecuto los míos en un solo host Proxmox con passthrough de GPU hacia un contenedor LXC dedicado. Docker encima de eso. El contenedor expone un endpoint HTTP compatible con OpenAI, y todo lo demás en mi red simplemente se comunica con eso.

Las piezas que importan:

  • Proxmox: hipervisor tipo bare-metal, gratuito, maneja el passthrough de GPU limpiamente.
  • Driver de NVIDIA + CUDA toolkit en el contenedor, coincidiendo con la versión del host.
  • Docker con GPU runtime: --gpus all y listo.
  • Un reverse proxy: yo uso Traefik para TLS, pero Caddy funciona igual de bien.

Configurar esto la primera vez me tomó una tarde. La segunda vez, veinte minutos. La parte difícil es el passthrough de GPU, y la documentación para eso ha mejorado drásticamente en el último año.

Eligiendo un modelo

Hay demasiados modelos. Así es como los filtro.

Si quiero ayuda general con chat y código, Llama 3.3 70B (o sus sucesores) es la opción por defecto. Si tengo poco espacio, Qwen 2.5 32B rinde muy por encima de su tamaño, especialmente en tareas multilingües y de razonamiento. Para máquinas muy pequeñas, Phi-4 o un Llama 3.2 3B manejan sorprendentemente bien el output estructurado y el seguimiento de instrucciones simples.

Para cualquier cosa que quiera ajustar (fine-tune), me quedo con las variantes de Mistral o Llama porque el ecosistema de herramientas (tooling) es maduro.

El benchmark que realmente me importa es: "¿funciona para mi prompt?". Guardo una carpeta con tareas representativas —una revisión de código, un refactor de SQL, un clasificador de etiquetas, un resumen largo— y las ejecuto contra cualquier modelo nuevo antes de promoverlo. Los benchmarks públicos mienten lo suficiente como para que no confíe en ellos sin una verificación de cordura (sanity check).

Frameworks de inferencia

No ejecutas los pesos brutos. Los ejecutas a través de un motor de inferencia (inference engine). Los cuatro que importan:

vLLM. Es mi opción por defecto para producción. Implementa PagedAttention, agrupa solicitudes eficientemente y maneja el continuous batching de forma nativa. El modo de API compatible con OpenAI se activa con una sola bandera. Es lo más cercano al nivel industrial en el mundo del código abierto.

llama.cpp. Escrito en C++ puro, funciona en cualquier cosa, incluyendo CPUs y Apple Silicon. Amigable con la cuantización (formato GGUF). Lo uso en mi laptop cuando estoy de viaje. Para uso en servidores, vLLM es más rápido.

Ollama. Un wrapper alrededor de llama.cpp con una experiencia de usuario (UX) de gestión de modelos mucho mejor. ollama pull qwen2.5:32b y listo. Excelente para desarrollo, aceptable para producción de bajo tráfico.

TGI (Text Generation Inference). La oferta de Hugging Face. Sólida, pero ya no veo que se elija tanto por encima de vLLM.

Ejecuto vLLM en producción y Ollama en mi laptop. Eso cubre todo lo que necesito.

Cuantización en la práctica

La cuantización es cómo logras que un modelo 32B quepa en 24GB. Los pesos en precisión completa (full-precision) necesitarían 64GB. Los comprimimos a 4 bits por peso y sacrificamos una pequeña cantidad de calidad por una reducción de memoria de 4x.

Los formatos que verás:

  • GGUF: el formato de llama.cpp. Mucho tooling, muy portátil.
  • AWQ: sensible a la activación (activation-aware). Mejor calidad con el mismo bit-rate, ligeramente más lento.
  • GPTQ: más antiguo pero bien probado. La mayoría de los modelos en Hugging Face tienen una variante GPTQ.
  • Q4_K_M: el nivel de cuantización GGUF que uso por defecto. La calidad es indistinguible de la precisión completa para cargas de trabajo tipo chat.

No he encontrado ninguna carga de trabajo donde la calidad cayera lo suficiente como para importar al pasar de FP16 a Q4_K_M. La excepción son las tareas de razonamiento pesado, donde Q5 o Q6 te devuelven una cantidad medible de precisión.

Servicio y operaciones (Ops)

Una vez que vLLM está activo, tienes un endpoint compatible con OpenAI en http://tu-host:8000/v1. Cualquier librería cliente que hable con OpenAI puede comunicarse con él. Lo único que cambias es la URL base y la clave de API.

Lo que agrego encima:

  • Un log de solicitudes (request log). Cada prompt, cada respuesta, latencia, conteo de tokens. Postgres funciona bien. Es la herramienta de depuración más barata que puedes instalar.
  • Métricas de Prometheus. vLLM las expone en /metrics. Rastrea tokens por segundo, tiempo hasta el primer token (time-to-first-token), utilización de la GPU y profundidad de la cola. Cuando la latencia se degrada, quieres saber qué palanca se movió.
  • Un health check. Un prompt de "ping" de 5 tokens cada 30 segundos. Si el modelo se queda sin memoria (OOM) o la GPU falla, te enteras de inmediato.

Para el procesamiento por lotes, vLLM lo hace por ti; el continuous batching significa que el motor llena la GPU incluso con tráfico intermitente. No necesitas programar esto tú mismo.

Cuándo el self-hosting realmente supera a la API

El punto de equilibrio está más cerca de lo que se piensa. Aproximadamente:

  • Con 1M de tokens/día en un modelo de vanguardia, la nube es más barata.
  • Con 10M de tokens/día en un modelo de nivel medio, el self-hosting en una 3090 gana.
  • Con 100M de tokens/día, el self-hosting es dramáticamente más barato y superarás la capacidad de una sola GPU.

Estos números varían según tus costos de electricidad, tu inversión inicial en hardware (capex) y con qué API estés comparando. La nube está ganando el juego de muy bajo volumen y perdiendo el de muy alto volumen. El punto medio es genuinamente una cuestión de criterio.

La carga operativa

Mentiría si dijera que esto es gratis. Heredas problemas que la API te oculta.

Las GPUs fallan. Las fuentes de poder fallan. Las actualizaciones de drivers rompen la compatibilidad con CUDA. Los modelos quedan obsoletos y tienes que decidir si actualizar. Salen nuevos motores de inferencia y tienes que decidir si migrar. Los formatos de cuantización evolucionan. Las ventanas de contexto crecen y tienes que reajustar tu configuración de servicio.

Para un equipo pequeño, eso suma quizás medio día a la semana de trabajo de operaciones, en promedio. Para un aficionado que ejecuta un modelo personal, es más cercano a una hora al mes después de la configuración inicial.

El trabajo es real. También lo es el control que obtienes a cambio. Prefiero depurar mi propia GPU que esperar a que una API se arregle sola.

Qué ejecuto realmente

Para los curiosos: una sola 3090 en un LXC de Proxmox, vLLM sirviendo Qwen 2.5 32B en Q4_K_M, detrás de Traefik con TLS. Unos 35 tokens/segundo en promedio, 60 en prompts simples, 20 en contextos largos. Costo total de electricidad: aproximadamente $15 USD/mes con mi tarifa. El hardware se pagó solo en menos de cinco meses con mi volumen. Tus números serán diferentes.

La nube está bien. El self-hosting también está bien. Elige el que mejor se adapte a lo que realmente necesitas.