Distributed
LLM Inference
Guide

vLLM, Ray Serve, TGI, On-prem ВМ + Kubernetes + cloud, команды, конфиги и процессы

2–24×
throughput vLLM vs naive serving
60–80%
KV cache waste без PagedAttention
4×
сжатие модели INT4 vs FP16
70%
экономия на spot GPU ВМ

// 01

Выбор стека

В 2026 году стек устоялся. vLLM — производственный стандарт для high-throughput inference. TGI — для экосистемы HuggingFace. Ray — оркестрация multi-node и multi-model. Выбор определяется не предпочтениями, а требованиями к нагрузке.

Матрица выбора

ИнструментДля чегоСильные стороныОграниченияКогда брать
vLLM High-throughput inference, production API, multi-GPU PagedAttention, continuous batching, OpenAI-compatible API, tensor/pipeline parallel из коробки Только NVIDIA CUDA (+ AMD ROCm beta). Не для CPU Default
TGI (HF) HuggingFace ecosystem, streaming, production с HF моделями Глубокая интеграция с HF Hub, Flash Attention, широкий список моделей Чуть ниже throughput чем vLLM. Менее гибкий параллелизм HF ecosystem
Ray Serve Оркестрация multi-node, multi-model, routing, autoscaling Fault tolerance, autoscaling, pipeline между моделями, cloud-agnostic Overhead на простые single-node деплои. Сложнее в настройке Multi-node / Multi-model
SGLang Structured generation, сложные agent pipelines Оптимизация для multi-step generation, RadixAttention для KV reuse Менее зрелая экосистема. Требует специфичной настройки Agent / Chain
Ollama / llama.cpp Dev-среда, CPU inference, прототипы CPU offload через GGUF, простой запуск, Apple Silicon Не production throughput. Нет distributed serving Dev только

Правило 2026: один GPU на одной ноде → standalone vLLM. Несколько GPU на одной ноде → vLLM с tensor parallelism. Несколько нод → vLLM + Ray. Несколько моделей или сложные пайплайны → Ray Serve как оркестратор над vLLM backends.

Архитектурные паттерны по вашей инфраструктуре

On-prem ВМ с GPU

vLLM напрямую или через Docker. Ray для multi-node. NFS/Object storage для моделей. Фиксированный baseline.

Kubernetes on-prem

vLLM в Pod с GPU resource limits. KubeRay для Ray cluster. KEDA для autoscaling по queue depth. NVIDIA GPU Operator.

Cloud ВМ (несколько)

Spot GPU ВМ для burst. Ray head on-prem, workers в cloud. Hybrid: модель в on-prem, overflow в cloud.

Гибрид (ваш кейс)

Ray cluster: head node on-prem, worker pool: on-prem ВМ + K8s pods + cloud ВМ. Единый API endpoint.

// 02

GPU sizing и квантизация

Самый частый вопрос: сколько GPU нужно? Ответ: параметры модели × байт на параметр + KV cache + overhead. KV cache может превышать размер весов при большом batch или длинном контексте.

Формула расчёта памяти

pythonvram_calculator.py
# VRAM = weights + KV cache + activations + framework overhead
# Weights = params_B * bytes_per_param
# KV cache = 2 * num_layers * num_heads * head_dim * seq_len * batch * bytes

# Быстрый расчёт весов модели:
# FP16/BF16  → params_B * 2 GB
# INT8       → params_B * 1 GB
# INT4/AWQ   → params_B * 0.5 GB
# FP8        → params_B * 1 GB (лучше INT8 по качеству)

model_sizes = {
    "7B-FP16":  14,   # GB
    "7B-INT4":  4,    # GB (AWQ/GPTQ)
    "13B-FP16": 26,
    "13B-INT4": 7,
    "70B-FP16": 140,
    "70B-INT4": 35,   # влезает на 2×A100 40GB
    "405B-FP8": 405,  # требует 6-8 нод с A100 80GB
}

# Правило: добавить 30-50% к весам для KV cache при production нагрузке
# gpu_memory_utilization=0.90 — безопасный baseline для H100
# gpu_memory_utilization=0.95 — допустимо на B200/H200

Таблица sizing под железо

