Выберите движок
- vLLM: широкая поддержка моделей, сервер с API, совместимым с OpenAI, сборки для NVIDIA и AMD (ROCm). Используется в остальной части этого руководства.
- SGLang: ещё один открытый движок с API, совместимым с OpenAI; запускается командой
python -m sglang.launch_server --model-path <model> --tp 2; по умолчанию слушает127.0.0.1:30000. См. документацию SGLang. - TensorRT-LLM: движок NVIDIA для GPU NVIDIA;
trtllm-serve <model>открывает эндпоинт, совместимый с OpenAI. См. документацию TensorRT-LLM.
Сначала подбирайте GPU по объёму памяти. Веса занимают около 2 байт на параметр в BF16 (70B-модели нужно около 140 ГБ), 1 байт в FP8 и около половины байта в 4-битных форматах. KV-кэш добавляется сверху и растёт с длиной контекста и числом одновременных запросов. Список конфигураций, подходящих для конкретной модели, — в подборе GPU под модель.
Установите vLLM и запустите первую модель
Устанавливайте vLLM в отдельное окружение Python, как рекомендовано в руководстве по установке vLLM. Храните загруженные модели на NVMe-диске для данных:
curl -LsSf https://astral.sh/uv/install.sh | sh # затем откройте новую оболочку, чтобы uv появился в PATH
uv venv --python 3.12 --seed --managed-python ~/vllm-env
source ~/vllm-env/bin/activate
uv pip install vllm --torch-backend=auto
export HF_HOME=/data/hf # кэш моделей на NVMe
export VLLM_API_KEY=$(openssl rand -hex 32) # этот ключ должны передавать клиенты
echo "$VLLM_API_KEY" # сохраните его для своих клиентов
vllm serve Qwen/Qwen3-4B --host 127.0.0.1 --port 8000 --max-model-len 8192
Запускайте сервер внутри tmux (см. Доступ по SSH). Для закрытых моделей нужен токен Hugging Face: hf auth login или переменная окружения HF_TOKEN. Проверьте из второй оболочки на сервере, экспортировав тот же ключ:
curl -s http://127.0.0.1:8000/v1/models -H "Authorization: Bearer $VLLM_API_KEY"
curl -s http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $VLLM_API_KEY" \
-d '{"model": "Qwen/Qwen3-4B", "messages": [{"role": "user", "content": "Say hello in five words."}], "max_tokens": 64}'
С этим API работает любой клиент OpenAI: укажите base_url="http://127.0.0.1:8000/v1" и api_key, равный вашему ключу.
Разнесите модель на 2, 4 или 8 GPU
vllm serve Qwen/Qwen3-32B --tensor-parallel-size 2 --host 127.0.0.1 --port 8000
vllm serve <model> --tensor-parallel-size 8 --host 127.0.0.1 --port 8000
- Тензорный параллелизм разбивает каждый слой между GPU и обменивается данными на каждом шаге. Это значение должно быть делителем числа голов внимания (attention heads) модели; обычно используют 2, 4 или 8.
- На платформах с NVLink и NVSwitch (8-GPU серверы H100, H200, B200 и B300) тензорный параллелизм — выбор по умолчанию.
- Без NVLink (L40S, RTX PRO 6000, карты GeForce) руководство vLLM по параллелизму рекомендует конвейерный параллелизм (
--pipeline-parallel-size) для более высокой пропускной способности. Измерьте оба варианта на своей модели. - Если модель помещается на меньшем числе GPU, несколько её копий обычно обслуживают больше запросов, чем один большой экземпляр:
--data-parallel-size, либо отдельные серверы, закреплённые за конкретными GPU черезCUDA_VISIBLE_DEVICES, каждый на своём порту.
Настройка GPU для работы с несколькими GPU описана в разделе Multi-GPU.
Квантование FP8 и 4-бит
| Формат | Память под веса | Оборудование | Компромисс |
|---|---|---|---|
| BF16 (без квантования) | 2 байта на параметр | Все GPU | Эталонное качество |
| FP8 | Около половины от BF16 | Ada (L40S, RTX 4090), Hopper, Blackwell, MI355X | Обычно небольшая потеря качества; тензорные ядра FP8 также ускоряют вычисления |
| AWQ, GPTQ (4-битные веса) | Около четверти | GPU NVIDIA (по AMD см. таблицу vLLM) | Более заметная потеря качества, зависящая от модели; позволяет разместить модель на меньшем числе GPU или на GPU с меньшей памятью |
| NVFP4, MXFP4 | Около четверти | Blackwell (NVFP4), MI355X (MXFP4) | Требуется чекпоинт, подготовленный для этого формата |
# FP8 на лету из чекпоинта BF16 (калибровочные данные не нужны)
vllm serve Qwen/Qwen3-32B --quantization fp8 --host 127.0.0.1
# заранее квантованные чекпоинты определяются по их конфигурации
vllm serve Qwen/Qwen3-32B-AWQ --host 127.0.0.1
# FP8 для KV-кэша: больше контекста или больше одновременных запросов на каждый ГБ
vllm serve Qwen/Qwen3-32B --kv-cache-dtype fp8 --host 127.0.0.1
Потеря качества зависит от модели и задачи. Перед переходом сравните квантованную модель с оригиналом на собственных запросах. В разделе vLLM о квантовании перечислено, какой метод работает на каком оборудовании.
Запустите vLLM в Docker
docker run --rm --runtime nvidia --gpus all \
-v /data/hf:/root/.cache/huggingface \
--env "HF_TOKEN=$HF_TOKEN" --env "VLLM_API_KEY=$VLLM_API_KEY" \
-p 127.0.0.1:8000:8000 \
--ipc=host \
vllm/vllm-openai:latest \
--model Qwen/Qwen3-4B --max-model-len 8192
Образ запускает vllm serve, поэтому аргументы после имени образа передаются vLLM. Публикуйте порт на 127.0.0.1: правила портов Docker обходят ufw. На MI355X используйте vllm/vllm-openai-rocm с --device /dev/kfd --device /dev/dri --group-add=video вместо --gpus (см. страницу vLLM про Docker и Контейнеры).
Открывайте эндпоинт безопасно
В руководстве vLLM по безопасности сказано прямо: --api-key защищает только маршруты /v1, /v2 и /inference, а остальные маршруты на том же сервере, включая те, что выполняют инференс, не проходят аутентификацию. Никогда не публикуйте сам порт vLLM. Выберите один из двух вариантов.
SSH-туннель: для вас и небольшой команды
# на вашем компьютере; после этого API доступен по адресу http://localhost:8000/v1
ssh -N -L 8000:127.0.0.1:8000 gpu1
Обратный прокси с TLS: для публичного эндпоинта
Направьте DNS-имя на сервер, установите Caddy из его официального репозитория и перенаправляйте только маршруты /v1/. Caddy сам получает и продлевает TLS-сертификат; vLLM проверяет API-ключ при каждом перенаправленном запросе.
sudo tee /etc/caddy/Caddyfile >/dev/null <<'EOF'
llm.example.com {
handle /v1/* {
reverse_proxy 127.0.0.1:8000
}
handle {
respond 404
}
}
EOF
sudo systemctl reload caddy
sudo ufw allow 80,443/tcp
Держите vLLM на --host 127.0.0.1 (или -p 127.0.0.1:8000:8000 в Docker), даже за прокси, чтобы прокси оставался единственным путём внутрь. Используйте длинный случайный API-ключ и заменяйте его в случае утечки.
Отслеживайте загрузку GPU
nvidia-smi dmon -s um # загрузка и память, одна строка на GPU в секунду
nvidia-smi --query-gpu=index,utilization.gpu,memory.used,memory.total,power.draw --format=csv -l 5
nvtop # интерактивный вид (в новых версиях также показываются GPU AMD)
watch -n 2 amd-smi monitor # AMD MI355X
curl -s http://127.0.0.1:8000/metrics | grep -E '^vllm:(num_requests_running|num_requests_waiting|kv_cache_usage_perc)'
vLLM резервирует большую часть памяти GPU под свой KV-кэш при запуске (--gpu-memory-utilization), поэтому высокое использование памяти — это нормально и ничего не говорит о нагрузке. GPU-Util в nvidia-smi — это доля времени, в течение которого выполнялось ядро (kernel), а не то, какая часть вычислительных ресурсов GPU была использована.
Вместо этого следите за количеством выполняющихся и ожидающих запросов и за использованием KV-кэша (метрики vLLM). Если запросы копятся в состоянии ожидания, а кэш почти заполнен — значит, нужно больше GPU, квантованная модель или более короткие контексты.
Нужна помощь с этим руководством?
Расскажите нам о своём GPU, командах, которые вы выполнили, и результате, который получили, через форму обратной связи.
