Cosa si realizza
Una istanza GPU che serve un modello open-weights tramite un'API HTTP compatibile con lo schema OpenAI, così ogni libreria client che già possiedi funziona cambiando solo l'URL di base. Dietro nginx, con TLS, una chiave API e un'unità systemd che sopravvive ai riavvii.
Scritto su una G-L40S: quarantotto gigabyte di VRAM su una singola scheda, passata all'istanza via PCIe anziché essere suddivisa nel tempo tra più tenant. Questa differenza è ciò che separa una latenza prevedibile dall'attesa dietro il job di addestramento di qualcun altro. La scheda è tua finché non la cancelli.
Prima di iniziare
- Una G-L40S con Debian 13. La G-ADA da venti gigabyte va bene per modelli più piccoli; l'aritmetica al punto quattro ti dice quali.
- Due terabyte di NVMe su questo piano, che è il posto giusto per i pesi. Scaricare quaranta gigabyte due volte perché la cache era sul filesystem di root è un modo fastidioso di spendere un'ora.
- Un hostname che punta all'istanza,
llm.example.comsotto.
1. Driver
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
rebootDopo che torna:
nvidia-smiVuoi la scheda elencata, il driver stampato e l'uso di memoria vicino a zero. Una scheda mancante a questo punto è quasi sempre un initramfs obsoleto; update-initramfs -u e riavvia un'altra volta prima di aprire un ticket.
nvidia-smi -q -d PERFORMANCE | grep -A3 "Clocks Event Reasons"
nvidia-smi -pm 1La modalità di persistenza tiene il driver caricato tra i processi, il che rimuove alcuni secondi di inizializzazione a ogni riavvio.
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'installazione scarica un ampio set di wheel CUDA e richiede tempo. Nel frattempo, decidi un modello.
3. Scegliere cosa entra
I pesi sono il minimo, non il budget. Un modello a precisione a 16 bit richiede circa due gigabyte di VRAM per miliardo di parametri, più la cache key-value per ogni richiesta concorrente, più un gigabyte o due di overhead runtime.
| Scheda | Pesi a 16 bit | Dimensione realistica del modello | Rimasto per la cache |
|---|---|---|---|
| L40S, 48 GB | 2 GB per miliardo | Fino a circa 20 miliardi | 6 a 8 GB |
| L40S, 48 GB, 8 bit | 1 GB per miliardo | Fino a circa 34 miliardi | 10 GB |
| RTX 4000 Ada, 20 GB | 2 GB per miliardo | Fino a circa 7 miliardi | 5 GB |
| Due × L40S, 96 GB | 2 GB per miliardo | Fino a circa 40 miliardi | 12 GB |
La colonna della cache è ciò che determina quante persone possono usare l'endpoint contemporaneamente. Riempi la scheda fino all'orlo di pesi e avrai costruito un giocattolo per utente singolo molto veloce.
4. Servire il modello
Punta la cache sull'NVMe e avvia il server. Sostituisci l'identificatore del repository del modello open-weights che hai scelto; il runtime lo scarica al primo avvio.
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 vllmIl bind su loopback è voluto. Il controllo della chiave API nel runtime è un singolo segreto condiviso senza limitazione di frequenza dietro, quindi nginx gestisce l'esposizione e il runtime non tocca mai l'interfaccia pubblica.
Il timeout di avvio generoso esiste perché il primo avvio scarica decine di gigabyte e poi compila i kernel. Gli avvii successivi richiedono meno di un minuto.
5. Proxy e 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 è la riga che fa sì che le risposte in streaming scorrano. Lasciala attiva e i token arrivano in batch ordinati quando nginx ritiene che un buffer sia pieno, il che sembra esattamente un modello lento e non lo è.
Verifica
Inizia con la scheda:
nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csvLa memoria usata dovrebbe essere circa il novanta percento del totale, perché è ciò che --gpu-memory-utilization ha richiesto. Poi l'endpoint:
curl -s https://llm.example.com/v1/models -H "Authorization: Bearer <the key>" | head -20Un modello, chiamato local. Ora una completazione vera, e cronometrala:
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}'Infine, misuralo sotto carico anziché una richiesta alla volta, che è l'unico numero che vale la pena citare:
/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 8Leggi tre numeri dall'output: token di output al secondo in aggregato, mediana del tempo al primo token e il 99° percentile end-to-end. Su una singola L40S con un modello nella fascia da dieci a venti miliardi, una velocità di output aggregata nell'ordine delle centinaia di token al secondo e un tempo al primo token ben sotto il secondo sono la forma attesa. Un tempo al primo token che cresce con la concorrenza significa che la tua cache key-value è troppo piccola, quindi riduci --max-model-len o --max-num-seqs ed esegui di nuovo.
Dopo
Controlla temperatura e throttling della frequenza per la prima settimana con nvidia-smi dmon, poiché una scheda che si termal-throttola sotto carico sostenuto produce esattamente il tipo di lentezza intermittente che viene attribuita alla rete. Per quanto riguarda la fatturazione, ricorda che un'istanza GPU costa lo stesso sia che la scheda sia occupata che inattiva, quindi processa il lavoro in batch piuttosto che lasciarla calda. I prezzi sono su la pagina GPU.