LOOMA / ДОКУМЕНТАЦИЯ

Развёртывание embed-сервера

Embed-сервер переносит расчёт визуальных эмбеддингов на Linux-компьютер с NVIDIA GPU. Настольное приложение отправляет ему документ, получает векторы и миниатюры, а библиотеку, OCR, текстовый поиск и индексы хранит у себя. При визуальном поиске текст запроса также отправляется серверу. Без внешнего сервера приложение может использовать локальную модель.

Это руководство подходит и для первой установки, и для обновления через deploy-embed-server.sh. Скрипт копирует код; пакеты устанавливаете и процесс перезапускаете вы.

Что подготовить#

В примерах user@gpu-host — ваш SSH-адрес, /home/user/pdfsearch-embed — каталог установки. Замените их своими значениями.

1. Передайте код#

На компьютере с исходниками:

git clone https://github.com/LoomaFloat/looma-search.git
cd looma-search
./deploy-embed-server.sh user@gpu-host /home/user/pdfsearch-embed

Без второго аргумента используется папка pdfsearch-embed в каталоге входа SSH. Поддерживаются алиасы из ~/.ssh/config. Другой порт и ключ:

SSH_PORT=2222 SSH_IDENTITY_FILE="$HOME/.ssh/id_ed25519" \
  ./deploy-embed-server.sh user@gpu-host /home/user/pdfsearch-embed

Скрипт использует одно SSH-соединение. Он сохраняет удалённые ключи, .venv, кеши и административные файлы; не передаёт локальную базу или ключ Anytype. Работающий сервер автоматически не перезапускается. Обновление кода выполняйте после остановки службы, чтобы не смешивать версии в одном процессе.

Альтернатива — клонировать репозиторий прямо на сервер. Тогда используйте путь embed_server/requirements.txt вместо корневого requirements.txt в командах ниже. В результате deploy файл зависимостей лежит в обоих местах.

2. Установите зависимости#

На GPU-сервере:

ssh user@gpu-host
cd /home/user/pdfsearch-embed
nvidia-smi
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

Установите CUDA-сборку PyTorch, совместимую с вашей картой и драйвером. Пример для CUDA 12.6:

python -m pip install torch==2.9.0 torchvision==0.24.0 \
  --index-url https://download.pytorch.org/whl/cu126
python -m pip install -r embed_server/requirements.txt
python -m pip install --no-deps \
  'sauerkrautlm-colpali @ git+https://github.com/VAGOsolutions/sauerkrautlm-colpali@040853262b0ccf6b90864b1ca74cb9f72da1e1de'
python -c 'import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))'

Команда проверки должна показать True и имя GPU. Подберите другую CUDA-сборку по официальной таблице PyTorch, если cu126 не подходит. Не устанавливайте CPU-only зависимости настольной сборки на GPU-сервер.

Проект использует Transformers 5.14.1. Sauerkraut устанавливается отдельно с --no-deps, чтобы его метаданные не заменили согласованную версию Transformers. flash-attn для текущего каталога не требуется.

3. Скачайте модели#

Активный каталог: ColQwen3 2B (colqwen3_2b) и EVIE 4.5B (evie_4_5b). Начать можно с одной модели:

.venv/bin/python -m embed_server.download_models --list
.venv/bin/python -m embed_server.download_models --models colqwen3_2b

Без --models скачиваются все активные модели. --refresh проверяет обновления на Hugging Face. Кеш по умолчанию — ~/.cache/huggingface/hub; изменить его можно через HF_HOME или HF_HUB_CACHE. Скачивайте и запускайте сервер от одного пользователя с одинаковыми переменными кеша, без sudo.

Загрузка весов на диск не означает загрузку в видеопамять. Первый запрос выбранной модели всё ещё может занять время.

4. Проверьте ручной запуск#

Безопасный вариант для подключения через SSH-туннель:

EMBED_HOST=127.0.0.1 EMBED_DOWNLOAD_MODELS=colqwen3_2b \
  bash embed_server/start.sh --gpu 0

start.sh проверяет CUDA, создаёт случайный ключ при отсутствии файла ключей, проверяет/скачивает выбранные веса и только после этого открывает API. При повторном запуске завершённые загрузки проверяются по локальным файлам. Без EMBED_DOWNLOAD_MODELS проверяется весь активный каталог. Ограничение предварительной загрузки не запрещает другие модели в API.

Во втором терминале сервера:

curl --fail http://127.0.0.1:8766/health

Ответ должен содержать status: ok и document_jobs_version: 1. Посмотрите API-ключ локально на сервере и скопируйте его в настройки приложения:

cd /home/user/pdfsearch-embed
.venv/bin/python -c 'import json; print(next(iter(json.load(open("embed_server_keys.json")))))'

Не публикуйте вывод этой команды. start.sh создаёт файл с правами 600. Не заменяйте его пустым или повреждённым JSON: текущая реализация при пустом/нечитаемом наборе ключей допускает запросы без авторизации. /health доступен без ключа.

5. Подключите приложение#

На компьютере с приложением откройте туннель и оставьте терминал работающим:

ssh -N -L 18766:127.0.0.1:8766 user@gpu-host

В Настройки → Модель эмбеддинга → Внешний сервис:

  1. Включите внешний сервис.
  2. Укажите http://127.0.0.1:18766 и API-ключ.
  3. Загрузите список моделей, выберите модель и сохраните настройки.
  4. Запустите индексацию небольшого документа и проверьте поиск.

