Qué se construye con esto
Una instancia de GPU que sirve un modelo de pesos abiertos sobre una API HTTP que habla el esquema compatible con OpenAI, de modo que todas las bibliotecas de cliente que ya tengas funcionen con solo cambiar la URL base. Detrás de nginx, con TLS, una clave de API y una unidad de systemd que sobrevive a los reinicios.
Escrito en una G-L40S: cuarenta y ocho gigabytes de VRAM en una sola tarjeta, pasada a la instancia a través de PCIe en lugar de ser troceada en tiempo entre varios inquilinos. Esa distinción es la diferencia entre una latencia predecible y esperar detrás del trabajo de entrenamiento de otro. La tarjeta es tuya hasta que la canceles.
Antes de empezar
- Una G-L40S con Debian 13. La G-ADA de veinte gigabytes sirve para modelos más pequeños; la aritmética del paso cuatro indica cuáles.
- Dos terabytes de NVMe en este plan, que es el lugar adecuado para los pesos. Descargar cuarenta gigabytes dos veces porque la caché estaba en el sistema de archivos raíz es una forma molesta de gastar una hora.
- Un nombre de host que apunte a la instancia,
llm.example.commás abajo.
1. Controlador
sed -i "s/ main$/ main contrib non-free-firmware non-free/" /etc/apt/sources.list.d/debian.sources
apt update
apt install -y nvidia-driver firmware-misc-nonfree build-essential
rebootDespués de que vuelva:
nvidia-smiQuieres que la tarjeta aparezca listada, que se imprima la versión del controlador y que el uso de memoria esté cerca de cero. Una tarjeta que no aparece en este punto casi siempre se debe a un initramfs obsoleto; update-initramfs -u y reinicia una vez más antes de abrir un ticket.
nvidia-smi -q -d PERFORMANCE | grep -A3 "Clocks Event Reasons"
nvidia-smi -pm 1El modo de persistencia mantiene el controlador cargado entre procesos, lo que elimina varios segundos de inicialización en cada reinicio.
2. Entorno de ejecución
apt install -y python3-venv python3-pip
install -d -o root -g root /srv/models /opt/vllm
python3 -m venv /opt/vllm/venv
/opt/vllm/venv/bin/pip install --upgrade pip
/opt/vllm/venv/bin/pip install vllmLa instalación descarga un conjunto grande de wheels vinculados a CUDA y tarda un rato. Mientras tanto, decide qué modelo usar.
3. Elegir lo que cabe
Los pesos son el mínimo, no el presupuesto. Un modelo con precisión de dieciséis bits necesita aproximadamente dos gigabytes de VRAM por cada mil millones de parámetros, más la caché de clave-valor para cada solicitud concurrente, más un gigabyte o así de sobrecarga de ejecución.
| Tarjeta | Pesos a 16 bits | Tamaño realista del modelo | Espacio para caché |
|---|---|---|---|
| L40S, 48 GB | 2 GB por mil millones | Hasta unos 20 mil millones | 6 a 8 GB |
| L40S, 48 GB, 8 bits | 1 GB por mil millones | Hasta unos 34 mil millones | 10 GB |
| RTX 4000 Ada, 20 GB | 2 GB por mil millones | Hasta unos 7 mil millones | 5 GB |
| Dos × L40S, 96 GB | 2 GB por mil millones | Hasta unos 40 mil millones | 12 GB |
La columna de caché determina cuántas personas pueden usar el endpoint a la vez. Llena la tarjeta hasta el borde con pesos y habrás construido un juguete de un solo usuario muy rápido.
4. Servirlo
Apunta la caché al NVMe y arranca el servidor. Sustituye el identificador de repositorio del modelo de pesos abiertos que hayas elegido; el entorno lo descarga en el primer arranque.
cat > /etc/systemd/system/vllm.service <<EOF
[Unit]
Description=vLLM inference server
After=network-online.target
[Service]
Environment=HF_HOME=/srv/models
Environment=VLLM_API_KEY=<a long random string>
ExecStart=/opt/vllm/venv/bin/vllm serve <org>/<model> \\
--host 127.0.0.1 --port 8000 \\
--served-model-name local \\
--max-model-len 16384 \\
--gpu-memory-utilization 0.92 \\
--max-num-seqs 32
Restart=on-failure
RestartSec=10
TimeoutStartSec=1800
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable --now vllm
journalctl -fu vllmEnlazar a loopback es intencionado. La verificación de la clave de API en el entorno es un secreto compartido único sin límite de tasa detrás, así que nginx hace la exposición y el entorno nunca toca la interfaz pública.
El tiempo de arranque generoso existe porque el primer lanzamiento descarga decenas de gigabytes y luego compila los kernels. Los arranques posteriores tardan menos de un minuto.
5. Proxy y TLS
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name llm.example.com;
ssl_certificate /etc/letsencrypt/live/llm.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;
location /v1/ {
proxy_pass http://127.0.0.1:8000;
proxy_buffering off;
proxy_read_timeout 600s;
proxy_set_header Host $host;
}
}proxy_buffering off es la línea que hace que las respuestas de streaming fluyan. Déjala activada y los tokens llegarán en lotes educados siempre que nginx considere que un búfer está lleno, lo que parece exactamente un modelo lento, pero no lo es.
Verifícalo
Empieza por la tarjeta:
nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csvLa memoria usada debe estar alrededor del noventa por ciento del total, porque eso es lo que pidió --gpu-memory-utilization. Luego el endpoint:
curl -s https://llm.example.com/v1/models -H "Authorization: Bearer <the key>" | head -20Un modelo, llamado local. Ahora una generación real, y cronométrale algo:
time curl -s https://llm.example.com/v1/chat/completions \
-H "Authorization: Bearer <the key>" \
-H "Content-Type: application/json" \
-d '{"model":"local","messages":[{"role":"user","content":"List three prime numbers."}],"max_tokens":64}'Por último, mídela bajo carga en lugar de con una sola solicitud a la vez, que es el único número que vale la pena citar:
/opt/vllm/venv/bin/vllm bench serve \
--backend openai-chat \
--base-url https://llm.example.com \
--endpoint /v1/chat/completions \
--model local --num-prompts 200 --request-rate 8Lee tres números de la salida: tokens de salida por segundo en agregado, mediana del tiempo al primer token y percentil noventa y nueve de extremo a extremo. En una sola L40S con un modelo en el rango de diez a veinte mil millones, un rendimiento de salida agregado de varios cientos de tokens por segundo y un tiempo al primer token muy por debajo de un segundo es la forma esperada. Un tiempo al primer token que sube con la concurrencia significa que tu caché de clave-valor es demasiado pequeña, así que baja --max-model-len o --max-num-seqs y ejecútalo de nuevo.
Después
Vigila la temperatura y la limitación de reloj durante la primera semana con nvidia-smi dmon, ya que una tarjeta que se limita térmicamente bajo carga sostenida produce exactamente ese tipo de lentitud intermitente que se achaca a la red. En cuanto a la factura, recuerda que una instancia de GPU cuesta lo mismo tanto si la tarjeta está ocupada como inactiva, así que agrupa el trabajo en lugar de dejarla encendida. Los precios están en la página de GPU.