MAATRIX / Блог / vLLM на сервере: частые ошибки и решения

vLLM на сервере: частые ошибки и решения

vLLM на сервере: частые ошибки и решения

MAATRIX

На домашней машине с видеокартой vLLM поднимается одной командой, а на арендованном сервере встречает стеной: pip не находит пакет, импорт падает на undefined symbol, движок жалуется на тип устройства, а API отвечает 404 на имя модели, которую вы только что скачали. Ошибки vLLM повторяются от установки к установке и опознаются по одной строке лога. Ниже — пять слоёв отказа с точными текстами ошибок и командами проверки.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

С чего начинать: vLLM ломается в пяти разных местах

«vLLM не запускается» — это пять независимых слоёв. Пока неясно, на каком вы застряли, правка вслепую тратит время.

СимптомСлойПервая команда
No matching distribution found for vllmpip и Pythonpython3 -V
undefined symbol при импортеконфликт с torch`pip list \grep torch`
Failed to infer device typeжелезо, драйверnvidia-smi
GatedRepoError: 401 Client Errorзагрузка весовhf auth whoami
EngineCore failed to startстарт движкаjournalctl -u vllm
{"type":"NotFoundError","code":404}HTTP-слойcurl /v1/models

Главная ловушка чтения логов пришла с движком V1 (умолчание с версии 0.8): инференс живёт в отдельном процессе VLLM::EngineCore, а родительский в конце печатает обобщённое:

RuntimeError: Engine core initialization failed. See root cause above.
Failed core proc(s): {}

Именно его копируют в поиск и не находят ничего: причина — выше, за десятки строк до трейсбека.

Признак успешного старта — строки Application startup complete. и Uvicorn running on http://127.0.0.1:8000. Пока их нет, curl отдаёт Connection refused: это не ошибка API, а незакончившийся старт. Эндпоинт /health даёт 200, только когда движок принял модель.

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/v1/models | jq -r '.data[].id'

Мало деталей — VLLM_LOGGING_LEVEL=DEBUG.

Установка: pip находит не то, а импорт падает на undefined symbol

Половина обращений «vllm ошибки» — это не vLLM, а сломанное окружение Python.

Пакета под вашу версию Python нет. vLLM собирает колёса под ограниченный набор версий CPython, и слишком свежий интерпретатор или старый 3.8 дают одинаковый ответ:

ERROR: Could not find a version that satisfies the requirement vllm (from versions: none)
ERROR: No matching distribution found for vllm

Ключевое — (from versions: none): pip отсеял всё по совместимости. Ubuntu 24.04 даёт 3.12, Debian 12 — 3.11, обе подходят; экзотику лечит uv venv --python 3.12 /opt/vllm.

Установка в системный Python. На Ubuntu 24.04 и Debian 12 глобальная установка упирается в защиту дистрибутива:

error: externally-managed-environment
× This environment is externally managed

Обход флагом --break-system-packages дорог: vLLM тянет свою версию PyTorch, а apt считает torch и numpy своими — первое же apt upgrade оставит вас с нерабочим Python. Только venv:

sudo mkdir -p /opt/vllm && sudo chown $USER /opt/vllm
python3 -m venv /opt/vllm
/opt/vllm/bin/pip install -U pip
/opt/vllm/bin/pip install "vllm==0.11.0"

Версию фиксируйте явно: между минорными релизами vLLM убирает и переименовывает флаги CLI.

Конфликт с заранее поставленным torch. Сначала ставят PyTorch «под свою CUDA», потом поверх — vLLM; несовпадение вылезает при импорте:

ImportError: /opt/vllm/lib/python3.12/site-packages/vllm/_C.abi3.so: undefined symbol:
_ZN3c105ErrorC2ENS_14SourceLocationENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE

Символ _ZN3c105Error... — это c10::Error из PyTorch: ядро vLLM ищет в libtorch функцию, которой там нет. Подбирать версии torch дольше, чем пересоздать venv:

rm -rf /opt/vllm && python3 -m venv /opt/vllm
/opt/vllm/bin/pip install "vllm==0.11.0"
/opt/vllm/bin/python -c "import torch, vllm; print(torch.__version__, torch.version.cuda, torch.cuda.is_available())"

Ответ 2.8.0+cu128 12.8 True значит, что слой установки пройден, False указывает на драйвер. Зависимости с ядрами CUDA занимают на диске 8–10 ГБ.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