МодельPrecisionMin GPU configРекомендуемо
Llama-3.1-8BFP161× A100 40GB1× A100 80GB
Llama-3.1-8BINT4 AWQ1× RTX 4090 24GB1× A100 40GB
Llama-3.1-70BFP164× A100 80GB (TP=4)8× A100 80GB
Llama-3.1-70BINT4 AWQ2× A100 40GB (TP=2)2× A100 80GB
Mistral-7BFP161× A100 40GB1× A100 80GB
Qwen2.5-32BFP162× A100 80GB4× A100 80GB
Llama-3.1-405BFP88× A100 80GB (TP=8,PP=2)16× A100 80GB
DeepSeek-R1-70BINT42× A100 40GB4× A100 80GB

Квантизация: что выбрать

FP8 (рекомендуется для H100/H200/B200)

GPU-native, почти нет потери качества vs FP16. Нативная поддержка в vLLM. Лучший выбор для Hopper+ архитектур.

AWQ INT4 (GPU production)

95% качества FP16 при 4× меньшем VRAM. Отличная поддержка в vLLM (Marlin kernels: 10× speedup над baseline AWQ). Лучший GPU INT4.

GPTQ INT4 (legacy GPU)

Чуть ниже качества AWQ, но огромное количество готовых моделей. С Marlin kernels в vLLM — 2.6× speedup. Допустимо для production.

GGUF Q4_K_M (CPU / hybrid)

Только для dev-сред или CPU offload сценариев. 92% качества FP16. Единственный вариант для CPU inference. Не для production GPU.

Ключевой принцип квантизации: большая модель при INT4 почти всегда лучше меньшей модели при FP16. Llama-3.1-70B INT4 (35GB) значительно превосходит Llama-3.1-7B FP16 (14GB) при похожем VRAM footprint.

// 03

Параллелизм: TP, PP, DP

Три вида параллелизма решают разные задачи. Неправильный выбор стоит throughput.

Tensor Parallelism (TP)

Делит матрицы весов между GPU. Требует высокоскоростного interconnect (NVLink). Для GPU в одной ноде — первый выбор. tensor_parallel_size = число GPU в ноде.

Pipeline Parallelism (PP)

Делит модель по слоям между нодами. Допустима медленная сеть (Ethernet). Для multi-node. pipeline_parallel_size = число нод.

Data Parallelism (DP)

Несколько полных копий модели обрабатывают разные запросы. Для throughput при условии что модель влезает. Классический horizontal scale.

Правила выбора

textparallelism_decision_tree
Модель влезает на 1 GPU?
  └── Да → Data Parallelism (несколько реплик vLLM)
      Нет → Модель влезает на 1 ноду с N GPU?
              └── Да → Tensor Parallelism (TP=N)
                        └── GPU с NVLink? → Предпочесть TP
                        └── GPU без NVLink (L40S)? → Предпочесть PP
                  Нет → Multi-node: TP=GPU_per_node, PP=num_nodes
                        └── Для MoE моделей (Mixtral/DeepSeek):
                            TP + Expert Parallelism (EP)

# Золотое правило vLLM 2025+:
# TP размер должен быть степенью 2 и делить attention heads без остатка
# Total GPUs = tensor_parallel_size × pipeline_parallel_size

# Пример: 2 ноды по 4 GPU = 8 GPU total
vllm serve model \
  --tensor-parallel-size 4 \  # TP в пределах ноды
  --pipeline-parallel-size 2 \  # PP между нодами
  --distributed-executor-backend ray

GPU без NVLink (например L40S, RTX серия) — используйте Pipeline Parallelism вместо Tensor Parallelism между нодами. Tensor Parallelism требует high-bandwidth interconnect: без NVLink коммуникационные расходы съедают всю выгоду.

// 04

Деплой на ВМ: single и multi-node

Самый прямолинейный путь. Минимум зависимостей, максимум контроля. Хорошо подходит как постоянная база для больших моделей.

Single-node (одна ВМ с несколькими GPU)

bashsingle_node_setup.sh
# 1. Prerequisites
pip install vllm  # CUDA 12.1+ required

# 2. Запуск — 4 GPU, модель 70B INT4
vllm serve meta-llama/Llama-3.1-70B-Instruct \
  --tensor-parallel-size 4 \
  --quantization awq_marlin \
  --gpu-memory-utilization 0.90 \
  --max-model-len 32768 \
  --enable-prefix-caching \
  --enable-chunked-prefill \
  --max-num-seqs 256 \
  --port 8000 \
  --host 0.0.0.0 \
  --api-key $VLLM_API_KEY

