Для серверного API на одной машине практичнее всего развернуть open-weights LLM в Docker с vLLM и NVIDIA GPU: вы получаете OpenAI-совместимый endpoint, управляемый кеш весов и предсказуемую эксплуатацию. Метод не подходит, если у вас только CPU, очень мало VRAM, нужен многозонный отказоустойчивый кластер, строгий air-gap без предварительной загрузки образов и весов или вы не готовы отдельно закрывать авторизацию, TLS и лицензирование модели.
Короткий ответ
Базовый путь такой: подготовить Linux-сервер, установить Docker Engine и NVIDIA Container Toolkit, выбрать модель с понятной лицензией на Hugging Face, затем запустить контейнер vllm/vllm-openai и проверить API запросом к /v1/models и /v1/chat/completions.
В этой статье под open-source LLM я имею в виду прежде всего модели с открыто доступными весами. Юридический статус у разных семейств разный, поэтому карточку модели и лицензию проверяйте до запуска, а не после публикации сервиса.
Как выбрать стек
Критерии выбора простые: нужен ли OpenAI-совместимый API, сколько у вас VRAM, нужен ли высокий параллелизм и готовы ли вы обслуживать production-контур, а не только лабораторный стенд.
| Сценарий | Что выбрать | Почему | Ограничения |
|---|---|---|---|
| Одна или несколько NVIDIA GPU, нужен HTTP API | vLLM | Удобный сервер инференса, batching, OpenAI-совместимый интерфейс | Нужна совместимая модель и достаточная VRAM |
| CPU-only или маленькая GPU, нужен минимальный стек | llama.cpp | Работает с GGUF и квантованными моделями | Ниже пропускная способность и обычно больше ручной настройки |
| Быстрый локальный стенд или дев-среда | Ollama | Простой старт и удобные локальные команды | Меньше контроля над production-параметрами |
Ниже — практический путь для самого частого сценария: один Linux-сервер, NVIDIA GPU, контейнерный запуск и API для внутреннего сервиса или чат-бота.
Что понадобится
- Linux-сервер. Проще всего работать на Ubuntu 22.04 или 24.04. Другие дистрибутивы тоже подходят, но команды установки отличаются.
- NVIDIA GPU и драйвер. Для моделей класса 7B или 8B обычно нужен сервер хотя бы с одной GPU, где выбранная точность и длина контекста помещаются в VRAM. Точный объём памяти зависит от квантования, длины контекста и внутренних настроек сервера.
- Docker Engine. Это минимальный операционный слой для воспроизводимого запуска и обновлений.
- NVIDIA Container Toolkit. Без него контейнер не увидит GPU.
- Диск под веса и кеш. Держите отдельный каталог под кеш Hugging Face. Для одной-двух моделей и образов контейнеров удобно закладывать десятки гигабайт, а не пытаться уместить всё в системный раздел.
- Модель с понятной лицензией. Например, instruct-модель для диалогов. Для первого запуска удобно брать семейство, которое хорошо документировано и публично доступно.
- План по безопасности. Если API будет доступен извне, заранее решите, где будут TLS, авторизация, ограничение источников и журналирование.
Если у вас нет GPU, но модель всё равно нужна на своём сервере, сразу смотрите в сторону
llama.cppи GGUF-моделей. Путь с vLLM имеет смысл прежде всего для GPU-сервинга.
Пошаговый план
1. Убедитесь, что сценарий вам подходит
Этот способ хорош, когда нужен серверный API для приложений, а не только интерактивная CLI-сессия. Если вы планируете десятки моделей на одном узле, сложный multi-tenant, автоматическое распределение нагрузки по нескольким серверам или жёсткий офлайн-контур, базовый контейнерный запуск — только первый шаг, а не готовая архитектура.
2. Подготовьте сервер и проверьте GPU
Установите Docker Engine и NVIDIA Container Toolkit по официальным инструкциям. Не копируйте устаревшие команды из случайных блогов: у Docker и NVIDIA меняются репозитории, ключи и поддерживаемые версии.
nvidia-smi
Если команда показывает вашу GPU и версию драйвера, переходите к проверке внутри контейнера.
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
Если и этот тест проходит, контейнерный рантайм уже видит устройство. Если нет, проблема почти всегда в драйвере, версии toolkit или настройках Docker runtime.
3. Выберите модель и проверьте лицензию
Для первого запуска разумно взять instruct-модель среднего размера, например Qwen/Qwen2.5-7B-Instruct. У неё публичная карточка, понятный формат распространения и хороший практический сценарий — чат и генерация текста. Важно не только название модели, но и три вещи: лицензия, требования к памяти и максимальная длина контекста, которую вы реально будете использовать.
Не закладывайте в стартовый запуск максимальный контекст только потому, что модель его теоретически поддерживает. Чем больше max-model-len, тем выше давление на память и тем чаще вы увидите ошибки запуска или деградацию пропускной способности.
4. Подготовьте каталог под кеш весов
Хранить веса внутри слоя контейнера неудобно: при пересоздании контейнера вы заново качаете модель. Сделайте внешний каталог.
sudo mkdir -p /srv/huggingface
sudo chown $USER:$USER /srv/huggingface
5. Запустите vLLM
Для первого безопасного запуска привяжите API только к localhost. Публиковать порт наружу стоит только после того, как у вас появятся reverse proxy, TLS и авторизация.
docker run -d --name llm --restart unless-stopped --gpus all -p 127.0.0.1:8000:8000 -v /srv/huggingface:/root/.cache/huggingface --ipc=host vllm/vllm-openai:latest --model Qwen/Qwen2.5-7B-Instruct --dtype auto --max-model-len 8192
Если модель gated или private, добавьте переменную окружения с токеном Hugging Face.
docker run -d --name llm --restart unless-stopped --gpus all -e HUGGING_FACE_HUB_TOKEN=hf_xxx -p 127.0.0.1:8000:8000 -v /srv/huggingface:/root/.cache/huggingface --ipc=host vllm/vllm-openai:latest --model Qwen/Qwen2.5-7B-Instruct --dtype auto --max-model-len 8192
Если у вас несколько GPU и модель должна раскладываться по ним, добавьте параметр --tensor-parallel-size с нужным числом устройств. Не включайте это по привычке: одна GPU — значение не нужно.
6. Проверьте логи и доступность API
На первом старте контейнер может заметно ждать: образ загружается, веса скачиваются, модель инициализируется. Это нормально. Важны не секунды ожидания, а отсутствие циклических ошибок и OOM.
docker logs -f llm
Когда сервер поднялся, проверьте список моделей.
curl http://127.0.0.1:8000/v1/models
Затем сделайте минимальный чат-запрос.
curl http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"Qwen/Qwen2.5-7B-Instruct","messages":[{"role":"user","content":"Ответь одним словом: сервер?"}],"temperature":0}'
Если вы видите валидный JSON-ответ с завершением генерации, сервис в рабочем состоянии.
7. Закрепите конфигурацию до публикации
Первый запуск почти всегда делается на плавающих версиях и дефолтных параметрах. Для production это плохая идея. После smoke test зафиксируйте конкретный образ, модель и, если возможно, ревизию модели. Иначе вы рискуете получить неожиданное поведение после следующего перезапуска.
Также проверьте, где у вас будет внешний вход. Хорошая практика — оставить LLM-порт локальным и выставлять наружу уже ваш прикладной сервис или отдельный прокси с TLS, auth и rate limiting.
8. Учтите эксплуатационные ограничения
Самые частые реальные ограничения — память, длина контекста, холодный старт и дисковый кеш. Если VRAM на грани, сначала уменьшайте размер модели или контекст, а не пытайтесь компенсировать всё системной памятью. Если нужен полностью офлайн-контур, заранее скачайте контейнерные образы и модельные файлы в локальное хранилище: сам по себе пример выше предполагает, что сервер может обратиться к внешнему реестру и к Hugging Face.
9. Планируйте обновления без простоя
Не перетягивайте новую модель или новый контейнер поверх рабочего процесса в часы нагрузки. Практичнее поднять второй экземпляр на другом порту, прогнать короткий набор тестов и только потом переключать трафик. Даже на одном сервере это даёт больше контроля, чем обновление «на живую».
Типичные ошибки
- Выбрана слишком большая модель. Контейнер либо не стартует, либо падает с ошибками памяти. Начинайте с меньшей instruct-модели и реального, а не максимального контекста.
- Порт открыт наружу без защиты. LLM API не должен сразу смотреть в интернет. Сначала ограничьте доступ, включите TLS и авторизацию, затем публикуйте.
- Используется плавающий стек. Тег
latest, незакреплённая ревизия модели и отсутствие changelog-проверки — прямой путь к труднообъяснимым регрессиям. - Игнорируется лицензия. Публичный доступ к модели не означает, что её можно без ограничений использовать в продукте или для определённых типов данных.
- Кеш хранится в неудобном месте. Если веса лежат в эфемерном слое контейнера или на медленном сетевом диске, рестарты и холодные старты будут болезненными.
- Контекст завышен без причины. Чем выше
max-model-len, тем тяжелее запуск и тем выше расход памяти. Для большинства прикладных сценариев разумнее начинать с умеренного значения. - Не проверена работа GPU внутри контейнера. Видимость GPU на хосте не гарантирует, что контейнер тоже её увидит. Тест с
nvidia/cudaобязателен.
Как проверить результат
- Проверка доступности API. Запрос к
/v1/modelsдолжен возвращать список моделей без ошибок 5xx. - Проверка базовой генерации. Короткий запрос к
/v1/chat/completionsдолжен завершаться корректным JSON и текстом ответа. - Проверка ресурсов. Во время запроса смотрите
nvidia-smiиdocker stats. Вас интересуют не «красивые цифры», а отсутствие OOM и повторяемая загрузка GPU. - Проверка логов. В
docker logs llmне должно быть циклических ошибок и повторной инициализации модели на каждый запрос. - Проверка сетевого контура. Если сервис доступен извне, убедитесь, что прямой доступ к внутреннему порту отсутствует, а внешний путь закрыт TLS и авторизацией.
- Проверка повторяемости. При
temperature=0короткие технические запросы должны вести себя предсказуемо. Это простой способ заметить, что вы случайно тестируете не ту модель или не тот endpoint.
Минимальный практический критерий готовности такой: контейнер стабильно переживает рестарт, веса не скачиваются заново без необходимости, API отвечает после перезапуска, а нагрузка на GPU выглядит ожидаемо и без ошибок памяти.
FAQ
Можно ли развернуть такую модель без GPU?
Да, но это уже другой компромисс. Для CPU-only и малых GPU чаще берут llama.cpp и GGUF-кванты. Для серверного API с нормальной задержкой путь с vLLM без GPU обычно не лучший.
Сколько VRAM нужно?
Универсальной цифры нет. На память влияют размер модели, точность, квантование, длина контекста и внутренние буферы сервера. Практический принцип простой: начинайте с меньшей модели и умеренного контекста, а не наоборот.
Нужен ли токен Hugging Face?
Для публичных моделей обычно нет. Для gated или private-репозиториев нужен. Даже если токен не нужен, серверу всё равно нужен сетевой доступ к реестру и к модели, если вы не подготовили локальное зеркало заранее.
Почему не Ollama?
Ollama удобен для локальной разработки и быстрых стендов. Но если вам нужен именно сервер инференса с привычным API, контролем параметров и понятной эксплуатацией на GPU, vLLM обычно удобнее как базовый production-слой.
Как сделать полностью офлайн-развёртывание?
Нужно заранее скачать контейнерные образы, веса модели и все зависимости во внешней сети, затем перенести их в локальный registry и локальное хранилище. Сам пример запуска из этой статьи предполагает онлайн-доступ на этапе первоначальной загрузки.
Как обновлять модель безопасно?
Запускайте новый экземпляр параллельно старому, проверяйте ответы на коротком тестовом наборе, затем переключайте трафик. Не обновляйте рабочий контейнер вслепую и не полагайтесь на плавающие теги.