«Failed to infer device type»: vLLM на сервере без видеокарты

Самая частая ошибка на VPS сбивает с толку тем, что не содержит слова GPU:

INFO [__init__.py:32] No plugins for group vllm.platform_plugins found.
INFO [__init__.py:44] Checking if TPU platform is available.
INFO [__init__.py:56] Checking if CUDA platform is available.
RuntimeError: Failed to infer device type

Перевод: vLLM перебрал платформы — CUDA, ROCm, TPU, XPU — и не нашёл ни одной. На VPS это значит буквально «видеокарты нет»: nvidia-smi должен выводить таблицу с картой и версией драйвера. Соседние случаи:

  • Драйвер не загрузился или устарел. NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver — обычно после обновления ядра без пересборки DKMS. The NVIDIA driver on your system is too old (found version 11080) — колёса собраны под CUDA 12.x.
  • Контейнер не видит карту. В Docker nvidia-smi работает только с --gpus all и nvidia-container-toolkit на хосте.
  • Карта занята. Чужой процесс на 22 ГБ из 24 — забытый Jupyter или упавший vLLM; sudo fuser -v /dev/nvidia* покажет, кого убить.

CPU-бэкенд у vLLM есть, но он не для продакшена: готовых колёс нет, нужна сборка из исходников с VLLM_TARGET_DEVICE=cpu и gcc-12. Да и смысла мало — выигрыш vLLM держится на видеопамяти.

Без GPU берите llama.cpp или Ollama. Наш замер: AMD EPYC 9554 (16 vCPU — 8 физических ядер плюс HT), Ollama 0.33.1, qwen2.5:7b в Q4_K_M:

num_threadГенерация, ток/сОбработка промпта, ток/с
25,712,6
47,631,0
87,661,7
167,468,0
320,3510,9

Генерация выходит на полку уже на четырёх потоках: дальше упор в память, и 16 ядер вместо 8 скорости ответа не добавят. А 32 потока на 16 vCPU обрушивают её в двадцать раз. Там же при 16 потоках llama3.1:8b даёт 12,8 ток/с, mistral:7b — 12,1, gemma2:9b — 8,8, qwen2.5:3b — 34,1; в памяти модели занимают от 2,2 до 5,6 ГБ. Сравнение движков — в разборе Ollama против vLLM.

Модель не скачивается: закрытый репозиторий, токен и место на диске

Окружение собрано, карта видна, а vllm serve падает при загрузке весов.

Gated repo. Веса Llama, Gemma и части моделей Mistral отдаются только после принятия лицензии:

OSError: You are trying to access a gated repo. Make sure to have access to it at
https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct.
huggingface_hub.errors.GatedRepoError: 401 Client Error.

Порядок: аккаунт, лицензия на странице модели (у Llama заявка одобряется не мгновенно), токен с правом чтения, hf auth login. Ловушка: интерактивный логин кладёт токен в ~/.cache/huggingface/token того пользователя, который его запускал, — сервис под systemd от другого упадёт с тем же 401. Передавайте окружением:

[Service]
User=vllm
Environment="HF_HOME=/var/lib/vllm/hf"
EnvironmentFile=/etc/vllm/vllm.env
TimeoutStartSec=600
ExecStart=/opt/vllm/bin/vllm serve meta-llama/Llama-3.1-8B-Instruct --host 127.0.0.1 --port 8000

В /etc/vllm/vllm.env — строка HF_TOKEN=hf_... без кавычек и без export: systemd примет export за часть имени переменной и напишет invalid variable name.

Кончился диск. Веса 8B в FP16 — 16 ГБ, 32B — под 65 ГБ, и всё льётся в ~/.cache/huggingface/hub. Обрыв выглядит как [Errno 28] No space left on device или как зависший процесс; переносите кэш через HF_HOME.

Обрыв соединения. Из России загрузки с HuggingFace рвутся, а ошибка приходит невнятная:

huggingface_hub.errors.LocalEntryNotFoundError: An error happened while trying to
locate the file on the Hub and we cannot find the requested files in the local cache.

Дословно — «в интернет не сходили и локально ничего нет». Качайте веса отдельным шагом:

/opt/vllm/bin/hf download meta-llama/Llama-3.1-8B-Instruct \
  --local-dir /var/lib/vllm/models/llama-3.1-8b