# 3. Проверка
curl http://localhost:8000/v1/models \
  -H "Authorization: Bearer $VLLM_API_KEY"

# 4. Тест генерации
curl http://localhost:8000/v1/chat/completions \
  -H "Authorization: Bearer $VLLM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"meta-llama/Llama-3.1-70B-Instruct",
     "messages":[{"role":"user","content":"Hello"}],
     "max_tokens":100}'

Multi-node через Ray (2 ноды, 8 GPU суммарно)

bashmulti_node_ray_setup.sh
# === НОДА 1 (head) — запустить первой ===
pip install vllm ray[default]

# Запуск Ray head
ray start --head \
  --port 6379 \
  --dashboard-host 0.0.0.0

# === НОДА 2 (worker) — подключиться к head ===
ray start \
  --address 'NODE1_IP:6379' \
  --block

# === НА HEAD НОДЕ: запуск vLLM ===
vllm serve meta-llama/Llama-3.1-405B-Instruct-FP8 \
  --tensor-parallel-size 4 \  # GPU на ноду
  --pipeline-parallel-size 2 \  # число нод
  --distributed-executor-backend ray \
  --gpu-memory-utilization 0.90 \
  --enable-prefix-caching \
  --port 8000

# Проверить Ray cluster:
ray status

Docker Compose для production-изоляции

