# Как самостоятельно развернуть инференс LLM с vLLM

> Инференс LLM на своём сервере с vLLM: подбор GPU, OpenAI-совместимый сервер, настройка FP8, кэширования префиксов и параллелизма, защита для продакшена.

Источник: https://fullgpu.com/ru/blog/self-host-llm-inference-vllm  
Обновлено: 2026-10-22  
Издатель: FullGPU (https://fullgpu.com/)

Чтобы самостоятельно развернуть инференс LLM (больших языковых моделей) с vLLM, нужны три вещи: GPU, памяти которого хватает на веса и KV-кэш, сервер vLLM с OpenAI-совместимым API и привычный для продакшена набор мер вокруг него — аутентификация, TLS, файрвол, менеджер служб и мониторинг. В этом руководстве каждый шаг разобран с командами, которые можно адаптировать под себя, на примере моделей Llama 3.1 и сервера Ubuntu с уже установленными драйверами NVIDIA.

## Зачем самостоятельно разворачивать инференс LLM с vLLM

vLLM — движок инференса с открытым исходным кодом, построенный на страничном KV-кэше и непрерывном батчинге (continuous batching): благодаря им один GPU может обслуживать множество запросов одновременно. Если запускать его самостоятельно, а не обращаться к API стороннего сервиса, вы получаете четыре преимущества:

- **Контроль над данными.** Промпты и ответы остаются на машине, которую вы контролируете, и не нужно разбираться в чужих правилах хранения данных.
- **Фиксированные расходы.** При оплате за токены счёт растёт вместе с использованием. Выделенный GPU стоит одинаково, обслуживает ли он миллион токенов или миллиард, поэтому стоимость токена — это цена в месяц, делённая на число обслуженных токенов, и она снижается по мере роста загрузки.
- **Задержка под вашим контролем.** Никакой общей очереди, сервер рядом с вашим приложением и собственный баланс между размером батча и временем ответа.
- **Гибкая настройка.** Любая открытая модель, ваши собственные модели после дообучения (fine-tuning) и адаптеры LoRA, структурированный вывод и ограничения контекста, подходящие вашему приложению.

Но и компромиссы вполне реальны. Стек обслуживаете вы: обновления, безопасность, мощности и отказоустойчивость — ваша забота. Вы платите и за часы простоя. Закрытые фронтирные модели развернуть у себя нельзя. А если объём запросов невелик или нагрузка скачкообразная, API с оплатой за токены часто обходится дешевле.

## Подбор GPU: веса плюс KV-кэш

Что вы сможете обслуживать, определяет память. Веса занимают число параметров × число байт на параметр: около 16 ГБ для Llama 3.1 8B в BF16 и около 70 ГБ для Llama 3.1 70B в FP8 или 140 ГБ в BF16. KV-кэш занимает 2 × число слоёв × число KV-голов × размерность головы × число байт на значение для каждого токена в обработке: около 0,13 МБ на токен для модели 8B и 0,33 МБ для 70B в BF16.

Пример расчёта: Llama 3.1 70B в FP8 на одном H200 со 141 ГБ при `--gpu-memory-utilization 0.92`. vLLM может использовать около 130 ГБ. После примерно 70 ГБ весов и нескольких гигабайт на активации на кэш остаётся около 55 ГБ: это примерно 170 000 токенов в BF16, или 20 одновременных диалогов с полным контекстом по 8 192 токена. Кэш в FP8 удваивает это число — примерно до 40. Полная методика и другие примеры — в нашем [руководстве по видеопамяти (VRAM) для LLM](https://fullgpu.com/ru/blog/vram-for-llms).

## Установка vLLM и запуск OpenAI-совместимого сервера

Установите vLLM в виртуальное окружение. Его wheel-пакеты включают собственную сборку PyTorch, поэтому от системы нужен только свежий драйвер NVIDIA; проверьте его командой `nvidia-smi`. См. также нашу [документацию по PyTorch и vLLM](https://fullgpu.com/ru/docs/pytorch-vllm).

```
sudo apt-get update
sudo apt-get install -y python3-venv
python3 -m venv ~/vllm-env
source ~/vllm-env/bin/activate
pip install vllm
```

Доступ к моделям Llama на Hugging Face ограничен: примите лицензию на странице модели, создайте токен доступа и экспортируйте его. Затем сгенерируйте API-ключ и запустите сервер с привязкой к localhost:

```
export HF_TOKEN=hf_your_token
export VLLM_API_KEY=$(openssl rand -hex 32)

vllm serve meta-llama/Llama-3.1-8B-Instruct \
  --host 127.0.0.1 --port 8000 \
  --api-key "$VLLM_API_KEY" \
  --max-model-len 32768
```

При первом запуске веса скачиваются в кэш Hugging Face; если домашний каталог небольшой, укажите в `HF_HOME` каталог на локальном NVMe. Затем проверьте эндпоинт:

```
curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $VLLM_API_KEY" \
  -d '{
    "model": "meta-llama/Llama-3.1-8B-Instruct",
    "messages": [
      {"role": "user", "content": "Explain the KV cache in one sentence."}
    ],
    "max_tokens": 100
  }'
```

Поскольку API следует формату OpenAI, существующие клиенты заработают, как только вы поменяете базовый URL и ключ:

```
from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="YOUR_KEY")
reply = client.chat.completions.create(
    model="meta-llama/Llama-3.1-8B-Instruct",
    messages=[{"role": "user", "content": "Hello"}],
)
print(reply.choices[0].message.content)
```

Если вы предпочитаете Docker, официальный образ `vllm/vllm-openai` принимает те же аргументы. Публикуйте порт только на 127.0.0.1, а в продакшене фиксируйте тег релиза вместо `latest`:

```
docker run --gpus all --ipc=host \
  -p 127.0.0.1:8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  -e HF_TOKEN \
  vllm/vllm-openai:latest \
  --model meta-llama/Llama-3.1-8B-Instruct \
  --api-key "$VLLM_API_KEY"
```

## Тензорный параллелизм на нескольких GPU

Когда модель не помещается на один GPU, параметр `--tensor-parallel-size` делит каждый слой между несколькими GPU. Веса и KV-кэш распределяются между GPU, которые обмениваются активациями на каждом слое, поэтому здесь важен NVLink. Это значение должно быть делителем числа голов внимания модели: у Llama 3.1 70B их 64, поэтому используйте 2, 4 или 8.

На сервере 8× H100 можно запустить две копии Llama 3.1 70B в BF16, каждую на четырёх GPU:

```
CUDA_VISIBLE_DEVICES=0,1,2,3 vllm serve meta-llama/Llama-3.1-70B-Instruct \
  --tensor-parallel-size 4 --host 127.0.0.1 --port 8001

CUDA_VISIBLE_DEVICES=4,5,6,7 vllm serve meta-llama/Llama-3.1-70B-Instruct \
  --tensor-parallel-size 4 --host 127.0.0.1 --port 8002
```

Каждая копия распределяет 140 ГБ весов по 320 ГБ памяти — около 35 ГБ на GPU, — так что при стандартной настройке памяти на каждом GPU для кэша остаётся примерно столько же. Обратный прокси распределяет запросы между двумя портами.

Эмпирическое правило: используйте тензорный параллелизм, когда модель не помещается на один GPU или когда нужна меньшая задержка на запрос. В остальных случаях запускайте по одной копии на каждом GPU за балансировщиком нагрузки — так трафика между GPU не будет вовсе. На картах, связанных только через PCIe, таких как L40S или RTX PRO 6000, лучше запускать отдельные копии или попробовать `--pipeline-parallel-size`: этот режим требует меньше обмена данными, чем тензорный параллелизм.

## Настройка памяти: FP8, кэширование префиксов и ограничения

Несколько параметров определяют, сколько поместится в память и насколько эффективно используется кэш:

- **`--quantization fp8`** преобразует веса из BF16 в FP8 при загрузке модели и вдвое сокращает память под веса на GPU Hopper, Ada и Blackwell. Проверьте, как это делает ваша версия vLLM: старые версии сначала загружали веса в полной точности, поэтому модель в BF16 должна была поместиться в память до преобразования. Для модели 70B на одном GPU используйте чекпоинт, уже квантованный в FP8; vLLM определит формат по конфигурации чекпоинта.
- **`--kv-cache-dtype fp8`** вдвое уменьшает кэш и вдвое увеличивает число токенов, которые в нём помещаются. Прежде чем включать этот параметр, проверьте качество на задачах с длинным контекстом.
- **Кэширование префиксов** позволяет повторно использовать кэш для общих префиксов промптов: системных промптов, примеров few-shot, предыдущих реплик диалога и документов, которые повторяются в разных RAG-запросах. В последних версиях оно включено по умолчанию; в более старых передайте `--enable-prefix-caching`. Чтобы извлечь из него пользу, ставьте в промптах неизменное содержимое в начало, а изменяющееся — в конец.
- **`--max-model-len`** ограничивает контекст одного запроса. По умолчанию это максимум модели — 131 072 токена для Llama 3.1, и vLLM не запустится, если одна последовательность такой длины не помещается в кэш, поэтому задайте значение, которое вам действительно нужно.
- **`--gpu-memory-utilization`** — доля памяти каждого GPU, которую vLLM может занять под веса, активации и кэш; по умолчанию 0,9. На выделенном GPU её можно поднять примерно до 0,95, чтобы получить больше кэша; уменьшите её, если GPU использует что-то ещё.
- **`--max-num-seqs`** ограничивает число последовательностей, которые обрабатываются одновременно, — простой способ удержать задержку под нагрузкой в разумных пределах.

Если собрать всё вместе, запуск заранее квантованного чекпоинта модели 70B в FP8 на одном H200 выглядит так:

```
vllm serve /models/llama-3.1-70b-instruct-fp8 \
  --served-model-name llama-3.1-70b \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92 \
  --kv-cache-dtype fp8 \
  --host 127.0.0.1 --port 8000
```

Чем квантование оборачивается для качества, разобрано в нашей статье [о точности FP8 и FP4](https://fullgpu.com/ru/blog/fp8-fp4-precision-explained).

## Защита эндпоинта

Открытый эндпоинт инференса рано или поздно найдут и начнут использовать посторонние. Защищайте его в несколько уровней.

### Привязка к localhost и обязательный ключ

В примерах выше vLLM привязан к 127.0.0.1, поэтому снаружи сервера к нему напрямую не обратиться. Параметр `--api-key` или переменная окружения `VLLM_API_KEY` заставляет клиентов передавать ключ в заголовке `Authorization: Bearer`. Ключ защищает маршруты API `/v1`; не рассчитывайте, что он закрывает и все остальные маршруты сервера, например метрики, — это ещё одна причина не открывать порт наружу. Если эндпоинтом пользуются несколько команд или клиентов, поставьте перед ним API-шлюз с отдельными ключами для пользователей и ограничением частоты запросов.

### Файрвол

Разрешите SSH, HTTP и HTTPS, а всё остальное запретите:

```
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
```

Если подключаться должны только известные клиенты, замените правило для порта 443 отдельным правилом для каждого адреса источника, например `sudo ufw allow from 203.0.113.10 to any port 443 proto tcp`. Есть одна ловушка: порты, опубликованные Docker, обходят правила UFW, — именно поэтому в примере с Docker порт публикуется только на 127.0.0.1. Подробнее — в нашем [руководстве по сети и файрволу](https://fullgpu.com/ru/docs/networking-firewall). Кроме того, на наших серверах публичные IP-адреса защищены от DDoS: это дополняет аутентификацию, но не заменяет её.

### Обратный прокси с TLS

Caddy автоматически получает и продлевает сертификат, как только ваша DNS-запись указывает на сервер, а порты 80 и 443 открыты. После установки из официального репозитория пакетов вся конфигурация в `/etc/caddy/Caddyfile` выглядит так:

```
llm.example.com {
    reverse_proxy 127.0.0.1:8000
}
```

Перезагрузите конфигурацию командой `sudo systemctl reload caddy`. Потоковые ответы передаются клиенту по мере генерации. Чтобы распределять запросы между двумя копиями vLLM, перечислите оба бэкенда: `reverse_proxy 127.0.0.1:8001 127.0.0.1:8002`. Если вместо Caddy вы используете nginx, отключите `proxy_buffering` для блока location с API и увеличьте `proxy_read_timeout`, иначе потоковые токены будут приходить рывками, а длинные запросы — обрываться по тайм-ауту.

## Запуск vLLM как службы и мониторинг

В продакшене запускайте vLLM под systemd от имени непривилегированного пользователя, чтобы он стартовал при загрузке системы и перезапускался после сбоя:

```
sudo useradd --system --user-group --create-home \
  --home-dir /opt/vllm --shell /usr/sbin/nologin vllm
sudo -u vllm python3 -m venv /opt/vllm/venv
sudo -u vllm /opt/vllm/venv/bin/pip install vllm
sudo mkdir -p /etc/vllm
```

Храните секреты в файле `/etc/vllm/vllm.env`, доступном для чтения только root (`sudo chmod 600 /etc/vllm/vllm.env`); systemd читает этот файл до того, как понижает привилегии:

```
HF_TOKEN=hf_your_token
HF_HOME=/opt/vllm/hf-cache
VLLM_API_KEY=your-long-random-key
```

Затем создайте `/etc/systemd/system/vllm.service`:

```
[Unit]
Description=vLLM OpenAI-compatible server
After=network-online.target
Wants=network-online.target

[Service]
User=vllm
Group=vllm
EnvironmentFile=/etc/vllm/vllm.env
ExecStart=/opt/vllm/venv/bin/vllm serve meta-llama/Llama-3.1-8B-Instruct \
  --host 127.0.0.1 --port 8000 --max-model-len 32768
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
```

```
sudo systemctl daemon-reload
sudo systemctl enable --now vllm
journalctl -u vllm -f
```

Здесь vLLM берёт ключ из `VLLM_API_KEY`, поэтому он никогда не появляется в командной строке. При мониторинге следите за тремя уровнями:

- **Работоспособность.** `GET /health` возвращает 200, когда сервер работает; настройте на него проверку доступности.
- **Метрики инференса.** `/metrics` отдаёт метрики Prometheus, в том числе число выполняемых и ожидающих запросов (`vllm:num_requests_running` и `vllm:num_requests_waiting`), время до первого токена, сквозную задержку и заполненность KV-кэша. Настройте оповещения на случаи, когда запросы ждут по нескольку минут, когда растёт время до первого токена или когда кэш остаётся почти заполненным, что вынуждает vLLM прибегать к вытеснению (preemption) запросов.
- **Метрики GPU.** Для быстрой проверки используйте `nvidia-smi`, а для Prometheus — экспортер DCGM от NVIDIA. Не удивляйтесь, что память показывает занятость около 90% даже в простое: vLLM резервирует свою долю при запуске. Следите за температурой, энергопотреблением и ошибками GPU в журнале ядра (`journalctl -k`).

Подробнее о том, что происходит на стороне GPU, — в нашем [руководстве по мониторингу GPU](https://fullgpu.com/ru/docs/gpu-monitoring).

## Выбор GPU

Подбирайте GPU под модель, точность и нужное вам число одновременных запросов. Скорость генерации во многом определяется пропускной способностью памяти, поэтому это второй показатель, который стоит сравнивать после объёма.

| Модель и точность | Веса | Подходящий GPU | Заявленная пропускная способность на GPU | Цена в месяц |
| --- | --- | --- | --- | --- |
| 8B в BF16 | Около 16 ГБ | RTX 5090 (32 ГБ) или L40S (48 ГБ) | 1,79 ТБ/с или 864 ГБ/с | 449 $ или 890 $ |
| 32B в FP8 или 70B в 4-битном формате | 32–40 ГБ | RTX PRO 6000 (96 ГБ) | 1,6 ТБ/с | 1 390 $ |
| 32B в BF16 | Около 64 ГБ | H100 (80 ГБ) | 3,35 ТБ/с | 2 190 $ |
| 70B в FP8 | Около 70 ГБ | H200 (141 ГБ) | 4,8 ТБ/с | 3 090 $ |
| 70B в BF16 | Около 140 ГБ | B200 (180 ГБ) или B300 (288 ГБ) | 8 ТБ/с | 4 590 $ или 5 190 $ |
| 405B в FP8 | Около 405 ГБ | 8× H100 (640 ГБ) или 8× H200 (1 128 ГБ) | 3,35 или 4,8 ТБ/с | 16 900 $ или 23 900 $ |
| DeepSeek-V3 в FP8 | Около 670 ГБ | 8× H200 или 8× B200 (1 440 ГБ) | 4,8 или 8 ТБ/с | 23 900 $ или 34 900 $ |

Модель 70B в FP8 помещается и на два H100 с тензорным параллелизмом, но за 4 380 $ в месяц это дороже одного H200, да ещё и добавляет трафик между GPU. vLLM поддерживает и GPU AMD через ROCm, поэтому для очень больших моделей подойдёт сервер 8× MI355X с 288 ГБ на GPU; сначала проверьте на нём свою модель. При фиксированной цене в месяц стоимость собственного эндпоинта известна заранее, а в наши тарифы входит 20 ТБ (один GPU) или 50 ТБ (8 GPU) исходящего трафика в месяц — гораздо больше, чем обычно нужно для потоковой передачи текста. Подробное сравнение — в нашем руководстве [о лучшем GPU для инференса LLM](https://fullgpu.com/ru/blog/best-gpu-for-llm-inference) или на [странице NVIDIA H200](https://fullgpu.com/ru/gpus/nvidia-h200).

## Часто задаваемые вопросы

### Какой GPU нужен, чтобы самостоятельно развернуть модель 70B с vLLM?

В FP8 веса занимают около 70 ГБ, поэтому один H200 со 141 ГБ обслуживает такую модель с запасом для одновременных запросов, а на H100 с 80 ГБ она помещается лишь впритык. В BF16 одни только веса занимают около 140 ГБ — значит, нужен B200, B300 или тензорный параллелизм на нескольких GPU.

### Совместим ли vLLM с API OpenAI?

Да. vLLM предоставляет эндпоинты в стиле OpenAI, такие как /v1/chat/completions, /v1/completions и /v1/models, поэтому большинство клиентских библиотек OpenAI работают, как только вы поменяете базовый URL и API-ключ.

### Как защитить эндпоинт vLLM?

Привяжите vLLM к 127.0.0.1, сделайте API-ключ обязательным и открывайте доступ только через обратный прокси с TLS за файрволом, который пропускает лишь SSH, HTTP и HTTPS. В Docker публикуйте порт на 127.0.0.1, потому что порты, опубликованные Docker, обходят UFW.

### Почему nvidia-smi показывает, что GPU почти заполнен, когда vLLM простаивает?

При запуске vLLM резервирует фиксированную долю памяти GPU — по умолчанию 90% — и отдаёт большую её часть под блоки KV-кэша. Это ожидаемое поведение, а не утечка памяти.

### Что выбрать: тензорный параллелизм или несколько реплик?

Тензорный параллелизм нужен, когда модель не помещается на один GPU или когда требуется меньшая задержка на запрос, — в идеале через NVLink. Если модель помещается на один GPU, отдельные реплики за балансировщиком нагрузки избавляют от трафика между GPU и обычно дают большую суммарную производительность.

## Связанные страницы

- [GPU-серверы для инференса LLM: круглосуточно и по фиксированной цене](https://fullgpu.com/ru/solutions/inference): GPU-серверы для инференса LLM с vLLM, SGLang или TensorRT-LLM: расчёт KV-кэша, FP8 и FP4, 20–50 ТБ трафика включено. Посмотрите расчёты.
- [Инференс LLM на vLLM](https://fullgpu.com/ru/docs/pytorch-vllm): Инференс LLM с vLLM на вашем GPU-сервере: настройте Python через uv, установите PyTorch и vLLM, проверьте OpenAI-совместимый API и запустите его как службу.
- [Лучший GPU для инференса LLM в 2026 году: подбор по размеру модели](https://fullgpu.com/ru/blog/best-gpu-for-llm-inference): Лучший GPU для инференса LLM зависит от размера модели, точности, KV-кэша и пропускной способности. Выбирайте по таблице 2026 года: от RTX 5090 до 8× B300.
- [Сколько видеопамяти нужно для LLM?](https://fullgpu.com/ru/blog/vram-for-llms): Сколько видеопамяти (VRAM) нужно LLM? Короткие ответы для моделей 7B, 14B, 32B, 70B и 405B в BF16, FP8 и 4 битах, KV-кэш по длине контекста и подходящий GPU.