/opt/vllm/bin/vllm serve /var/lib/vllm/models/llama-3.1-8b \
  --served-model-name llama-3.1-8b --host 127.0.0.1 --port 8000

Повторный hf download продолжает с места обрыва. С британской площадки проблемы нет вовсе: HuggingFace и PyPI открываются напрямую.

Модель не того формата. Ещё две ошибки на том же шаге:

ValueError: Loading <model> requires you to execute the configuration file in that repo
on your local machine.
ValueError: Quantization method specified in the model config (awq) does not match the
quantization method specified in the `quantization` argument (gptq).

Первая — модель с собственным кодом, нужен --trust-remote-code (вы разрешаете исполнить чужой Python). Вторая — вы задали --quantization вручную; обычно флаг не нужен, vLLM определяет квантование сам.

Движок не стартует: KV-кэш, CUDA-графы и процесс, убитый по памяти

Здесь важно различать три разные нехватки памяти.

Не хватило видеопамяти под KV-кэш. Модель загрузилась, а на контекст места не осталось:

ValueError: The model's max seq len (131072) is larger than the maximum number of tokens
that can be stored in KV cache (32496). Try increasing `gpu_memory_utilization` or
decreasing `max_model_len` when initializing the engine.

Рефлекс «поднять --gpu-memory-utilization до 0.98» неверен: остаток нужен движку на активации. Правильный рычаг — --max-model-len 8192. Расчёт с формулами — в разборе vLLM не запускается из-за памяти.

Не хватило видеопамяти на самих весах:

torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 2.00 GiB. GPU 0 has a
total capacity of 23.64 GiB of which 1.21 GiB is free.

Модель в выбранной точности не влезает: берите AWQ или GPTQ вместо FP16 либо две карты с --tensor-parallel-size 2.

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

sudo dmesg -T | grep -i -E 'killed process|out of memory'

Строка Out of memory: Killed process 4711 (VLLM::EngineCore) значит, что убил не vLLM, а ядро: веса при загрузке проходят через RAM, и на машине с 16 ГБ модель на 16 ГБ упрётся гарантированно.

Ещё три частых стопора:

  • Долгий захват CUDA-графов. Лог замирает на Capturing CUDA graphs — это норма, холодный старт занимает 40–90 секунд, но systemd убивает сервис на середине: Job for vllm.service failed because a timeout was exceeded. Отсюда TimeoutStartSec=600 в юните выше; --enforce-eager сокращает старт ценой пропускной способности.
  • Неделимое число голов внимания. Total number of attention heads (32) must be divisible by tensor parallel size (3) — значение --tensor-parallel-size обязано быть делителем: 1, 2, 4, 8, но не 3 и не 6.
  • Мало разделяемой памяти в контейнере. Docker даёт /dev/shm всего 64 МБ, а процессы vLLM обмениваются через неё тензорами: при --tensor-parallel-size 2 контейнер падает с Bus error (core dumped) без трейсбека. Лечится --shm-size=8g или --ipc=host.

API поднялся, но отвечает не то: 404, 400 и обрыв стрима

Сервер слушает, /health отдаёт 200, а клиент получает ошибку. Это HTTP-слой, лечится за минуты.

404 на имя модели — частая ошибка интеграции:

{"object":"error","message":"The model `llama3` does not exist.","type":"NotFoundError","code":404}

vLLM ждёт в поле model ровно ту строку, которой запущен: полный путь meta-llama/Llama-3.1-8B-Instruct или локальный каталог. Короткие имена в стиле Ollama он не понимает — задайте псевдоним --served-model-name llama3.

401 и открытый наружу порт. Без флага --api-key vLLM не проверяет авторизацию вообще, а с --host 0.0.0.0 это открытый инференс-сервер за ваш счёт. Слушайте loopback, наружу выпускайте через Nginx с TLS:

sudo ufw allow 22/tcp
sudo ufw deny 8000/tcp
sudo ufw enable

Ключ — --api-key sk-local-$(openssl rand -hex 16). Приходит 401 при верном ключе — виноват Nginx: auth_basic использует тот же заголовок Authorization и съедает ключ клиента.

400 по длине контекста. Ответ объясняет арифметику:

This model's maximum context length is 8192 tokens. However, you requested 8500 tokens
(500 in the messages, 8000 in the completion).

