Hace tan solo un par de semanas puse este tweet a modo de "idea loca" a ver si alguien estaba interesado en montar algún server de inferencia para poder correr modelos locales sin limites de tokens.
Supongo que los límites cada vez mas bajos y encima cada vez mas caros de los proveedores de modelos privados (Claude, GPT, etc) ha hecho que la gente empiece a tomar cada vez más enserio la necesidad de probar alternativas.
Así nació NaN una comunidad de builders que necesitan quemar tokens enserio y los límites de los modelos privados empezaban a quedarse cortos o demasiado caros. En este post os cuento cómo estan montados los servidores de inferencia de la comunidad.
Hardware
Todos nuestros servers -de momento- van a tener esta configuración:
Para poder acceder/controlar la GPU, al ser de la familia Blackwell, hemos instalado los drivers del paquete nvidia-driver-570-open y el cuda-toolkit
Modelos
Por no aburriros probamos varios modelos pero finalmente estamos sirviendo los siguientes aunque cada 3 meses los sacaremos a votación para rotar por otros más nuevos/potentes o mantenerlos:
Stack de inferencia
Bien, tras este contexto vamos a lo interesante, esta es la aquitectura que tiene el servidor:
⚠️ En este esquema se muestra la arquitectura de un solo servidor pero siguiendo esta misma base se puede escalar en horizontal tranquilamente. Es lo que estamos haciendo en NaN
El servidor tiene 4 capas, de mas bajo a mas alto nivel son:
Modelos: los modelos descargados que van a correr en el servidor. En nuestro caso solo el LLM elegido se carga vRAM y corre en GPU. El resto dado que tienen mucha menos demanda y no requerimos una velocidad enorme, corren en CPU y se cargan en la RAM del sistema.
Model Serving: Dependiendo del modelo utilizamos un server específico. Me centraré en vLLM ya que es la pieza clave que nos permite paralelizar peticiones, el manejo de memoria y nos ayuda con la misma inferencia del modelo LLM. Dentro de Hugging Face podréis ver los parámetros recomendados para poder servir el modelo, por ejemplo, para nuestro modelo actual: link. Por no alargar el post, citaré los parámetros mas importantes que hemos configurado para mejorar la inferencia del modelo:
--max-model-len 131072: Qwen 3.6 tiene una ventana de contexto nativa de 128K tokens.
--reasoning-parser qwen3: Indicamos este pero es necesario asegurarse que tienes los parsers adecuados para que el modelo pueda interpretar correctamente todo lo que le llega sino puedes tener clientes que ven la cadena de pensamiento junto con la respuesta mezclada y otros problemas.
--mm-encoder-attn-backend TORCH_SDPA: Necesario para el codificador multimodal (visión) de Qwen3.6. Sin él, el codificador utiliza un backend de atención que puede no estar disponible en todas las arquitecturas de GPU.
--chat-template chat_template_fixed.jinja: Este template es utilizado por el modelo para saber qué ocurre durante un chat según las etiquetas XML que le llegan. Ejemplo <think> Con esto el modelo etiqueta su cadena de pensamiento. Este template tiene un bug que afecta a versiones anteriores de Qwen pero también a modelos de otras familias como Kimi. El fix aplicado es el mismo que está a la espera de hacer merge en vLLM: bug
--speculative-config '{"method":"mtp","num_speculative_tokens": 2}': Este parámetro es puro fine-tunning. Por resumir mucho este parámetro permite "adivina" 2 tokens extra en cada paso de generación. Si la predicción es correcta (lo cual ocurre el 80-92% de las veces), se aceptan todos de golpe, duplicando la velocidad de generación de tokens sin coste adicional de memoria. Gracias a este parámetro hemos conseguido:
- ~2x boost de throughput
- 80-92% de tasa de aceptación de los tokens especulados
- Longitud media de aceptación de ~2.6 tokens
API GW: LiteLLM es el elemento que nos permite servir bajo una misma API todos los modelos. Además nos da la capa de autenticación/autorización para poder proporcionar una API Key a cada uno de los miembros de la comunidad.
No solo eso, sino que nos permite medir y añadir algo de hardening a nivel de inferencia para evitar DDoS, abusos o que alguien quiera acaparar la GPU para si mismo afectando al resto de usuarios. Algunos de los limits aplicados por cada API Key mas importantes que tenemos son (tenemos usuarios que queman +300 millones de tokens diarios y no llegan a estos límites):
- 100 RPM
- 5 Request paralelas máximo por minuto
NO hay limites de tokens, ni limites de uso como los proveedores de privados
Reverse Proxy: Este servidor web, resumiendo, nos permite exponer a internet el endpoint que necesitan los miembros de la comunidad para consumir los modelos y prohibir el acceso a todos los endpoints que no son imprescindibles para proporcionar el servicio de inferencia.
En el esquema no se muestra tres capas importantes de securización:
- Cloudflare: donde tenemos el SSL estricto con el server y túneles (este no directamente para la inferencia pero estamos trabajando para que en breve el server no sea solo inferencia ya os contaré).
- VPN: el acceso a todos los paneles, gráficas y endpoints privados se realiza vía VPN. No hay nada mas que el endpoint de inferencia expuesto a internet.
- Hardening: como a cualquier otro servidor hay que hacerle las reglas básicas de seguridad (bloquear el acceso por password, prohibir acceso root, etc.) Me saltaré esta parte a modo de resumir el post y porque además hay 400 posts haciendo esto para cualquier server Linux.
Monitoring
El servidor está completamente monitorizado, desde lo mas básico en LiteLLM (Gráfico de tokens quemados en 5 días):
Pasando por el estado y uso de la GPU:
Incluso métricas de uso de modelos, users, clientes, etc
Cada dashboard tiene mucha mas información pero las capturas son un pequeño detalle de todo lo que hay monitorizado. El stack utilizado es:
- Prometheus (métricas)
- Grafana (Dashboards y alertas)
- El propio LiteLLM con sus métricas
Tenemos alertas de todo tipo para detectar errores y poder actuar proactivamente.
Privacidad
En LiteLLM tenemos desactivado cualquier tracking de input/output más allá de métricas básicas para controlar el estado del servidor (tokens/s, requests, modelos más llamados, etc) pero en NINGUN caso se registra ningún tipo de dato ni en el servidor ni en logs. Todo es pura inferencia y el contexto vive mientras mantienes una sesión activa. Tras esto desaparece.
Dado que no hay datos, nada de lo que ocurre en el servidor es utilizado para un entrenamiento o tratado posterior. Cosa que sí ocurre cuando utilizas clientes o providers de modelos privados.
Reflexión final
Como veis montar un server de inferencia no es nada del otro mundo, sin embargo, la “dificultad” viene en saber detectar errores. Ya sea en la capa de “Model Serving” que suele ser lo mas habitual con los parsers, etc o también es muy frecuente que en el cliente/agente/IDE de turno falle algo en especial y toque buscar una configuración concreta para evitar estos problemas.
En la comunidad han ido compartiendo diferentes miembros sus configuraciones y estamos intentando recopilar la mayor parte de ellas en nuestra documentación:
https://nan.builders/docs/examples
En Twitter , estoy contando todos los días las diferentes pruebas que voy haciendo y sus resultados, tanto los buenos como los malos. Estaré encantado de escuchar vuestro feedback o ideas sobre todo esto.
Recordad que seguiremos añadiendo cada vez mas servers a la comunidad para que todos podamos quemar tokens sin miedo a llegar a limites. En NaN ya somos +50 miembros y tenemos en lista de espera a +150 personas. ¡Se vienen curvas!
¡Hasta la próxima! 🖖