yamldocker-compose.yml
services:
  vllm:
    image: vllm/vllm-openai:v0.8.5  # Пинить конкретный тег!
    runtime: nvidia
    environment:
      NVIDIA_VISIBLE_DEVICES: all
      HUGGING_FACE_HUB_TOKEN: ${HF_TOKEN}
      VLLM_API_KEY: ${VLLM_API_KEY}
    volumes:
      - /mnt/models:/models:ro  # NFS или local path
      - vllm-cache:/root/.cache
    command: >
      --model /models/llama-3.1-70b-instruct-awq
      --tensor-parallel-size 4
      --quantization awq_marlin
      --gpu-memory-utilization 0.90
      --max-model-len 32768
      --enable-prefix-caching
      --served-model-name llama-70b
    ports:
      - "8000:8000"
    healthcheck:
      test: ["CMD","curl","-f","http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      start_period: 120s  # Модели загружаются долго
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        reservations:
          devices:
          - driver: nvidia
            count: all
            capabilities: [gpu]

volumes:
  vllm-cache:

// 05

Деплой на Kubernetes

K8s добавляет autoscaling, health management и multi-replica управление. Основная сложность — GPU scheduling и KV-cache-aware autoscaling. С 2026 года Gateway API Inference Extension (GA) добавляет model-aware routing из коробки.

Prerequisites: NVIDIA GPU Operator

bashgpu_operator_setup.sh
# Установка NVIDIA GPU Operator (обязателен для GPU scheduling)
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update

helm install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator \
  --create-namespace \
  --set driver.enabled=false \  # Если драйвер уже установлен
  --set toolkit.enabled=true

# Проверить GPU resource
kubectl get nodes -o json | jq '.items[].status.capacity | select(."nvidia.com/gpu")'

vLLM Deployment на K8s

yamlvllm-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-llama70b
  namespace: inference
spec:
  replicas: 2
  selector:
    matchLabels:
      app: vllm-llama70b
  template:
    metadata:
      labels:
        app: vllm-llama70b
        model: llama-3.1-70b
    spec:
      nodeSelector:
        nvidia.com/gpu.product: A100-SXM4-80GB
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "kubernetes.io/hostname"
        whenUnsatisfiable: DoNotSchedule
      containers:
      - name: vllm
        image: vllm/vllm-openai:v0.8.5
        args:
        - --model=/models/llama-3.1-70b-awq
        - --tensor-parallel-size=4
        - --quantization=awq_marlin
        - --gpu-memory-utilization=0.90
        - --max-model-len=32768
        - --enable-prefix-caching
        - --port=8000
        env:
        - name: VLLM_API_KEY
          valueFrom:
            secretKeyRef:
              name: vllm-secrets
              key: api-key
        resources:
          requests:
            nvidia.com/gpu: "4"
            memory: 64Gi
            cpu: "8"
          limits:
            nvidia.com/gpu: "4"
            memory: 128Gi
            cpu: "16"
        volumeMounts:
        - name: model-storage
          mountPath: /models
          readOnly: true
        readinessProbe:
          httpGet: {path: /health, port: 8000}
          initialDelaySeconds: 120
          periodSeconds: 10
        livenessProbe:
          httpGet: {path: /health, port: 8000}
          initialDelaySeconds: 180
          periodSeconds: 30
          failureThreshold: 3
      volumes:
      - name: model-storage
        persistentVolumeClaim:
          claimName: model-pvc

KEDA autoscaling по queue depth

yamlkeda-vllm-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: vllm-scaler
  namespace: inference
spec:
  scaleTargetRef:
    name: vllm-llama70b
  minReplicaCount: 1
  maxReplicaCount: 4
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      # Scale по queue depth (in-flight requests)
      query: avg(vllm:num_requests_waiting)
      threshold: "10"  # >10 waiting → добавить реплику
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      # Также scale по KV cache utilization
      query: avg(vllm:gpu_cache_usage_perc) * 100
      threshold: "80"  # >80% KV cache → scale up

// 06

Ray Cluster: конфигурация для гибридной инфраструктуры

Ray — оркестратор для вашего кейса: on-prem ВМ + Kubernetes + cloud ВМ как единый кластер. Head node on-prem, worker pool гетерогенный.

Гибридная топология

yamlray-cluster-config.yaml
# ray up ray_hybrid_cluster.yaml
cluster_name: hybrid-inference

provider:
  type: local  # Head на on-prem ВМ
  head_ip: 192.168.1.10

head_node_type:
  node_config: {}
  resources:
    CPU: 32
    GPU: 4

available_node_types:
  # On-prem ВМ workers
  onprem_gpu_worker:
    min_workers: 1
    max_workers: 3
    resources:
      CPU: 32
      GPU: 4
    node_config:
      NodeType: onprem

  # Cloud burst workers (spot)
  cloud_gpu_worker:
    min_workers: 0  # Scale to zero когда не нужно
    max_workers: 5
    resources:
      CPU: 48
      GPU: 8
    node_config:
      InstanceType: p4d.24xlarge  # 8× A100 40GB
      SpotInstances: true

setup_commands:
  - pip install vllm ray[default]
  - pip install ray[serve]

Ray Serve + vLLM: multi-model routing

pythonray_serve_vllm.py
import ray
from ray import serve
from vllm.engine.arg_utils import AsyncEngineArgs
from vllm.engine.async_llm_engine import AsyncLLMEngine

ray.init("ray://head-node-ip:10001")

@serve.deployment(
    num_replicas=2,
    ray_actor_options={
        "num_gpus": 4,
        "resources": {"NodeType": 0.001}  # Предпочесть on-prem
    }
)
class LLMDeployment:
    def __init__(self, model_id: str, tp_size: int):
        args = AsyncEngineArgs(
            model=model_id,
            tensor_parallel_size=tp_size,
            gpu_memory_utilization=0.90,
            enable_prefix_caching=True,
            quantization="awq_marlin",
        )
        self.engine = AsyncLLMEngine.from_engine_args(args)

    async def generate(self, prompt: str, params: dict):
        # OpenAI-compatible generation
        results = []
        async for output in self.engine.generate(prompt, ...):
            results.append(output)
        return results

# Роутер: направлять запросы по model_name
@serve.deployment
class ModelRouter:
    def __init__(self):
        self.models = {
            "llama-70b":  LLMDeployment.bind("llama-70b-awq", 4),
            "llama-8b":   LLMDeployment.bind("llama-8b", 1),
        }

    async def __call__(self, request):
        model_name = request.json()["model"]
        return await self.models[model_name].remote(request)

serve.run(ModelRouter.bind())

// 07

Production оптимизации

PagedAttention + Prefix Caching
EngineerAlways ON

PagedAttention — фундаментальная инновация vLLM: делит KV cache на страницы как виртуальная память ОС. Устраняет 60–80% фрагментации памяти. Prefix caching переиспользует KV cache для повторяющихся системных промптов.

  • Всегда включать: --enable-prefix-caching
  • Всегда включать: --enable-chunked-prefill (снижает TTFT для длинных промптов)
  • --gpu-memory-utilization 0.90 — безопасный базовый уровень для A100; 0.95 для H100/H200
  • KV cache utilization мониторить через метрику vllm:gpu_cache_usage_perc
Continuous Batching (встроено в vLLM)
EngineerDefault

В отличие от статического батчинга, continuous batching добавляет новые запросы в batch как только завершаются старые. Это единственно правильная стратегия для production LLM inference.

  • --max-num-seqs 256 — максимум одновременных последовательностей
  • --max-num-batched-tokens 32768 — регулировать под GPU memory
  • При высоком concurrency мониторить vllm:num_requests_waiting — если растёт, нужно больше реплик или снизить max-model-len
Speculative Decoding (для latency-sensitive)
EngineerAdvanced

Маленькая draft-модель генерирует несколько токенов, большая верифицирует. Снижает TTFT и inter-token latency без потери качества при правильной настройке.

  • Подходит когда TTFT важнее throughput (chatbot, real-time интерфейсы)
  • Draft-модель должна быть в 5–10× меньше target
  • Не использовать для batch inference — теряется throughput
  • Флаги: --speculative-model, --num-speculative-tokens 5
Модель в shared memory / NFS для multi-worker
EngineerOn-prem critical

При нескольких нодах модели должны быть доступны на каждой. Варианты: NFS mount, pre-pull на каждую ноду, object storage (S3/MinIO).

  • NFS — прост, но bottleneck при загрузке больших моделей (70B = 35GB+ трансфер)
  • Рекомендуется: pre-pull моделей на каждую ноду с помощью скрипта при инициализации
  • vLLM поддерживает load model from local path — указывать --model /local/path
  • Для K8s: ReadOnlyMany PVC с NFS или использовать model-init-container
API Gateway / Load Balancer поверх vLLM
EngineerProduction

Не expose vLLM напрямую. Нужен слой маршрутизации, rate limiting, auth, и routing между репликами.

  • Nginx или Traefik для simple load balancing между репликами
  • LiteLLM proxy — OpenAI-compatible gateway, поддерживает vLLM, TGI, cloud API в одном endpoint
  • Gateway API Inference Extension (K8s, GA с февраля 2026) — KV-cache-aware routing из коробки
  • Sticky sessions НЕ нужны — vLLM stateless по запросам

// 08

Observability и метрики

vLLM экспортирует Prometheus метрики из коробки. Мониторить не CPU/RAM, а LLM-специфичные метрики: TTFT, inter-token latency, KV cache, queue depth.

Ключевые метрики vLLM

Метрика PrometheusНормаТревогаЧто значит
vllm:time_to_first_token_seconds P99 < 2s P99 > 5s — перегрузка Время до первого токена. Главная latency метрика.
vllm:time_per_output_token_seconds P99 < 100ms > 200ms — KV cache или batch переполнен Inter-token latency. Критично для streaming UX.
vllm:num_requests_waiting < 5 > 20 стабильно — нужно масштабировать Запросы в очереди. Главный сигнал для autoscaling.
vllm:gpu_cache_usage_perc 60–85% > 90% → preemption → latency spikes Использование KV cache. При overflow начинаются preemption.
vllm:num_requests_running Зависит от config = max_num_seqs постоянно Активные запросы. Если всегда на максимуме — бутылочное горло.
vllm:request_success_total Error rate < 0.1% > 1% ошибок Успешные vs failed запросы.
nvidia_smi_utilization_gpu 70–95% < 50% при нагрузке — неэффективно GPU utilization. Должен быть высоким при нагрузке.

Prometheus scrape config

yamlprometheus-scrape.yaml
scrape_configs:
- job_name: vllm
  scrape_interval: 15s
  static_configs:
  - targets: ['vllm-service:8000']  # vLLM metrics on /metrics

# Ключевые PromQL запросы для дашборда:

# TTFT P99
histogram_quantile(0.99,
  rate(vllm:time_to_first_token_seconds_bucket[5m]))

# Requests waiting (autoscaling trigger)
avg(vllm:num_requests_waiting)

# KV cache utilization
avg(vllm:gpu_cache_usage_perc) * 100

# Throughput (tokens/sec)
sum(rate(vllm:generation_tokens_total[1m]))

Сигналы для алертинга

🔴 Critical — немедленное действие

  • TTFT P99 > 10s в течение 5 минут
  • GPU OOM / pod restart
  • KV cache > 95% — preemption cascade
  • Error rate > 5%
  • Ray cluster nodes недостижимы

🟡 Warning — разобраться в течение часа

  • Requests waiting > 20 дольше 2 мин
  • TTFT P99 > 5s
  • KV cache > 85%
  • GPU utilization < 30% при нагрузке
  • Pod не прошёл readiness probe после 3 мин

✅ Что мониторить как норму

  • Tokens/sec (throughput baseline)
  • Inter-token latency P50/P95
  • Batch size distribution
  • Model load time при restart
  • Ray cluster resource utilization

📊 Business метрики

  • Cost per 1M tokens generated
  • GPU hours per request
  • SLA соответствие (TTFT P99)
  • Успешно обработанные запросы/сутки
  • Uptime inference endpoint

// 09

Процесс: роли, ритм и зоны ответственности

Руководитель / Eng. Manager

Выбор модели под бизнес-задачи. Определение SLA по latency. Бюджет GPU (on-prem vs cloud). Приоритизация optimization vs новых фич.

ML / Infra Engineer

Настройка vLLM/Ray. Выбор квантизации. Конфигурация parallelism. Production деплой, мониторинг, тюнинг параметров.

DevOps / Platform

K8s конфигурация. GPU Operator. KEDA autoscaling. CI/CD для model updates. Network / storage для моделей.

Ритм процесса

ФазаSETUP
Неделя 1–2: baseline деплой

Engineer: поднять vLLM на одной ноде, протестировать модель, настроить мониторинг. Manager: зафиксировать SLA требования (TTFT P99, throughput target). Выбрать квантизацию и сделать benchmark.

ФазаSCALE
Неделя 3–4: распределение и autoscaling

Добавить Ray для multi-node если нужно. Настроить K8s деплой если инфра готова. KEDA autoscaling по queue depth. Нагрузочное тестирование.

ФазаOPTIMIZE
Месяц 2: тюнинг и стабилизация

Оптимизация gpu_memory_utilization, max-num-seqs. Prefix caching эффективность. KV cache sizing. Runbook для инцидентов.

РитмDAILY
Автоматический мониторинг

Алерты на critical метрики: TTFT > threshold, OOM events, requests waiting > N. Никакого ручного труда в штатном режиме.

РитмWEEKLY
Engineer: performance review

Просмотр throughput trend, P99 TTFT за неделю, KV cache utilization. Обновление vLLM если есть security/bug fixes. Проверка cloud GPU costs (spot ВМ).

РитмMONTHLY
Manager + Engineer: capacity review

Cost per token анализ. Нужна ли другая модель или другая квантизация. GPU capacity plan на следующий месяц. Есть ли смысл переходить на более новое железо.

Действия менеджера — конкретно

Что делает Manager (не инженер)
Manager
  • Определить SLA заранее: «TTFT P99 не более 2 сек при 50 concurrent users» — конкретное требование, не «должно быть быстро»
  • Выбор модели — бизнес-решение: 7B vs 70B — это трейдофф стоимость/качество, который должен принять менеджер, не инженер в одиночку
  • GPU бюджет: on-prem GPU — капитальные расходы с длинным горизонтом. Cloud GPU — операционные, гибкие. Принять решение об балансе
  • Защитить время на тюнинг: первый запуск занимает 20% времени, следующие 80% — стабилизация и оптимизация
  • Не требовать одну модель на все задачи: routing между small/large моделями по сложности задачи — стандартный cost optimization подход
  • Знать cost per token: это бизнес-метрика. Оптимизация infrastructure должна измеряться в этих единицах

Действия инженера — конкретно

Что делает ML/Infra Engineer
Engineer
  • Запустить vLLM с --enable-prefix-caching --enable-chunked-prefill — это всегда включать
  • Benchmark квантизации: запустить lm-eval-harness на AWQ и FP16 версиях выбранной модели на реальных промптах
  • Нагрузочное тестирование с locust или wrk2: проверить TTFT P99 при 10/50/100 concurrent users
  • Для multi-node: протестировать сетевую пропускную способность между нодами перед деплоем (iperf3, bandwidth ≥ 25Gbps для TP)
  • Пинить версию vLLM Docker image — никогда не использовать :latest
  • Настроить graceful shutdown: terminationGracePeriodSeconds: 300 (5 мин для завершения активных генераций)
  • Runbook: задокументировать что делать при OOM, при Ray node failure, при model load failure

// 10

Чеклисты

Pre-deployment (Engineer)

Post-deployment benchmark (Engineer)

Manager: принятые решения до старта

Ongoing (Engineer, еженедельно)

Самый быстрый path to production: одна ВМ → vLLM + Docker → Prometheus → нагрузочный тест → зафиксировать метрики. Только после этого добавлять Ray, K8s, autoscaling. Сложность должна следовать за реальной нагрузкой, а не предшествовать ей.