В прошлой статье я описывал как построить сетевую часть самодержавного сервера, пора принести в него что-то отдаленно разумное. Это руководство описывает весь процесс: от подготовки хоста Proxmox и настройки LXC-контейнера до поиска, конвертации и запуска embedding-моделей (на примере BAAI/bge-large-en-v1.5) с использованием Intel GPU для работы модели. Но будет легко запустить не одну модель или полноценного чатбота на этой основе. Главное, что будет ясно как использовать даже простое имеющееся железо домашнего сервера для этого.


Небольшое отступление по поводу того, что у нас получилось после прошлой статьи:

  1. Есть Asus NUC у которого процессор двенадцатого поколения Intel и Intel Xe графикой, NPU и 12 ядрами CPU. Встройка работает с ОЗУ, а значит медленно, но верно сможет работать даже с приличного размера моделями, но все проверять надо, пока, первый заход.

  2. Сетевая инфраструктура, которая позволяет нам поднимать в локальной сети за мостом services, сервисы, которые мы можем легко выставить в интернет через Caddy реверс-прокси.

  3. Лично у меня на этот сервер переехал мой инстанс Mastodon. Содержать его у хостера было не дешево.

  4. Помимо прочего я распилил изолированный мост services на набор отдельных VLAN для групп сервисов что-бы изолировать их дополнительно, теперь OPNSense настоящий шлюз между этими сетями. Включил на OPNSense такую штуку как Suricata, которая показывает когда сервисы сканируют автоботы на предмет открытых уязвимостей, не сказать еще хужей. Если бы самодержавные хостеры знали сколько их сканят, они бы беспокоились о безопасности побольше, но о безопасности в другой раз.

Чего мы хотим:

  1. Счастья.

  2. Пробросить Intel GPU из Proxmox хоста внутрь LXC контейнера, а там и внутрь Docker контейнера. Вложенность такая потому, что запуск среды обработки неронных моделей без Docker это довольно сложное мероприятие.

  3. Запустить LXC контейнер с OpenVINO models server (OVMS), который будет движком, обеспечивающим embedding или inference, зависит от наших потребностей.

  4. В принципе хотим еще и WebUI на это все натянуть, но это за рамками статьи потому, что мне это не нужно и сделаь это просто, так как OVMS поддерживает самые разные распространенные API, например от OpenAI, с которыми работает любая WebUI. Это в его документации описано довольно ясно.

  5. Получить возможность сделать curl запрос к нейронке и получить embedding, что мне в данном случае и нужно, так как хочется построить свой RAG и давать к нему доступ всяким нейронкам в виде MCP, если вы понимаете о чем я.

Штош, хватит отступлений, поехали. Напомню только, что если что-то не ясно, спросите нейронку, они отлично пояснят.

Шаг 0: Настройка Proxmox и проброс GPU в LXC

Есть масса статей на эту тему, но как руками отредактировать конфиги LXC контейнеров, на деле все можно сделать в два клика в UI Proxmox, если знать что делать и как.

1. Установка драйверов Intel на хост Proxmox

Обратите внимание, что установка драйверов на хост это действие противоположное пробросу GPU в виртуалки, вполне вероятно это несовместимые подходы в рамках одного хоста. Подробности можно посмотреть тут и тут

Подключитесь к хосту Proxmox по SSH и выполните следующие команды:

Команды
# Установка зависимостей
apt-get update && apt-get install -y wget gpg

# Добавление ключа репозитория Intel
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \
  gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg

# Добавление репозитория Intel GPU, я ставил сразу noble, но вероятно можно bookworm.
cat > /etc/apt/sources.list.d/intel-gpu.list << 'EOF'
deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu noble client
EOF

# Обновление списка пакетов и установка драйверов
apt-get update
apt-get install -y \
  intel-opencl-icd \
  intel-media-va-driver-non-free \
  ocl-icd-libopencl1 \
  clinfo \
  intel-gpu-tools

Проверьте, что драйвер загружен, возможно нужно будет reboot Proxmox хоста:

Команды
clinfo

Увидите свой GPU в списке.

2. Сбор необходимой информации

На хосте Proxmox:

Проверьте список устройств GPU, именно их нужно будет потом добавлять, у вас будут свои вероятно.

Команды
root@pve:~# ls /dev/dri
by-path  card1	renderD128

Узнайте GID группы render (запишите это число)

root@pve:~# stat -c '%g' /dev/dri/renderD128
993

Внутри LXC контейнера:

Для простоты нам нужен контейнер с ubuntu 24.04, под него вся среда у Intel заточена. При этои мы будем использовать возможности Intel Xe GPU и легко то же самое сделать с CPU или даже обоими. Просто потому, что у меня эта встройка есть на сервере и ее для моих задач достаточно. Но, конечно примерно таким же образом можно настроить и другие GPU, под Nvidia так вообще есть полные подробные гайды. Использо��ать будем OpenVINO models server, подробности: тут,тут,тут,тут,тут,тут,тут,тут,тут,тут

Я привел серию статей включая статьи про ollama что бы было ясно, что можно ollama сделать фронтендом для интеловских поделок, но я не стал, так как у intel есть свой собственный сервер, который поддерживает API доступа по http и нормально работает без дополнительных прослоек. Правда прослойки конечно могут делать что-то полезное типа конвертации моделей, но мне пойдет и так.

Команды
# Узнайте UID вашего пользователя внутри LXC (запишите это число)
id -u

3. Настройка проброса GPU через веб-интерфейс Proxmox

  1. В веб-интерфейсе Proxmox выберите ваш LXC-контейнер

  2. Откройте вкладку «Ресурсы» (Resources)

  3. Нажмите «Добавить» (Add)«Проброс устройства» (Device Passthrough). Особо обратите внимание на то, что Device Passthrough доступен только если вы зашли в WebUI под пользователем root.

  4. Добавьте устройство /dev/dri/renderD128, в расширенных настройках (advanced галка) нужно задать GID от группы render на хосте Proxmox (у меня 993), который мы ранее достали и UID пользователя в LXC контейнере, которому надо дать доступ (у меня 1000, это тот, что записывали). Так же можно указать права доступа, но по умолчанию они заданы и так достаточные, можно не трогать.

  5. Повторите для устройства /dev/dri/card1

4. Отключение AppArmor для контейнера

Недавний баг в Proxmox не дает использовать вложенные docker контейнеры внутри LXC, поправим. Но может его исправят, уже патч был когда я писал статью. Так что если не видите ошибок при старте docker контейнера внутри LXC контейнера, то не нужно. На хосте Proxmox выполните:

Команды
# Замените 100 на ID вашего контейнера
nano /etc/pve/lxc/${lxc_container_id}.conf

Добавьте в конец файла:

Команды
lxc.apparmor.profile: unconfined
lxc.mount.entry: /dev/null sys/module/apparmor/parameters/enabled none bind 0 0

Так будет примерно выглядеть:

Команды
arch: amd64
cores: 8
dev0: /dev/dri/card1,gid=993,uid=1000
dev1: /dev/dri/renderD128,gid=993,uid=1000
features: nesting=1
hostname: ubuntu.24.04
memory: 16768
nameserver: 10.0.40.1
net0: name=eth0,bridge=services,hwaddr=BC:24:11:CD:8A:8F,ip=dhcp,tag=40,type=veth
onboot: 1
ostype: ubuntu
rootfs: local-btrfs:107/vm-107-disk-0.raw,mountoptions=discard,size=64G
swap: 0
unprivileged: 1
lxc.apparmor.profile: unconfined
lxc.mount.entry: /dev/null sys/module/apparmor/parameters/enabled none bind 0 0

Сохраните файл и перезапустите контейнер через веб-интерфейс или pct stop ID/pct start ID. Обратите внимание, что контейнер у меня настроен так, что он работает внутри VLAN, что сделано в моей домашней инфраструктуре и описано тут, вернее написано, что хорошо бы сделать.

5. Установка драйверов в LXC-контейнере