Для прямого подключения в доверенной сети используйте EMBED_HOST=0.0.0.0 и адрес http://gpu-host:8766. По умолчанию start.sh слушает 0.0.0.0. Для соединения через интернет используйте туннель/VPN или HTTPS-прокси с ограничением доступа: исходники и ключ не должны идти через публичный HTTP. При прокси учитывайте размер PDF и время загрузки.

6. Запуск службой systemd#

Остановите ручной процесс (Ctrl+C). Создайте /etc/systemd/system/pdfsearch-embed.service, заменив пользователя и пути:

[Unit]
Description=Looma Search embeddings
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=user
WorkingDirectory=/home/user/pdfsearch-embed
Environment=EMBED_HOST=127.0.0.1
Environment=EMBED_PORT=8766
Environment=EMBED_GPU=0
Environment=EMBED_GPU_BATCH_SIZE=4
Environment=EMBED_DOWNLOAD_MODELS=colqwen3_2b,evie_4_5b
Environment=EMBED_SERVER_KEYS_FILE=/home/user/pdfsearch-embed/embed_server_keys.json
ExecStart=/bin/bash /home/user/pdfsearch-embed/embed_server/start.sh
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now pdfsearch-embed
journalctl -u pdfsearch-embed -f

systemctl может показать запущенную службу, пока ещё скачиваются веса. Готовность API проверяйте через /health. Не запускайте ручной процесс одновременно со службой на том же порту.

Обновление существующего сервера#

  1. Приостановите индексацию в приложении и дождитесь текущей порции.
  2. На сервере: sudo systemctl stop pdfsearch-embed (или остановите ручной процесс).
  3. На компьютере с исходниками: git pull --ff-only, затем повторите ./deploy-embed-server.sh user@gpu-host /home/user/pdfsearch-embed.
  4. На сервере обновите зависимости и запустите службу:
cd /home/user/pdfsearch-embed
.venv/bin/python -m pip install -r embed_server/requirements.txt
.venv/bin/python -m pip install --no-deps \
  'sauerkrautlm-colpali @ git+https://github.com/VAGOsolutions/sauerkrautlm-colpali@040853262b0ccf6b90864b1ca74cb9f72da1e1de'
sudo systemctl start pdfsearch-embed
journalctl -u pdfsearch-embed -n 80 --no-pager
curl --fail http://127.0.0.1:8766/health

После готовности возобновите индексацию в приложении. Сохраняйте файл ключей и каталог заданий: продолжение использует тот же ключ. start.sh очищает веса выведенных из каталога моделей; удалите их имена из EMBED_DOWNLOAD_MODELS. Код поддержки Ops сохранён, но модель отсутствует в активном каталоге.

Производительность и настройки#

На GPU выполняется одна операция за раз. Запросы поиска имеют приоритет перед ожидающими порциями индексации; текущая порция завершается. CPU готовит следующие страницы параллельно. Несколько workers uvicorn дублируют модель в памяти — оставьте один.

Переменная По умолчанию Назначение
EMBED_GPU Текущее CUDA-окружение Номер или UUID GPU; --gpu 1 выбирает вторую карту
EMBED_HOST / EMBED_PORT 0.0.0.0 / 8766 Адрес и порт API
EMBED_GPU_BATCH_SIZE 4 Страниц в порции; при нехватке VRAM попробуйте 1
EMBED_RENDER_WORKERS 2 CPU-процессов рендеринга
EMBED_PARALLEL_DOCUMENTS 3 Документов одновременно, от 1 до 8
EMBED_DOWNLOAD_MODELS Все активные модели Имена для предварительной загрузки через запятую
EMBED_SERVER_KEYS_FILE Файл в каталоге установки JSON с API-ключами
EMBED_JOBS_DIR embed_jobs Состояние заданий и временные файлы
EMBED_JOB_TTL_SECONDS 86400 Срок хранения без обращений клиента
EMBED_JOB_RETENTION_GRACE_SECONDS 3600 Когда завершённое задание можно удалить при заполнении лимита; минимум 600 секунд
EMBED_MAX_UPLOAD_BYTES 2147483648 Ограничение размера исходника, 2 GiB

Некоторые модели ограничивают порцию одной страницей. Число «PDF одновременно» в настройках приложения регулирует параллельную отправку, а не число копий модели. В журнале сервера видны времена рендеринга и вычислений. Для выбора GPU: nvidia-smi --query-gpu=index,uuid,name,memory.free --format=csv. Внутри процесса выбранная карта отображается как cuda:0.

Временные файлы и восстановление#

Документ передаётся один раз. Результат порции — ZIP с float32 .npy без pickle, JPEG-миниатюрами и JSON-геометрией. Исходник удаляется после вычисления, ошибки или отмены. Готовые порции удаляются после подтверждения клиента; оставшиеся задания очищаются по TTL. После перезапуска незавершённая обработка продолжается с сохранённой контрольной точки.

Не удаляйте embed_jobs при активной индексации. При нехватке места сначала проверьте размеры кеша моделей и временных заданий. Очень большие страницы ограничиваются бюджетом рендеринга 40 миллионов пикселей; исходный PDF не изменяется.

Диагностика#

Живой справочник API доступен на /docs, схема — /openapi.json. Не публикуйте управляющие endpoints наружу без защиты.

Нашли неточность? Сообщите на GitHub ↗