LOOMA / ДОКУМЕНТАЦИЯ
Развёртывание embed-сервера
Embed-сервер переносит расчёт визуальных эмбеддингов на Linux-компьютер с NVIDIA GPU. Настольное приложение отправляет ему документ, получает векторы и миниатюры, а библиотеку, OCR, текстовый поиск и индексы хранит у себя. При визуальном поиске текст запроса также отправляется серверу. Без внешнего сервера приложение может использовать локальную модель.
Это руководство подходит и для первой установки, и для обновления через deploy-embed-server.sh. Скрипт копирует код; пакеты устанавливаете и процесс перезапускаете вы.
Что подготовить#
- Linux x64, NVIDIA GPU с рабочим драйвером (
nvidia-smi). - Python 3.11 с модулем venv, Git, доступ в интернет для пакетов и весов.
- Место для Python/CUDA, выбранных моделей, временных документов и результатов. Универсального минимума VRAM нет: он зависит от модели, страницы и размера порции.
- SSH-доступ и
rsyncна обеих машинах. Деплой выполняется из macOS/Linux или WSL.
В примерах 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
В Настройки → Модель эмбеддинга → Внешний сервис:
- Включите внешний сервис.
- Укажите
http://127.0.0.1:18766и API-ключ. - Загрузите список моделей, выберите модель и сохраните настройки.
- Запустите индексацию небольшого документа и проверьте поиск.
Для прямого подключения в доверенной сети используйте 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. Не запускайте ручной процесс одновременно со службой на том же порту.
Обновление существующего сервера#
- Приостановите индексацию в приложении и дождитесь текущей порции.
- На сервере:
sudo systemctl stop pdfsearch-embed(или остановите ручной процесс). - На компьютере с исходниками:
git pull --ff-only, затем повторите./deploy-embed-server.sh user@gpu-host /home/user/pdfsearch-embed. - На сервере обновите зависимости и запустите службу:
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 не изменяется.
Диагностика#
- Порт ещё закрыт: проверьте загрузку моделей в
journalctl. - CUDA unavailable: проверьте драйвер, CUDA-сборку Torch и выбранную карту.
- CUDA out of memory: уменьшите порцию, проверьте другие процессы; перезапуск освобождает модели, удерживаемые сервером.
- 401/403: проверьте ключ и заголовок
Authorization: Bearer …. - mm_token_type_ids missing: обновите код и зависимости вместе, затем перезапустите сервер. Не правьте файлы в кеше Hugging Face вручную.
- После деплоя всё по-старому: deploy не перезапускает процесс. Проверьте
WorkingDirectoryслужбы и её перезапуск.
Живой справочник API доступен на /docs, схема — /openapi.json. Не публикуйте управляющие endpoints наружу без защиты.