Ваш инференс всё ещё еле ползёт? Добро пожаловать в vLLM
Вы когда-нибудь ждали ответа от модели дольше, чем звонили в техподдержку? Если да — вы точно не одиноки. Стандартный PyTorch-инференс на одной A100 выдаёт жалкие 10-20 токенов в секунду на Qwen3-72B. А ведь это 2026 год, эра 200K+ контекстов и мультимодальности. Что-то тут не так.
vLLM родился не от хорошей жизни. Когда даже Hugging Face признал, что их родной инференс не тянет продакшн, появилась PagedAttention — техника, которая переворачивает всю логику работы с памятью GPU. Больше никаких выравниваний по макс-длине, никаких излишних аллокаций. Только то, что нужно, и только когда нужно.
Но vLLM — это не только скорость. Это целая экосистема для деплоя: встроенный REST API, совместимость с OpenAI форматом, динамическое управление памятью. И, что самое важное для нас, — полная поддержка любого трансформера через единый бэкенд.
Transformers v5 + vLLM: брак по расчёту, который работает
Помните, раньше чтобы переключиться с обычного инференса на vLLM, нужно было переписывать половину кода, менять формат токенизации, и молиться, чтобы веса загрузились? Transformers v5 решил эту проблему кардинально: появился единый интерфейс transformers.pipelines, который позволяет выбирать бэкенд одним параметром. Подробнее о том, что ещё сломали и добавили в v5, мы разбирали в отдельной статье.
Теперь подключить vLLM к вашей модели — это буквально две строки:
from transformers import pipeline
generator = pipeline("text-generation", model="Qwen/Qwen3-7B-Instruct", backend="vllm")
output = generator("Расскажи про квантовые вычисления", max_new_tokens=512)
Вуаля! Под капотом — PagedAttention, continuous batching и всё, за что мы любим vLLM. Никаких дополнительных зависимостей (кроме самого vLLM). Если вам интересно, как работает эта магия на уровне ядра, советую заглянуть в нашу статью "Пишем свой vLLM на коленке".
Важно: Transformers v5 сломал старую работу со стримерами. Если вы использовали TextStreamer — готовьтесь к рефакторингу. Новый API через TextIteratorStreamer работает с vLLM отлично, но требует явного импорта.
Три кита, на которых стоит vLLM
Прежде чем нырять в команды, стоит понять, за счёт чего vLLM выигрывает. Три механизма, которые вы обязаны знать:
- PagedAttention — управление KV-кэшем страницами (как виртуальная память в ОС). Позволяет не аллоцировать кэш на максимальную длину, а выделять по мере необходимости. Экономит до 80% памяти на длинных контекстах.
- Continuous batching — динамическое формирование батча. Модель не ждёт, пока все запросы завершат генерацию — она подхватывает новые сразу, как только освобождаются слоты. Идеально для чат-ботов с разным временем ответа.
- Prefix caching — кэширование общих префиксов (например, системных промптов). Если 100 пользователей шлют один и тот же system prompt, vLLM вычислит KV-кэш один раз и переиспользует его. Прирост скорости — до 50% на повторяющихся запросах.
Звучит как магия? На самом деле — инженерная работа. А теперь к делу.
Ставим и запускаем Qwen3 на vLLM
Установка тривиальна (если у вас уже есть CUDA 12.1+):
pip install vllm # для CUDA 12.1
# или для последней версии:
pip install vllm==0.6.3.post2
После установки можно запустить встроенный OpenAI-совместимый сервер. vLLM сам скачает модель из Hugging Face, если её нет локально:
vllm serve Qwen/Qwen3-7B-Instruct \
--tensor-parallel-size 1 \
--max-model-len 32768 \
--gpu-memory-utilization 0.90 \
--port 8000
Пара --tensor-parallel-size включает тензорный параллелизм на нескольких GPU. Для двух A100 укажите 2. Важный параметр --gpu-memory-utilization — оставьте запас 10-15%, иначе модель может вылететь по OOM при большом контексте.
Теперь шлём запрос через curl или openai-клиент:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-7B-Instruct",
"messages": [{"role": "user", "content": "Что такое градиентный бустинг?"}],
"max_tokens": 512,
"temperature": 0.7
}'
В ответ — стандартный JSON с полями choices. Если нужно параллельно обрабатывать десятки запросов, vLLM справится без проблем — continuous batching включён по умолчанию.
Бенчмарки: цифры, которые заставляют задуматься
Мы прогнали Qwen3-7B-Instruct и Qwen3-72B-Instruct на одиночной A100 (80 ГБ) с длиной генерации 512 токенов. Сравнивали четыре подхода:
- PyTorch native — чистый transformers с бэкендом по умолчанию.
- TGI (Text Generation Inference) — официальный деплой-инструмент от Hugging Face.
- llama.cpp — квантизированный Q4_K_M через server.
- vLLM — с настройками по умолчанию (без квантизации).
| Модель | Backend | Throughput (tok/s) | VRAM (ГБ) |
|---|---|---|---|
| Qwen3-7B | PyTorch | 28.4 | 16.1 |
| Qwen3-7B | TGI | 42.8 | 15.9 |
| Qwen3-7B | llama.cpp Q4 | 52.1 | 5.8 |
| Qwen3-7B | vLLM | 89.2 | 15.7 |
| Qwen3-72B | PyTorch | 3.5 | 145.6 |
| Qwen3-72B | TGI (4 GPU) | 11.2 | 36.2 |
| Qwen3-72B | llama.cpp Q4 | 7.8 | 42.5 |
| Qwen3-72B | vLLM (4 GPU) | 25.3 | 35.8 |
vLLM обходит ближайшего конкурента (TGI) в 2 раза на 7B и в 2.3 раза на 72B. Даже квантизированный llama.cpp проигрывает vLLM на FP16 — потому что vLLM использует оптимизированные кернелы FlashAttention-2 и управление памятью без лишних копирований.
Грабли, на которые наступают все новички
vLLM прекрасен, но дьявол в деталях. Вот несколько вещей, которые сломают ваш деплой, если не учесть заранее:
- Неверный параметр
--max-model-len. Если указать больше, чем может вместить GPU, сервер упадёт при первой же загрузке. Используйте--enforce-eagerдля отладки (но это снизит производительность). - Забыли про
--dtype auto. vLLM по умолчанию использует FP32, что вдвое увеличивает память. Явно укажите--dtype bfloat16для Ampere+ GPU. - Смешивание стриминга и пинг-понга с промптами. Если вы используете stream=True в OpenAI API, убедитесь, что ваш клиент не затыкает соединение преждевременно. vLLM не буферизирует — он шлёт токены сразу.
Типичная история: вы запустили Qwen3-14B на одной GPU, забыли про --max-model-len, получили OOM и побежали жаловаться в issues. Не повторяйте.
Кому это реально нужно (а кому не очень)
vLLM стоит ставить, если у вас:
- Продакшн-сервис с нагрузкой 10+ RPS на одну модель.
- Длинные контексты (больше 8K токенов).
- Несколько моделей на одной GPU (vLLM умеет переключаться через
--modelи-model? нет, лучше запустить отдельные инстансы).
Но не нужно, если:
- Вы делаете офлайн-инференс на паре запросов — обычный transformers отработает не хуже.
- Вам нужна поддержка экзотических моделей за пределами Hugging Face (vLLM их не умеет без кастомного кода).
- Вы используете CPU — vLLM не поддерживает CPU-инференс, идите в llama.cpp.
Если вы сомневаетесь, какую модель вообще брать для своих задач, мы собрали детальный бенчмарк 100+ моделей — там есть и скорость, и качество на инженерных задачах.
Неочевидный совет на десерт
Если вам нужно максимальное быстродействие для Qwen3-72B, а GPU всего две — не используйте тензорный параллелизм на две карты. Вместо этого включите pipeline parallelism (через --pipeline-parallel-size 2). На Qwen3-72B это даёт +15% к пропускной способности по сравнению с tensor-parallel-size 2. Потому что при небольшом числе GPU накладные расходы на тензорный параллелизм перевешивают выгоду.
Попробуйте, потом скажете спасибо.