Cosa ti serve

  • Un host Linux (o Windows + WSL2) con GPU NVIDIA, 24GB di VRAM consigliati
  • Docker + NVIDIA Container Toolkit installati (il toolkit è ciò che passa la GPU nei container)
  • ~30GB liberi su disco per la cache dei modelli

Passo 1 — Verifica il passthrough GPU (2 min)

$ docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi

Se vedi la tua GPU elencata, il collegamento Docker↔GPU funziona. Se ottieni "could not select device driver", installa l'NVIDIA Container Toolkit (nvidia-ctk runtime configure) e riavvia Docker.

Passo 2 — Scegli il modello: AWQ, non GGUF (2 min)

L'errore classico in questo passo: il percorso nativo di vLLM serve pesi full-precision, AWQ, GPTQ o FP8non i file GGUF che usa Ollama (vedi la guida alla quantizzazione). Per una scheda da 24GB, una build AWQ classe ~27B (≈16GB di pesi) lascia spazio sano per la KV-cache. Useremo una build AWQ di Qwen3.6-27B come esempio — sostituisci con il repo AWQ del tuo modello preferito da Hugging Face.

Passo 3 — Avvia vLLM (10 min incluso download)

$ docker run -d --name vllm --gpus all -p 8000:8000 \ -v vllm_hf_cache:/root/.cache/huggingface \ --restart unless-stopped \ vllm/vllm-openai:latest \ --model Qwen/Qwen3.6-27B-Instruct-AWQ \ --max-model-len 16384 \ --gpu-memory-utilization 0.92

I tre flag che contano:

  • --max-model-len — il contesto massimo per richiesta. vLLM pre-pianifica la memoria della KV-cache attorno a questo valore: più grande = meno sequenze concorrenti. 16K è un buon default da team.
  • --gpu-memory-utilization — frazione di VRAM che vLLM riserva (default 0,9). Alza a 0,92–0,95 su una scheda dedicata; abbassala se la GPU pilota anche il monitor.
  • -v vllm_hf_cache — rende persistente il modello scaricato, così ricreare il container non riscarica 16GB.

Osserva l'avvio con docker logs -f vllm — è pronto quando stampa la riga Uvicorn "running on 0.0.0.0:8000".

Passo 4 — Testa la API (2 min)

$ curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "Qwen/Qwen3.6-27B-Instruct-AWQ", "messages": [{"role": "user", "content": "Rispondi con una parola: funziona?"}]}'

Una risposta JSON = il tuo team ha ora un endpoint privato compatibile OpenAI. Qualsiasi SDK OpenAI ci funziona impostando base_url su http://IP-SERVER:8000/v1 (api_key può essere qualsiasi stringa, o imponine una con --api-key).

Passo 5 — Aggiungi Open WebUI con docker-compose (10 min)

Per un setup durevole, sposta entrambi i servizi in un unico file compose (docker-compose.yml):

services: vllm: image: vllm/vllm-openai:latest command: --model Qwen/Qwen3.6-27B-Instruct-AWQ --max-model-len 16384 --gpu-memory-utilization 0.92 ports: ["8000:8000"] volumes: ["vllm_hf_cache:/root/.cache/huggingface"] restart: unless-stopped deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] open-webui: image: ghcr.io/open-webui/open-webui:main ports: ["3000:8080"] environment: - OPENAI_API_BASE_URL=http://vllm:8000/v1 - OPENAI_API_KEY=local volumes: ["open_webui:/app/backend/data"] restart: unless-stopped depends_on: [vllm] volumes: vllm_hf_cache: open_webui:
$ docker rm -f vllm # rimuovi prima il container del passo 3
$ docker compose up -d

Apri http://IP-SERVER:3000, crea l'account amministratore e invita il team. Entrambi i servizi ora ripartono automaticamente con l'host.

Passo 6 — Monitora e dimensiona per la concorrenza (continuativo)

  • vLLM esporta metriche Prometheus su http://IP-SERVER:8000/metrics — quelle da osservare sono le richieste running/waiting (coda che cresce = saturazione) e l'uso della KV-cache. Graficale in Grafana dal giorno uno.
  • Matematica della concorrenza: memoria KV-cache ≈ cache per token × contesto × sequenze concorrenti. Se gli utenti segnalano code, abbassa --max-model-len (libera cache → più sequenze concorrenti) o passa a una GPU più grande/una seconda. La matematica completa è nella guida VRAM.
  • Occhio ai consumi: una GPU di serving lavora 9-18 — un power limit (nvidia-smi -pl) scambia ~5–10% di velocità per 25–30% di energia.

Risoluzione dei problemi

  • CUDA out of memory all'avvio — modello + cache pianificata non entrano: abbassa --max-model-len (prima leva), abbassa --gpu-memory-utilization, o scegli un modello AWQ più piccolo.
  • "Cannot load GGUF" / errori di formato — hai puntato vLLM a un repo GGUF. Usa invece la build AWQ (o GPTQ/FP16) del modello.
  • La prima richiesta è lenta — normale: warmup dei grafi CUDA. Giudica la latenza dalla seconda richiesta in poi.
  • La WebUI non vede il modello — verifica che OPENAI_API_BASE_URL punti a http://vllm:8000/v1 (nome del servizio, non localhost) e che il container vllm sia healthy in docker compose ps.

Prossimi passi