Войдите в консоль LXC, в моей инфраструктуре нет доступа по ssh снаружи к контейнерам, так что войти можно:

  1. Web console

  2. pct enter ID на хосте Proxmox куда по ssh из внутренней сети можно зайти

  3. или ssh если настроено

Команды
# Установка зависимостей
sudo apt-get update && sudo apt-get upgrade
sudo apt-get install -y wget gpg mc jq curl docker-compose-v2 tree

# Добавление ключа репозитория Intel
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \
  sudo gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg

# Добавление репозитория (для Ubuntu 24.04 'noble')
# Измените 'noble' на кодовое имя вашего дистрибутива, если необходимо, но рекомендую именно этот
cat > /tmp/intel-gpu.list << 'EOF'
deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu noble client
EOF
sudo mv /tmp/intel-gpu.list /etc/apt/sources.list.d/intel-gpu.list

# Установка драйверов и утилит
sudo apt-get update
sudo apt-get install -y \
  intel-igc-cm \
  intel-opencl-icd \
  intel-media-va-driver-non-free \
  ocl-icd-libopencl1 \
  clinfo \
  intel-gpu-tools

# Добавление пользователя в группы video и render
sudo usermod -aG video,render $USER
sudo usermod -aG docker $USER
# Применение изменений для текущей сессии
newgrp docker
newgrp render
newgrp video

Проверьте доступ к GPU:

Команды
clinfo

В выводе будет название вашей видеокарты, у меня так:

Команды
i3draven@ubuntu:~$ clinfo |tail -n 10
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM)  No devices found in platform
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL)  Success (1)
    Platform Name                                 Intel(R) OpenCL Graphics
    Device Name                                   Intel(R) Iris(R) Xe Graphics

ICD loader properties
  ICD loader Name                                 OpenCL ICD Loader
  ICD loader Vendor                               OCL Icd free software
  ICD loader Version                              2.3.2
  ICD loader Profile                              OpenCL 3.0

Все, проброс GPU из Proxmox хоста в LXC контейнер готов!

Шаг 1: Развертывание OpenVINO Model Server

Это как раз сервер, который поддерживает API для доступа к инференсу и эмбеддингам. Сам процесс будет из нескольких этапов:

  1. Скачать модель

  2. Конвертировать ее в формат, понятный OpenVINO, в процессе можно квантизовать и оптимизировать. Нужно отметить, что есть и готовые модели, уже в формате openvino их конвертировать не нужно, но выбор не велик.

  3. Развернуть сервер с нужной моделью

  4. PROFIT

1: Поиск моделей для конвертации

Все следующие команды выполняются внутри LXC-контейнера. Для работы мне нужны будут embedding модели, то есть те, которые строят "вектора смысла" для текста. Причем желательно с встроенным токенизатором что бы не возиться с этим отдельно. Но сервер поддерживает и LLM модели, что в документации описано и так хорошо, не стану расписывать, LLM проще.

Найдите подходящие embedding-модели на Hugging Face:

Команды
curl -s "https://huggingface.co/api/models?search=embedding" | \
  jq -r '.models[] | "\(.id) - \(.downloads) загрузок"'

Эта команда выведет список моделей с количеством загрузок. Выберите нужную модель, например, BAAI/bge-large-en-v1.5. Так же есть инструмент для скачивания моделей тут, можно использовать и его.

Помимо прочего OVMS умеет и сам качать модели вот тут подробности и даже сразу же сам их конвертировать, что описано тут

Шаг 2: Подготовка и конвертация модели

1. Создание рабочей директории

Команды
# Создайте папку для работы
mkdir -p ~/ovms-embeddings
cd ~/ovms-embeddings

# Создайте папку для моделей
mkdir -p ./models

2. Конвертация модели в формат OpenVINO

Тут есть ряд проблем. Дело в том, что если запустить Intel контейнер в режиме --pull то есть, скачивать модель и потом автоматически конвертировать, то он скачает и конвертирует, но там не будет токенизатор конвертироваться (параметр стоит --disable-convert-tokenizer), не знаю зачем они эту граблю положили туда. Потому мы могли бы скачать и конвертировать как описано в документации:

Команды
docker run --device /dev/dri --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1) --user $(id -u):$(id -g) --rm -v $(pwd)/models:/models:rw openvino/model_server:latest-py --pull --source_model "BAAI/bge-large-en-v1.5" --model_repository_path /models --model_name bge-large-en-v1.5 --target_device GPU --task embeddings --weight-format int8 --log_level DEBUG --overwrite_models --num_streams 8

Но запустим все это напрямую вызвав optimum-cli, выглядит так:

Команды
docker run --device /dev/dri --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1)   --user $(id -u):$(id -g) --rm   -v $(pwd)/models:/models   --entrypoint /usr/local/bin/optimum-cli   openvino/model_server:latest-py   export openvino   --model BAAI/bge-large-en-v1.5   --weight-format int8   --trust-remote-code   --num-samples 8   --library sentence_transformers   --task feature-extraction   ./models/BAAI/bge-large-en-v1.5

Если вдруг будут проблемы и я где то не углядел, а первая команда из докунметации скачала и закэшировала модель, потому вторая ее может сразу не качая использовать, то просто выполните обе команды по очереди. Но на данный момент я думаю второй достаточно для всего.
Мы просто напрямую запускаем optimim-cli с нужными параметрами. Хочу отдельно отметить, что для конвертации используется optimum-cli, эту штуку не плохо бы посмотреть подробнее так как она позволяет подогнать модели под свое железо и оптимизировать их. Есть вагон параметров. Вот полный вывод команд с структурой папок:

Команды
i3draven@ubuntu:~$ cd ./ovms-embeddings/
i3draven@ubuntu:~/ovms-embeddings$ ls
models
i3draven@ubuntu:~/ovms-embeddings$ docker run --device /dev/dri --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1) --user $(id -u):$(id -g) --rm -v $(pwd)/models:/models:rw openvino/model_server:latest-py --pull --source_model "BAAI/bge-large-en-v1.5" --model_repository_path /models --model_name bge-large-en-v1.5 --target_device GPU --task embeddings --weight-format int8 --log_level DEBUG --overwrite_models --num_streams 8
Unable to find image 'openvino/model_server:latest-py' locally
latest-py: Pulling from openvino/model_server
baa9e71a063a: Pull complete 
a76d3e698922: Pull complete 
5bdd5c6068df: Pull complete 
e1d63ab00fa2: Pull complete 
97f5e74b6399: Pull complete 
9cd7a4880448: Pull complete 
f2fd7d158b30: Pull complete 
5774c385c156: Pull complete 
0864fefc1d57: Pull complete 
1a83f47c7fa9: Pull complete 
16efed5f6d0e: Pull complete 
47a75649fb3d: Pull complete 
21b1671afd79: Pull complete 
912688daea51: Pull complete 
94b691fcc499: Pull complete 
Digest: sha256:5431ac5989c3ae548cb8c954f6caf2a2fafa72ab254fbf90ab5db26381ddd9b8
Status: Downloaded newer image for openvino/model_server:latest-py
[2025-11-17 15:37:04.180][1][serving][debug][optimum_export.cpp:144] Optimum-cli executable is present
[2025-11-17 15:37:04.180][1][serving][debug][optimum_export.cpp:180] Executing command: optimum-cli export openvino --disable-convert-tokenizer --task feature-extraction --library sentence_transformers --model BAAI/bge-large-en-v1.5 --trust-remote-code  --weight-format int8 /models/BAAI/bge-large-en-v1.5
/usr/local/lib/python3.12/dist-packages/torch/onnx/_internal/registration.py:162: OnnxExporterWarning: Symbolic function 'aten::scaled_dot_product_attention' already registered for opset 14. Replacing the existing function with new function. This is unexpected. Please report it on https://github.com/pytorch/pytorch/issues.
  warnings.warn(
`SentenceTransformer._target_device` has been deprecated, please use `SentenceTransformer.device` instead.
`SentenceTransformer._target_device` has been deprecated, please use `SentenceTransformer.device` instead.
`loss_type=None` was set in the config but it is unrecognised.Using the default loss: `ForCausalLMLoss`.
Model: BAAI/bge-large-en-v1.5 downloaded to: /models/BAAI/bge-large-en-v1.5
[2025-11-17 15:37:40.150][1][serving][debug][filesystem.cpp:191] Creating file /models/BAAI/bge-large-en-v1.5/graph.pbtxt
Graph: graph.pbtxt created in: /models/BAAI/bge-large-en-v1.5
i3draven@ubuntu:~/ovms-embeddings$ tree .
.
`-- models
    `-- BAAI
        `-- bge-large-en-v1.5
            |-- config.json
            |-- graph.pbtxt
            |-- openvino_model.bin
            |-- openvino_model.xml
            |-- special_tokens_map.json
            |-- tokenizer.json
            |-- tokenizer_config.json
            `-- vocab.txt

4 directories, 8 files
i3draven@ubuntu:~/ovms-embeddings$ docker run --device /dev/dri --group-add=$(stat -c "%g" /dev/dri/render* | head -n 1)   --user $(id -u):$(id -g) --rm   -v $(pwd)/models:/models   --entrypoint /usr/local/bin/optimum-cli   openvino/model_server:latest-py   export openvino   --model BAAI/bge-large-en-v1.5   --weight-format int8   --trust-remote-code   --num-samples 8   --library sentence_transformers   --task feature-extraction   ./models/BAAI/bge-large-en-v1.5
/usr/local/lib/python3.12/dist-packages/torch/onnx/_internal/registration.py:162: OnnxExporterWarning: Symbolic function 'aten::scaled_dot_product_attention' already registered for opset 14. Replacing the existing function with new function. This is unexpected. Please report it on https://github.com/pytorch/pytorch/issues.
  warnings.warn(
`SentenceTransformer._target_device` has been deprecated, please use `SentenceTransformer.device` instead.
`SentenceTransformer._target_device` has been deprecated, please use `SentenceTransformer.device` instead.
`loss_type=None` was set in the config but it is unrecognised.Using the default loss: `ForCausalLMLoss`.
INFO:nncf:Statistics of the bitwidth distribution:
┍━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┑
│ Weight compression mode   │ % all parameters (layers)   │ % ratio-defining parameters (layers)   │
┝━━━━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥
│ int8_asym                 │ 100% (147 / 147)            │ 100% (147 / 147)                       │
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┙
Applying Weight Compression ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% • 0:00:02 • 0:00:00
i3draven@ubuntu:~/ovms-embeddings$ tree .
.
`-- models
    `-- BAAI
        `-- bge-large-en-v1.5
            |-- config.json
            |-- graph.pbtxt
            |-- openvino_detokenizer.bin
            |-- openvino_detokenizer.xml
            |-- openvino_model.bin
            |-- openvino_model.xml
            |-- openvino_tokenizer.bin
            |-- openvino_tokenizer.xml
            |-- special_tokens_map.json
            |-- tokenizer.json
            |-- tokenizer_config.json
            `-- vocab.txt

4 directories, 12 files

Собственно мы добивались появления openvino_detokenizer.bin, openvino_detokenizer.xml когда запускали отдельно конвертацию токенизатора.

Далее просто пример нам это не нужно. Можно сделать конвертацию и полностью из кода или даже токенизатор использовать свой это не то что бы сложно, но предположим, что хотим не возиться. Далее пример вовсе конвертации модели скриптом, эта страшная весчь делает простое действие, качает скрипт, который и конвертирует модель. Только имя модели поменять и параметры конвертации. --weight-format это квантизация, --target_device это собственно под, что затачивать будем, CPU/GPU. Есть гибридные варианты, но я не стал копаться и так мне достаточно. Гибридные, GPU+CPU, описаны тут, так же там описано как использовать NPU от intel, но первые варианты NPU ограниченны относительно возможностей GPU. Работает этот вариант конвертации значительно дольше так как зависимости долго ставит в контейнере. Просто для примера привел.

Команды
docker run --rm \
  --user $(id -u):$(id -g) \
  -v $(pwd)/models:/workspace/models \
  -w /workspace \
  openvino/ubuntu24_dev:latest \
  bash -c "\
    curl -L https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/releases/2025/3/demos/common/export_models/export_model.py -o export_model.py && \
    pip install -r https://raw.githubusercontent.com/openvinotoolkit/model_server/refs/heads/releases/2025/3/demos/common/export_models/requirements.txt && \
    python3 export_model.py embeddings_ov \
      --source_model BAAI/bge-large-en-v1.5 \
      --weight-format fp16 \
      --target_device GPU \
      --config_file_path /workspace/models/config.json \
      --model_repository_path /workspace/models"

После скрипта нужно исправление конфигурации графа. Скрипт экспорта, тот страшный выше в ненужном примере, добавляет параметр NUM_STREAMS, который может вызывать проблемы при работе с GPU. Проблемы можно увидеть в логах сервера при старте и если нужно, можно отредактировать или удалить данный раздел конфига графа вычислений. Это именно конфиг графа вычислений, не конфига сервера:

Команды
# Удалите проблемную строку из graph.pbtxt
sed -i '/plugin_config: \'\'\'{"NUM_STREAMS": 1}\'\'\'/d' \
  ./models/BAAI/bge-large-en-v1.5/graph.pbtxt

Проверьте, что строка удалена:

Команды
# Просмотрите содержимое файла
cat ./models/BAAI/bge-large-en-v1.5/graph.pbtxt

В файле не должно быть упоминания NUM_STREAMS. Редактировать можно с nano/vi чем угодно конечно. Но в случае если вы использовали конвертацию с докером и optimum-cli, это не нужно все, привел для упрощения поиска граблей желающим погрузиться в ручной труд.
Докер в данном случае спасает от установки среды разработки этого всего барахла и там совместить все версии всего так что-бы оно работало ох как не просто. Можете посмотреть отдельно контейнер для разработчика, описано тут. Так же обратите внимание, что мы используем контейнер для конвертации openvino/model_server:latest-py, запускать будем openvino/model_server:latest-gpu, а для разработки вовсе нужен openvino/ubuntu24_dev и там в каждом полная среда настроена.

3. Создание файла конфигурации

Теперь снова то, что нам нужно. Для того что бы сервер нашел модель или модели нужен файл конфигурации:

Команды
i3draven@ubuntu:~/ovms-embeddings$ cat ./models/config.json 
{
    "model_config_list": [{
        "config": {
            "name": "BAAI/bge-large-en-v1.5",
            "base_path": "/models/BAAI/bge-large-en-v1.5",
            "target_device": "GPU"
        }
    }],
    "mediapipe_config_list": [{
        "name": "BAAI/bge-large-en-v1.5",
        "graph_path": "/models/BAAI/bge-large-en-v1.5/graph.pbtxt"
    }]
}

Посмотреть подробности и даже несколько моделей одновременно что бы было, можно тут.
Где-то в логах мелькало, что при конвертации взят только первый слой графа или что-то подобное, но я пока вникать не стал и без того пришлось перелопатить много всего, не уверен даже, что это в итоговый заход попало с этими командами, но, можете повнимательнее посмотреть логи.

4. Проверка результата

Вы должны увидеть папки с моделью, токенизатором и файлом config.json. Примерно такие:

Команды
i3draven@ubuntu:~/ovms-embeddings$ tree .
.
|-- docker-compose.yml <-- # еще сделаем
`-- models
    |-- BAAI
    |   `-- bge-large-en-v1.5
    |       |-- config.json
    |       |-- graph.pbtxt
    |       |-- openvino_detokenizer.bin
    |       |-- openvino_detokenizer.xml
    |       |-- openvino_model.bin
    |       |-- openvino_model.xml
    |       |-- openvino_tokenizer.bin
    |       |-- openvino_tokenizer.xml
    |       |-- special_tokens_map.json
    |       |-- tokenizer.json
    |       |-- tokenizer_config.json
    |       `-- vocab.txt
    `-- config.json

4 directories, 14 files

Шаг 3: Создание конфигурации Docker Compose

1. Создание файла .env

Создайте файл с переменными окружения, используя GID который вы записали в самом начале.

Команды
# Замените 993 GID был уменя, ваш GID группы render с хоста Proxmox будет совпадать с LXC
echo "RENDER_GID=$(stat -c '%g' /dev/dri/renderD128)" > .env
# Замените 1000 на ваш UID пользователя в LXC (если отличается)
echo "YOUR_UID=$(id -u)" >> .env

# Проверьте содержимое файла
cat .env

Вывод должен быть примерно таким:

Команды
RENDER_GID=993
YOUR_UID=1000

2. Создание файла docker-compose.yml

Тут все просто, поднимаем сервер, указываем ему конфиг и порт на котором работать:

Команды
cat > docker-compose.yml << 'EOF'
services:
  bge-large-embeddings:
    image: openvino/model_server:latest-gpu
    container_name: bge-large-embeddings
    user: "${YOUR_UID}:${YOUR_UID}"
    ports:
      - "8001:8000"
    devices:
      - /dev/dri:/dev/dri
    group_add:
      - "${RENDER_GID}"
    volumes:
      - ./models:/models:ro
    command: >
      --config_path /models/config.json
      --rest_port 8000
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
EOF

Шаг 4: Запуск и проверка сервера

1. Запуск сервера

Команды
# Запустите сервер в фоновом режиме
docker compose up -d

2. Мониторинг запуска

Команды
# Просмотр логов контейнера в реальном времени
docker compose logs -f

Дождитесь сообщения о том, что сервер запущен и модель загружена. Обычно это занимает 15-20 секунд. Для выхода из просмотра логов нажмите Ctrl+C.

3. Проверка статуса контейнера

Команды
# Проверьте, что контейнер запущен
docker compose ps

Вы должны увидеть контейнер bge-large-embeddings в статусе Up.

4. Отправка тестового запроса

OVMS поддерживает довольно обширное API, описанное тут и может маскироваться под самые разные сервера. Так можно получить состояние модели:

Команды
i3draven@openvino:~/openvino/big$ curl http://localhost:8001/v1/config
{
"BAAI/bge-large-en-v1.5" : 
{
 "model_version_status": [
  {
   "version": "1",
   "state": "AVAILABLE",
   "status": {
    "error_code": "OK",
    "error_message": "OK"
   }
  }
 ]
}

Так можно получить собственно то, ради чего все затевалось, а именно embedding вектор для заданного текста

Команды
# Отправьте запрос на получение эмбеддинга
curl -X POST http://localhost:8001/v3/embeddings \
  -H "Content-Type: application/json" \
  -d '{
    "model": "BAAI/bge-large-en-v1.5",
    "input": "The entire stack, from Proxmox to OVMS, is fully operational."
  }' | jq

Вы должны получить JSON-ответ с векторным представлением текста, примерно такого вида:

Json
{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "embedding": [0.123, -0.456, 0.789, ...],
      "index": 0
    }
  ],
  "model": "BAAI/bge-large-en-v1.5",
  "usage": {
    "prompt_tokens": 12,
    "total_tokens": 12
  }
}

5. Проверка использования GPU

Можно посмотреть нагрузку на GPU, но запускать нужно на Proxmox хосте, в LXC оно заработать не захотело и я не стал разбираться почему.

Команды
# В отдельном терминале запустите мониторинг GPU
intel_gpu_top

Выше изложена основа для того что бы на своем домашнем сервере завести себе LLM/Embedding модели, которые например будут полезны для тегирования фоточек, просто как чатботы или например для построения RAG системы через MCP для вашего любимого LLM на основе embedding моделей. Позже покажу для чего это мне нужно, наверное, как кобычно по настроению. Выдался просто выходной внеочередной.

Комментарии (0)