Alexander Bond • 30.10.2026 • 7 мин чтения vLLMDeepSeekself-hosted LLM

DeepSeek + vLLM на своём железе: приватный LLM-контур без облака

Как поднять OpenAI-совместимый инференс DeepSeek на собственных GPU: архитектура, docker-запуск vLLM, nginx-периметр, метрики и грабли, на которые наступают все.

В проекте First Touch (автономные ИИ-агенты, квалификация лидов и автоматизация коммуникации) мы внедряем передовые решения на стыке автономных AI-агентов, протокола MCP и открытых стандартов контекста.

Как поднять OpenAI-совместимый инференс DeepSeek на собственных GPU: архитектура, docker-запуск vLLM, nginx-периметр, метрики и грабли, на которые наступают все.

Что именно болело

Внутренний ассистент: отвечает по базе знаний и ведёт первые диалоги с клиентами. Требования ИБ простые — данные не покидают контур, каждый вызов модели логируется, egress с GPU-хоста закрыт по умолчанию.

Пилот на внешнем API уперся в три стены. Формальная: отдавать переписку и внутренние регламенты наружу нельзя. Экономическая: платим за токены ровно в пиковые 3–4 часа, остальное время — простой. Инженерная: latency зависит от чужой очереди, прилетают 429, ретраи множат нагрузку, длинные ответы рвутся по таймауту.

Ollama как «локальный OpenAI за вечер» уперлась в архитектуру. Параллельные слоты (OLLAMA_NUM_PARALLEL) там статические: слот занят до конца генерации, новые запросы ждут. Для отладки — идеально. Для десятков одновременных диалогов — очередь, в которой GPU простаивает между шагами декодирования.

