Ce que cela construit
Une instance GPU servant un modèle open-weights sur une API HTTP qui parle le schéma compatible OpenAI, donc chaque bibliothèque client que vous possédez déjà fonctionne avec une simple URL de base modifiée. Derrière nginx, avec TLS, une clé API et une unité systemd qui survit aux redémarrages.
Écrit sur un G-L40S : quarante-huit gigaoctets de VRAM sur une seule carte, transmis à l'instance via PCIe plutôt que partagés dans le temps entre locataires. Cette distinction fait la différence entre une latence prévisible et le fait d'attendre derrière le travail d'entraînement de quelqu'un d'autre. La carte est à vous jusqu'à annulation.
Avant de commencer
- Un G-L40S avec Debian 13. Le G-ADA à vingt gigaoctets convient pour les modèles plus petits ; l'arithmétique à l'étape quatre vous indique lesquels.
- Deux téraoctets de NVMe sur ce plan, ce qui est le bon endroit pour les poids. Télécharger quarante gigaoctets deux fois parce que le cache était sur le système de fichiers racine est une façon ennuyeuse de passer une heure.
- Un nom d'hôte pointant vers l'instance,
llm.example.comci-dessous.
1. Pilote
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
rebootAprès son retour :
nvidia-smiVous voulez la carte listée, la version du pilote imprimée et l'utilisation mémoire proche de zéro. Une carte manquante à ce stade est presque toujours un initramfs obsolète ; update-initramfs -u et redémarrez une fois de plus avant d'ouvrir un ticket.
nvidia-smi -q -d PERFORMANCE | grep -A3 "Clocks Event Reasons"
nvidia-smi -pm 1Le mode persistance maintient le pilote chargé entre les processus, ce qui supprime plusieurs secondes d'initialisation à chaque redémarrage.
2. Runtime
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 vllmL'installation tire un ensemble de wheels liés à CUDA volumineux et prend un certain temps. En attendant, décidez d'un modèle.
3. Choisir ce qui convient
Les poids sont le plancher, pas le budget. Un modèle en précision seize bits nécessite environ deux gigaoctets de VRAM par milliard de paramètres, plus le cache clé-valeur pour chaque requête concurrente, plus environ un gigaoctet de frais généraux d'exécution.
| Carte | Poids en 16 bits | Taille réaliste du modèle | Reste pour le cache |
|---|---|---|---|
| L40S, 48 Go | 2 Go par milliard | Jusqu'à environ 20 milliards | 6 à 8 Go |
| L40S, 48 Go, 8 bits | 1 Go par milliard | Jusqu'à environ 34 milliards | 10 Go |
| RTX 4000 Ada, 20 Go | 2 Go par milliard | Jusqu'à environ 7 milliards | 5 Go |
| Deux × L40S, 96 Go | 2 Go par milliard | Jusqu'à environ 40 milliards | 12 Go |
La colonne cache détermine combien de personnes peuvent utiliser le point de terminaison en même temps. Remplissez la carte à ras bord avec des poids et vous avez construit un jouet très rapide pour un seul utilisateur.
4. Servir le modèle
Pointez le cache vers le NVMe et démarrez le serveur. Remplacez l'identifiant du référentiel du modèle open-weights que vous avez choisi ; le runtime le télécharge au premier démarrage.
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 vllmLa liaison à loopback est délibérée. La vérification de la clé API dans le runtime est un secret partagé unique sans limite de débit derrière, donc nginx fait l'exposition et le runtime ne touche jamais l'interface publique.
Le délai de démarrage généreux existe parce que le premier lancement télécharge des dizaines de gigaoctets puis compile les kernels. Les démarrages suivants prennent moins d'une minute.
5. Proxy et 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 est la ligne qui fait que les réponses en streaming streament. Laissez-la activée et les jetons arrivent par lots polis chaque fois que nginx sent qu'un tampon est plein, ce qui ressemble exactement à un modèle lent et ne l'est pas.
Vérifiez
Commencez par la carte :
nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csvLa mémoire utilisée devrait être autour de quatre-vingt-dix pour cent du total, car c'est ce que --gpu-memory-utilization a demandé. Ensuite le point de terminaison :
curl -s https://llm.example.com/v1/models -H "Authorization: Bearer <the key>" | head -20Un modèle, nommé local. Maintenant une complétion réelle, et chronométrez-la :
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}'Enfin, mesurez-la sous charge plutôt qu'une requête à la fois, ce qui est le seul chiffre qui vaille la peine d'être cité :
/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 8Lisez trois nombres dans la sortie : le débit de jetons de sortie par seconde en agrégat, le temps médian jusqu'au premier jeton et le quatre-vingt-dix-neuvième percentile de bout en bout. Sur un seul L40S avec un modèle dans la plage de dix à vingt milliards, un débit de sortie agrégé dans les centaines élevées de jetons par seconde et un temps jusqu'au premier jeton bien en dessous d'une seconde est la forme attendue. Un temps jusqu'au premier jeton qui grimpe avec la concurrence signifie que votre cache clé-valeur est trop petit, donc baissez --max-model-len ou --max-num-seqs et relancez.
Ensuite
Surveillez la température et l'étranglement de l'horloge pendant la première semaine avec nvidia-smi dmon, car une carte qui s'étrangle thermiquement sous charge soutenue produit exactement le genre de lenteur intermittente attribuée au réseau. Côté facturation, rappelez-vous qu'une instance GPU coûte le même prix que la carte soit occupée ou inactive, donc battez plutôt que de la laisser chaude. Les prix sont sur la page GPU.