Vllm

Материал из Мои проекты

Задача: Работа Ollama в связке с LightRAG оказалась очень медленной. Настроить vllm.

В VM проброшено

  • RTX3090 24GB - 2 штуки

Настроим все в Docker Compose

Реализация.

В целях оптимизации было принято решение embed модель bge-m3 запускать на CPU (она не требовательна к ресурсам), а bge-reranker-v2-m3 и основную модель Qwen3-30B-A3B-GPTQ-Int4 на двух видеокартах. Qwen3-30B-A3B-GPTQ-Int4 - это MOE модель, с квантизацией GPTQ 4-bit. Была выбрана с учетом того, чтобы влезла в две видеокарты с максимально возможным контекстом (max model len 40960). Забегая вперед, вот что из этого получилось.

# nvidia-smi 
Fri Apr 24 11:00:24 2026       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.126.20             Driver Version: 580.126.20     CUDA Version: 13.0     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3090        On  |   00000000:01:00.0 Off |                  N/A |
| 34%   37C    P8             24W /  350W |   23349MiB /  24576MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA GeForce RTX 3090        On  |   00000000:03:00.0 Off |                  N/A |
|  0%   42C    P8             23W /  350W |   23349MiB /  24576MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A           36822      C   VLLM::Worker_TP0                       1662MiB |
|    0   N/A  N/A           36832      C   VLLM::Worker_TP0                      21672MiB |
|    1   N/A  N/A           36823      C   VLLM::Worker_TP1                       1662MiB |
|    1   N/A  N/A           37138      C   VLLM::Worker_TP1                      21672MiB |
+-----------------------------------------------------------------------------------------+

Создать папку проекта и перейти в нее. Создать директорию для моделей.

$ mkdir vllm
$ cd vllm
$ mkdir models

Активировать виртуальное окружение

$ source ../patents/bin/activate

Скачать модели локально, это нужно, чтобы контейнеры стартовали быстрее

$ pip install -U "huggingface_hub[cli]"
$ hf download BAAI/bge-m3 --local-dir ./models/bge-m3
$ hf download BAAI/bge-reranker-v2-m3 --local-dir ./models/bge-reranker-v2-m3
$ hf download Qwen/Qwen3-30B-A3B-GPTQ-Int4 --local-dir ./models/Qwen3-30B-A3B-GPTQ-Int4

Вот содержимое docker-compose.yml

services:
  vllm-embed:
    image: vllm/vllm-openai-cpu:latest
    container_name: vllm-embed
# Права для оптимизации NUMA
    cap_add:
      - SYS_NICE
      - SYS_ADMIN
# Shared memory для стабильности PyTorch/vLLM
    shm_size: '2gb'
# Лимит памяти контейнера (запас под ОС + модель + кэш)
    mem_limit: 24g
    ports:
      - "8001:8000"
    environment:
# Отключаем сетевые проверки, работаем строго локально
      - TRANSFORMERS_OFFLINE=1
      - HF_HUB_OFFLINE=1
# ~12 ГБ под KV-кэш
      - VLLM_CPU_KVCACHE_SPACE=12000
    env_file: .env
    volumes:
# Монтируем локальную модель (только для чтения)
      - ./models/bge-m3:/app/models/bge-m3:ro
    command: >
      /app/models/bge-m3
      --dtype float32
      --host 0.0.0.0
      --port 8000
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
      interval: 5s
      timeout: 3s
      retries: 120
      start_period: 10s
    networks:
      - localai_default
    restart: unless-stopped

  vllm-rerank:
    image: vllm/vllm-openai:latest
    container_name: vllm-rerank
# Shared memory для стабильности PyTorch/vLLM
    shm_size: '1gb'
# Лимит памяти контейнера (запас под ОС + модель + кэш)
    mem_limit: 8g
    ports:
      - "8003:8000"
    environment:
# Отключаем сетевые проверки, работаем строго локально
      - VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS=1
      - OMP_NUM_THREADS=4
      - MKL_NUM_THREADS=4
      - TRANSFORMERS_OFFLINE=1
      - HF_HUB_OFFLINE=1
    env_file: .env
    volumes:
# Монтируем локальную модель (только для чтения)
      - ./models/bge-reranker-v2-m3:/app/models/bge-reranker-v2-m3:ro
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
      interval: 5s
      timeout: 3s
      retries: 120
      start_period: 10s
    networks:
      - localai_default
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ['0','1']
              capabilities: [gpu]
    restart: unless-stopped
    command: >
      /app/models/bge-reranker-v2-m3
      --tensor-parallel-size "2"
      --gpu-memory-utilization "0.1"

  vllm-qwen3-30b:
    image: vllm/vllm-openai:latest
    container_name: vllm-qwen3-30b
    environment:
      - VLLM_MEMORY_PROFILER_ESTIMATE_CUDAGRAPHS=1
    volumes:
      - ./models/Qwen3-30B-A3B-GPTQ-Int4:/app/models/Qwen3-30B-A3B-GPTQ-Int4:ro
    ports:
      - "8002:8000"
    ipc: host
    shm_size: 40g
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
      interval: 5s
      timeout: 3s
      retries: 120
      start_period: 10s
    networks:
      - localai_default
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ['0', '1']
              capabilities: [gpu]
    restart: unless-stopped
    command: >
      /app/models/Qwen3-30B-A3B-GPTQ-Int4
      --tensor-parallel-size "2"
      --dtype auto
      --quantization gptq_marlin
      --gpu-memory-utilization "0.90"
      --kv-cache-dtype auto
      --enable-prefix-caching
      --trust-remote-code
networks:
  localai_default:
    external: true
    name: localai_default

Содержимое .env

VLLM_API_KEY=sk-vllm-$(openssl rand -hex 16)

Настройка подключения к OpenWebUI

2026-04-24 15-15-03.png

Пример лога работы. Запрос из OpenWebUI через подключенный фильтр к LightRAG.

Как звали сына Анны от Каренина?

Ответ

Анна Каренина
Thought for 1 seconds
Сын Анны Карениной от её мужа, князя Алексея Александровича Каренина, назывался Сергей Алексеевич Каренин (часто именуется Серёжей).

В романе Льва Толстого «Анна Каренина» Сергей является важным персонажем, символизирующим семейные узы и социальные обязательства, которые конфликтуют с эмоциональными и моральными выборами Анны. Его присутствие подчёркивает трагедию её жизни, связанную с браком и любовью.

Источники:

[4] part06_chapter019.md
[5] part06_chapter021.md
[10] part01_chapter033.md

Лог

vllm-qwen3-30b  | (APIServer pid=1) INFO 04-24 11:18:36 [loggers.py:259] Engine 000: Avg prompt throughput: 61.7 tokens/s, Avg generation throughput: 122.9 tokens/s, Running: 1 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.8%, Prefix cache hit rate: 0.0%
vllm-qwen3-30b  | (APIServer pid=1) INFO:     172.18.0.14:59878 - "POST /v1/chat/completions HTTP/1.1" 200 OK
vllm-embed      | (APIServer pid=1) INFO:     172.18.0.14:39136 - "POST /v1/embeddings HTTP/1.1" 200 OK
vllm-rerank     | (APIServer pid=1) WARNING 04-24 11:18:37 [input_processor.py:235] Passing raw prompts to InputProcessor is deprecated and will be removed in v0.18. You should instead pass the outputs of Renderer.render_cmpl() or Renderer.render_chat().
vllm-embed      | (APIServer pid=1) INFO 04-24 11:18:43 [loggers.py:259] Engine 000: Avg prompt throughput: 4.4 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
vllm-rerank     | (APIServer pid=1) INFO:     172.18.0.14:51936 - "POST /rerank HTTP/1.1" 200 OK
vllm-qwen3-30b  | (APIServer pid=1) INFO 04-24 11:18:46 [loggers.py:259] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 2.6 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
vllm-rerank     | (APIServer pid=1) INFO 04-24 11:18:46 [loggers.py:259] Engine 000: Avg prompt throughput: 13141.3 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
vllm-embed      | (APIServer pid=1) INFO 04-24 11:18:53 [loggers.py:259] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
vllm-qwen3-30b  | (APIServer pid=1) INFO 04-24 11:18:56 [loggers.py:259] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 1 reqs, Waiting: 0 reqs, GPU KV cache usage: 13.0%, Prefix cache hit rate: 0.0%
vllm-rerank     | (APIServer pid=1) INFO 04-24 11:18:56 [loggers.py:259] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
vllm-qwen3-30b  | (APIServer pid=1) INFO:     172.18.0.14:39648 - "POST /v1/chat/completions HTTP/1.1" 200 OK
vllm-qwen3-30b  | (APIServer pid=1) INFO:     172.18.0.8:42514 - "POST /v1/chat/completions HTTP/1.1" 200 OK
vllm-qwen3-30b  | (APIServer pid=1) INFO 04-24 11:19:06 [loggers.py:259] Engine 000: Avg prompt throughput: 3464.2 tokens/s, Avg generation throughput: 76.1 tokens/s, Running: 1 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.4%, Prefix cache hit rate: 0.0%

Запрос в среднем отрабатывает в течении минуты.