В лимит входит и max_tokens ответа, поэтому клиент с прошитым max_tokens: 8000 сломается даже на крошечном промпте.

Нет шаблона чата. Базовые модели, в отличие от Instruct-версий, часто не содержат chat_template в токенизаторе:

ValueError: As of transformers v4.44, default chat template is no longer allowed,
so you must provide a chat template if the tokenizer does not define one.

Передайте шаблон Jinja флагом --chat-template или перейдите на /v1/completions. Рядом — вызов инструментов: без --enable-auto-tool-choice --tool-call-parser hermes модель вернёт JSON текстом в content, а клиент будет ждать tool_calls.

Nginx рвёт стриминг. Ответ приходит целиком после паузы, а длинная генерация обрывается на 504:

location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_buffering off;
    proxy_read_timeout 600s;
    proxy_http_version 1.1;
}

Порт занят умершим не до конца процессом — uvicorn скажет [Errno 98] ... address already in use, ищите через sudo ss -ltnp | grep 8000. И следите за vllm:num_requests_waiting в /metrics: стабильно больше нуля — нехватка железа.

Какой сервер брать под vLLM в MAATRIX

Сразу честно: vLLM нет в каталоге apps.maatrix.io, автоматической установки при заказе не будет. Сервер приезжает чистым — Ubuntu 24.04 или Debian 12, — и vLLM вы ставите по второму разделу статьи. Зато в каталоге есть готовые сборки соседей по стеку: Ollama как запасной движок на CPU, LiteLLM как шлюз с ключами и бюджетами перед vLLM, AnythingLLM или Dify как интерфейс, Qdrant под векторы.

Честный минимум: GPU с 24 ГБ VRAM, 8 vCPU, 32 ГБ RAM, 100 ГБ NVMe. Граница, за которой vLLM имеет смысл: 8B в FP16 занимает 16 ГБ, остаток уходит под KV-кэш, контекст держится на 8–16 тысячах токенов. Оперативная память нужна не для счёта, а чтобы через неё прошла загрузка весов.

Комфортный вариант: 48 ГБ VRAM одной картой или две по 24 с --tensor-parallel-size 2, 16 vCPU, 64 ГБ RAM, 200–300 ГБ NVMe. Здесь 8B живёт в FP16 с длинным контекстом, 32B — в 4-битном AWQ, а на диске лежит несколько моделей: каждая весит от 5 до 65 ГБ.

Без GPU vLLM брать не надо. Для CPU-инференса хватит 8 vCPU и 16–32 ГБ RAM под Ollama: 7–13 токенов в секунду на моделях 7–9B — боту и ночной обработке документов достаточно, живому чату нет.

Локация — Великобритания, Лондон. Довод практический: с британского адреса HuggingFace, PyPI и реестры контейнеров открываются напрямую, а hf download на 16 ГБ не рвётся на середине. Плюс низкий пинг до Европы и понятная контрагентам юрисдикция. Берите US, если рядом стоит прокси к зарубежным API, и RU, если данные обязаны оставаться в России по 152-ФЗ. Подробности — в материале GPU-сервер в Великобритании для инференса LLM.

Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT; доступы появляются в личном кабинете. Совет напоследок: прежде чем заказывать GPU, снимите на своём трафике число одновременных запросов в пике. Меньше четырёх — vLLM не окупится, начните с Ollama на обычном VPS.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

vllm serve работает из консоли, а под systemd падает. Почему?

Чаще всего из-за токена HuggingFace: hf auth login кладёт его в ~/.cache/huggingface/token вашего пользователя, а сервис работает от другого и получает GatedRepoError: 401. Передавайте HF_TOKEN через EnvironmentFile и не забудьте TimeoutStartSec=600: холодный старт занимает до полутора минут.

Можно ли запустить vLLM на VPS без видеокарты?

Формально да, сборкой из исходников с VLLM_TARGET_DEVICE=cpu, но смысла нет: готовых колёс под CPU не публикуют, а выигрыш vLLM держится на видеопамяти. Берите Ollama или llama.cpp.

Как понять, чего не хватает — видеопамяти или обычной?

По источнику сообщения. CUDA out of memory и larger than the maximum number of tokens that can be stored in KV cache — это VRAM, лечится --max-model-len и квантованием. А исчезнувший без ошибок процесс — это RAM хоста: sudo dmesg -T | grep -i 'killed process' покажет VLLM::EngineCore.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.