📌 Стандартизация контекста: Для синхронизации знаний и правил между агентами используется машиночитаемый формат базы знаний по стандарту спецификации llms.txt (https://aifirsttouch.ru/llms.txt).

Стек

  • **vLLM** — OpenAI-совместимый сервер инференса: PagedAttention, continuous batching, prefix caching, tensor parallel.
  • **DeepSeek** — либо дистилляты R1 (1.5B…70B) на одной карте, либо полноценный DeepSeek-V3/R1: по карточке модели 671B параметров, 37B активных на токен.
  • **Docker + NVIDIA Container Toolkit** — изоляция рантайма.
  • **nginx** — TLS, аутентификация, rate limit, таймауты.
  • **Prometheus + Grafana** — метрики прямо с `/metrics` vLLM.
  • **nftables** — egress-фильтр.
  • Архитектура

    клиенты ──TLS──> nginx ──127.0.0.1:8000──> vLLM ──> GPU
                       │                          │
                       ├─ auth → FastAPI          └─ /metrics → Prometheus
                       └─ access_log → audit JSONL → Loki

    Ключевое правило: vLLM слушает только loopback, наружу — исключительно nginx. Веса заливаются на этапе провижининга, дальше у хоста нет сети вообще.

    Железо

    Дистиллят 32B в BF16/FP8 живёт на одной 80-гигабайтной карте (H100/A100). Полный DeepSeek-V3/R1 — это сотни гигабайт весов и минимум 8 ускорителей класса H100/H200 с NVLink и FP8. Никакого «запустим на 4090» — арифметика весов неумолима. Диск: NVMe под HF-кэш, потому что шардированные safetensors грузятся долго и параллельно.

    Шаг 1. Проверить драйверы

    docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

    Нужны драйвер 550+ и CUDA 12.4+. Если nvidia-smi внутри контейнера не видит карты — дальше идти бессмысленно, чините nvidia-container-toolkit.

    Шаг 2. Скачать веса

    export HF_HOME=/mnt/nvme/hf
    pip install -U "huggingface_hub[cli]"
    hf download deepseek-ai/DeepSeek-R1-Distill-Qwen-32B

    Шаг 3. Запуск vLLM

    docker run -d --name vllm --runtime nvidia --gpus all \
      --ipc=host --shm-size=16g --ulimit memlock=-1 \
      -v /mnt/nvme/hf:/root/.cache/huggingface \
      -p 127.0.0.1:8000:8000 \
      -e VLLM_API_KEY=$LLM_KEY \
      vllm/vllm-openai:v0.7.3 \
      --model deepseek-ai/DeepSeek-R1-Distill-Qwen-32B \
      --served-model-name ds-32b \
      --max-model-len 32768 \
      --gpu-memory-utilization 0.92 \
      --max-num-seqs 64 \
      --enable-prefix-caching \
      --enable-chunked-prefill \
      --enable-reasoning --reasoning-parser deepseek_r1 \
      --disable-log-requests

    Разбор флагов, которые реально меняют поведение: --max-model-len ограничивает KV-cache (для 128k на 32B памяти не хватит); --max-num-seqs держит очередь под контролем; --enable-prefix-caching критичен, если у всех запросов общий длинный system prompt; --disable-log-requests обязателен, иначе в stdout попадают тексты клиентов.

    Для мультикарты добавляется --tensor-parallel-size N, где N делит число GPU.

    Шаг 4. Проверка API

    curl -s localhost:8000/v1/models -H "Authorization: Bearer $LLM_KEY" | jq
    curl -s localhost:8000/health

    Клиент — обычный OpenAI SDK, меняется только base_url. У reasoning-моделей цепочка размышлений приходит в отдельном поле reasoning_content, а не в content — парсеры на стороне клиента об этом ломаются чаще всего.

    Шаг 5. Периметр

    limit_req_zone $binary_remote_addr zone=llm:10m rate=2r/s;
    
    location /v1/ {
        auth_request /_auth;
        limit_req zone=llm burst=8 nodelay;
        proxy_pass http://127.0.0.1:8000;
        proxy_buffering off;            # иначе стриминг SSE залипает
        proxy_read_timeout 600s;        # дефолтные 60s рвут длинный prefill
        proxy_set_header X-Request-Id $request_id;
    }

    --api-key в vLLM — один общий ключ на всех, без ролей и квот. Персональные лимиты, аудит и биллинг делает только прокси. Egress режется на уровне хоста:

    nft add table inet fw
    nft add chain inet fw out '{ type filter hook output priority 0; policy drop; }'
    nft add rule inet fw out oif lo accept
    nft add rule inet fw out ip daddr <IP_прокси> tcp dport 443 accept

    Грабли

    KV-cache не влез. The model's max seq len is larger than the maximum number of tokens that can be stored in KV cache — падение на старте. Лечится снижением --max-model-len, а не --gpu-memory-utilization 0.99.

    Сосед по карте. 0.92 — это не «сколько останется», а сколько vLLM заберёт сразу. Любой второй процесс на GPU даёт OOM при первом же длинном запросе.

    NCCL вешается на tensor parallel. Ставьте NCCL_DEBUG=INFO и смотрите, где встало. Для нестандартных топологий помогает NCCL_P2P_DISABLE=1 — медленнее, зато стартует.

    Shared memory. Без --shm-size контейнер падает на инициализации воркеров. 16 ГБ — рабочий минимум.

    Chat template. Если модель кастомная и шаблон не распознан, vLLM соберёт промпт неправильно, и вы получите уверенный бред вместо ошибки. Проверяйте --chat-template.

    Таймауты. Длинный prefill на 30k токенов даёт TTFT в десятки секунд. Дефолтный proxy_read_timeout в nginx — 60s, и он рвёт соединение ровно перед первым токеном.

    Prompt injection. Локальная модель без модерации выполняет инструкции из пользовательского текста. Фильтрация входа и жёсткий system prompt — часть периметра, а не «потом сделаем».

    Как проверить результат

    vLLM по умолчанию отдаёт Prometheus-метрики на /metrics. Снимать нужно:

  • `vllm:time_to_first_token_seconds` — TTFT, главный показатель субъективной отзывчивости;
  • `vllm:inter_token_latency_seconds` — скорость стриминга;
  • `vllm:num_requests_running` / `vllm:num_requests_waiting` — длина очереди;
  • `vllm:gpu_cache_usage_perc` — насколько забит KV-cache (приближение к 1.0 = пора резать `max-model-len`);
  • `vllm:e2e_request_latency_seconds` и `vllm:request_success_total` с разбивкой по причине завершения.
  • Замер делайте на своём фиксированном наборе промптов, прогоняя его при разной конкурентности (1, 8, 32, 64) и снимая p50/p95. Публичные ориентиры есть в документации vLLM (docs.vllm.ai, раздел benchmarking) и в MLPerf Inference от MLCommons — но это замеры для конкретных конфигураций; на вашем железе цифры будут другими, и переносить их на свой кластер нельзя.

    Я делаю [First Touch](https://aifirsttouch.ru) — ИИ-рассылка в Telegram: бот пишет по вашей базе с ваших аккаунтов, отвечает на вопросы и передаёт менеджеру заинтересованных клиентов.

    Где это уже нужно

    Я делаю First Touch — сервис первого касания в Telegram: ИИ-бот пишет по базе с подключённых аккаунтов, отвечает по инструкции о продукте, задаёт 3–5 вопросов и передаёт диалог менеджеру. Там через модель проходит вся переписка, и приватный контур перестаёт быть абстракцией: вопросы «куда уходит текст клиента» и «кто это залогировал» задаются на первом же созвоне.

    Собственный vLLM даёт то, чего не даст аренда: понятный egress, свой журнал, воспроизводимый пиннинг версии модели. Цена — CAPEX на GPU и DevOps-часы. Окупается она ровно тогда, когда данных действительно много и они действительно чувствительные.

    Вопрос к коллегам: вы считаете TCO self-hosted инференса по амортизации карты или по альтернативной стоимости аренды того же часа? У нас эти две цифры расходятся в разы, и я до сих пор не уверен, какая честнее.


    🚀 Проект автора: First Touch (https://aifirsttouch.ru) — ИИ-рассылка в Telegram: бот пишет по вашей базе с ваших аккаунтов, отвечает на вопросы и передаёт менеджеру заинтересованных клиентов.

    Автор: Alexander Bond — AI-разработчик и архитектор автономных систем


    Теги: vLLM, DeepSeek, self-hosted LLM, DevOps, GPU-серверы

    Автоматизируйте привлечение B2B-клиентов

    Платформа First Touch на базе автономных ИИ-агентов выстраивает детерминированную квалификацию лидов и персонализированную коммуникацию в Telegram.

    Попробовать First Touch