Mười hai bài xây dựng

Local inference on a passthrough GPU with an OpenAI-compatible endpoint

Driver, runtime and model on a G-L40S, served behind TLS with an API key, and a load test that reports real tokens per second rather than a vendor slide.

Những gì hướng dẫn này tạo ra

Một GPU instance phục vụ một mô hình open-weights qua HTTP API tuân thủ schema tương thích OpenAI, vì vậy mọi thư viện client bạn đã có đều hoạt động với nó chỉ bằng cách đổi base URL. Phía sau nginx, với TLS, API key, và một systemd unit tồn tại qua các lần reboot.

Viết trên G-L40S: bốn mươi tám gigabyte VRAM trên một card duy nhất, được chuyển trực tiếp qua PCIe đến instance thay vì chia sẻ theo thời gian giữa các tenant. Sự khác biệt đó là ranh giới giữa độ trễ có thể dự đoán và việc chờ đợi sau job huấn luyện của người khác. Card là của bạn cho đến khi bạn hủy.

Trước khi bắt đầu

  • Một G-L40S với Debian 13. G-ADA 20 gigabyte hoạt động với các mô hình nhỏ hơn; phép tính ở bước bốn cho bạn biết cái nào.
  • Hai terabyte NVMe trong gói này, là nơi phù hợp cho weights. Tải bốn mươi gigabyte hai lần vì cache ở trên root filesystem là một cách lãng phí một giờ.
  • Một hostname trỏ tới instance, llm.example.com bên dưới.

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
reboot

Sau khi nó trở lại:

nvidia-smi

Bạn muốn thấy card được liệt kê, driver version được in ra, và memory usage gần bằng không. Card bị thiếu ở thời điểm này gần như luôn là initramfs cũ; update-initramfs -u và reboot thêm một lần nữa trước khi mở ticket.

nvidia-smi -q -d PERFORMANCE | grep -A3 "Clocks Event Reasons"
nvidia-smi -pm 1

Persistence mode giữ driver được nạp giữa các tiến trình, giúp giảm vài giây khởi tạo cho mỗi lần restart.

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 vllm

Quá trình cài đặt kéo về một bộ wheel liên kết CUDA lớn và mất chút thời gian. Trong lúc đó, hãy quyết định mô hình.

3. Chọn mô hình phù hợp

Weights là tầng dưới cùng, không phải ngân sách. Một mô hình ở độ chính xác 16-bit cần khoảng hai gigabyte VRAM cho mỗi tỷ tham số, cộng với key-value cache cho mỗi yêu cầu đồng thời, cộng thêm khoảng một gigabyte cho chi phí runtime.

CardWeights ở 16-bitKích thước mô hình thực tếCòn lại cho cache
L40S, 48 GB2 GB mỗi tỷTối đa khoảng 20 tỷ6 đến 8 GB
L40S, 48 GB, 8-bit1 GB mỗi tỷTối đa khoảng 34 tỷ10 GB
RTX 4000 Ada, 20 GB2 GB mỗi tỷTối đa khoảng 7 tỷ5 GB
Hai × L40S, 96 GB2 GB mỗi tỷTối đa khoảng 40 tỷ12 GB

Cột cache xác định số người có thể dùng endpoint cùng lúc. Nếu bạn nhét đầy card với weights, bạn sẽ tạo ra một món đồ chơi rất nhanh nhưng chỉ dùng được cho một người.

4. Phục vụ mô hình

Trỏ cache vào NVMe và khởi động server. Thay thế repository identifier của bất kỳ mô hình open-weights bạn chọn; runtime sẽ tự tải nó ở lần khởi động đầu tiên.

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 vllm

Việc bind vào loopback là có chủ đích. Việc kiểm tra API key trong runtime là một bí mật dùng chung duy nhất, không có rate limiting phía sau, vì vậy nginx chịu trách nhiệm phơi bày và runtime không bao giờ chạm vào interface công cộng.

Start timeout dài tồn tại vì lần khởi động đầu tiên tải về hàng chục gigabyte và sau đó biên dịch kernel. Các lần khởi động tiếp theo mất chưa đầy một phút.

5. Proxy và 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 là dòng làm cho streaming responses thực sự stream. Hãy để nó bật; các token đến theo từng lô nhỏ khi nginx cảm thấy buffer đầy, khiến nó trông giống một mô hình chậm nhưng thực ra không phải vậy.

Xác minh

Bắt đầu với card:

nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv

Memory đã dùng nên nằm khoảng 90 phần trăm tổng dung lượng, bởi vì đó là thứ mà --gpu-memory-utilization yêu cầu. Sau đó là endpoint:

curl -s https://llm.example.com/v1/models -H "Authorization: Bearer <the key>" | head -20

Một mô hình, tên là local. Bây giờ một completion thực sự, và đo thời gian:

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}'

Cuối cùng, đo dưới tải thay vì từng yêu cầu một, bởi vì đó là con số đáng giá duy nhất:

/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 8

Đọc ba con số từ output: tổng throughput output tokens mỗi giây, median thời gian đến token đầu tiên, và phân vị thứ 99 từ đầu đến cuối. Trên một L40S duy nhất với mô hình trong khoảng 10 đến 20 tỷ, tổng output throughput ở hàng trăm tokens mỗi giây và thời gian đến token đầu tiên dưới một giây là hình dạng dự kiến. Thời gian đến token đầu tiên tăng theo độ đồng thời nghĩa là key-value cache của bạn quá nhỏ, vì vậy hãy giảm --max-model-len hoặc --max-num-seqs và chạy lại.

Sau đó

Theo dõi nhiệt độ và việc giảm xung nhịp trong tuần đầu với nvidia-smi dmon, vì một card bị giảm xung do nhiệt dưới tải ổn định sẽ tạo ra đúng loại chậm chạp không liên tục thường bị đổ lỗi cho mạng. Về hóa đơn, hãy nhớ rằng một GPU instance có giá như nhau cho dù card bận hay rảnh, vì vậy hãy xử lý theo lô thay vì để nó ấm. Giá cả nằm trên trang GPU.

Sẵn sàng khi bạn cần

Chọn thành phố. Chọn kích thước. Thanh toán bằng coin.

Không có biểu mẫu về bạn là ai, không chờ đợi con người phê duyệt, không gọi điện thoại để xác minh bất cứ điều gì. Hóa đơn được thanh toán và thông tin đăng nhập sẽ vào hộp thư của bạn.