RAG-синхронизация: git → OpenWebUI knowledge base¶
Автоматическая загрузка markdown-документации из git-репозитория alatyr-infra-kb в OpenWebUI knowledge collection на ragserver для использования локальными AI-агентами.
Дата снимка: 05.08.2026
Развернуто на: ragserver (192.168.1.200)
Источник: GitHub oswold1979/alatyr-infra-kb (private)
Назначение: OpenWebUI knowledge collection alatyr-infra-kb (ID 191ae5b9-2520-492e-b6ee-937646008658)
Быстрая справка¶
| Параметр | Значение |
|---|---|
| Git-репо | git@github-alatyr-kb:oswold1979/alatyr-infra-kb.git |
| Локальный clone | /opt/rag-kb/ (владелец oswold:oswold) |
| Директория скрипта | /opt/rag-sync/ (700, oswold) |
| Скрипт | /opt/rag-sync/sync-to-openwebui.sh |
| State-файл | /opt/rag-sync/state.json |
| Лог | /opt/rag-sync/sync.log |
| Lock-файл | /opt/rag-sync/.lock |
| Файлы окружения | /opt/rag-sync/.env (600) — токен OpenWebUI |
| Аутентификация в GitHub | Deploy key (SSH, ED25519, read-only) |
| Cron | */10 * * * * (каждые 10 минут, user cron oswold + flock) — ✅ 07.08.2026 |
Архитектура¶
┌─────────────────────┐ ┌─────────────────────┐
│ Perplexity chat │ │ GitHub │
│ (пишу файлы) │───push─▶│ alatyr-infra-kb │
└─────────────────────┘ │ (private) │
└──────────┬──────────┘
│ SSH pull
│ (deploy key)
▼
┌─────────────────────────────────────────┐
│ ragserver (192.168.1.200) │
│ │
│ cron: sync-to-openwebui.sh (каждые 5м) │
│ │ │
│ ├─ git pull /opt/rag-kb/ │
│ ├─ diff + hash → state.json │
│ ├─ curl → OpenWebUI API │
│ │ │
│ ▼ │
│ OpenWebUI (Docker :3000) │
│ │ │
│ ├─ POST /api/v1/files/ (upload) │
│ ├─ POST /api/v1/knowledge/ │
│ │ {id}/file/add (attach) │
│ │ │
│ ▼ │
│ Ollama (host systemd :11434) │
│ └─ nomic-embed-text │
│ → 768-dim vectors │
│ │ │
│ ▼ │
│ Qdrant (Docker :6333) │
│ └─ collection open-webui_knowledge │
│ │
└─────────────────────────────────────────┘
Компоненты¶
1. Git-репозиторий и Deploy Key¶
Что: Приватный репо oswold1979/alatyr-infra-kb на GitHub, доступ по SSH через Deploy Key (read-only, привязан к репо).
Как создан:
sudo ssh-keygen -t ed25519 \
-f /home/oswold/.ssh/id_ed25519_alatyr_kb \
-C "ragserver-alatyr-kb-deploy-key" \
-N ""
Публичный ключ добавлен в github.com/oswold1979/alatyr-infra-kb/settings/keys с Allow write access: НЕТ.
SSH-конфиг — ~/.ssh/config пользователя oswold:
# Deploy key для alatyr-infra-kb (read-only)
Host github-alatyr-kb
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_alatyr_kb
IdentitiesOnly yes
URL для клона: git@github-alatyr-kb:oswold1979/alatyr-infra-kb.git (не github.com а псевдоним из config).
Fingerprint нашего deploy key: SHA256:q7olwXJsWFx/FarxezWpdaDkonbLZHdKTLnRnE77lwI
Первый клон:
sudo mkdir -p /opt/rag-kb
sudo chown oswold:oswold /opt/rag-kb
git clone git@github-alatyr-kb:oswold1979/alatyr-infra-kb.git /opt/rag-kb
2. Директория /opt/rag-sync/¶
Права 700, только oswold.
Содержимое:
/opt/rag-sync/
├── .env # OPENWEBUI_API_TOKEN и OPENWEBUI_URL (perms 600)
├── sync-to-openwebui.sh # исполняемый скрипт синхронизации (700)
├── state.json # соответствие файл→file_id→sha256
├── sync.log # лог всех запусков
└── .lock # PID активного запуска (создаётся/удаляется скриптом)
Файл .env:
Токен создан в OpenWebUI → Settings → Account → API Keys → "rag-sync-ragserver".
TODO: скопировать токен также в Vaultwarden как резервную копию (сейчас доступ к Vaultwarden с рабочего компа не работает — офисный провайдер режет TLS handshake).
3. OpenWebUI knowledge collection¶
Имя: alatyr-infra-kb
ID: 191ae5b9-2520-492e-b6ee-937646008658
Создана автоматически скриптом при первом запуске через POST /api/v1/knowledge/create.
Что в неё синхронизируется — все *.md из корня репо, кроме файлов начинающихся с TODO- (потому что они меняются каждый день и засоряют RAG).
Файлов на 05.08.2026: 10
00_INDEX.mdREADME.mdvps-hostkey-vm-mini.mdnginx-vps-configs.mddns-alatyr-service.mdvaultwarden.mdamneziawg-tunnels.mdcertbot.mdragserver-workstation.mdcrm-objects-spec.md
Скрипт sync-to-openwebui.sh¶
Расположение в репо: scripts/sync-to-openwebui.sh (версионируется)
Расположение на ragserver: /opt/rag-sync/sync-to-openwebui.sh (копия, исполняемая)
Логика¶
- Loading
.env— токен и URL - Lock: если существует
.lockи PID жив → выйти с ошибкой (иначе удалить stale lock) git pull --ff-onlyв/opt/rag-kb/- Найти/создать коллекцию
alatyr-infra-kb: GET /api/v1/knowledge/→ поиск по имени- Если нет →
POST /api/v1/knowledge/create - Прогон всех
*.md(кромеTODO-*): - Считать
sha256sum - Сравнить с
state.json - Если новый → upload + attach + запись state
- Если изменился → remove-from-collection + delete-file + upload + attach + update state
- Если не изменился → skip
- Удалённые в репо (были в state, нет в файловой системе) → удалить из коллекции + удалить из state
- Логировать всё в
/opt/rag-sync/sync.log - Summary в конце:
added=N, updated=N, removed=N, skipped=N, errors=N
Обновление скрипта¶
Скрипт лежит в самом git-репозитории (scripts/sync-to-openwebui.sh). Чтобы обновить:
- Правишь в
alatyr-infra-kb/scripts/sync-to-openwebui.sh(например через Perplexity) git pushв GitHub- На ragserver — при следующем запуске скрипт сам делает
git pullи подхватывает новую версию сам себя, но она применится только к следующему запуску (уже запущенный экземпляр работает старой версией) - Скопировать новую версию из
/opt/rag-kb/scripts/в/opt/rag-sync/и сделать исполняемой:
cp /opt/rag-kb/scripts/sync-to-openwebui.sh /opt/rag-sync/
chmod +x /opt/rag-sync/sync-to-openwebui.sh
TODO: автоматизировать это — в самом скрипте вначале проверять диффу между /opt/rag-kb/scripts/sync-to-openwebui.sh и /opt/rag-sync/sync-to-openwebui.sh, при различии — копировать и рестартовать себя. Аккуратно чтобы не зациклиться.
OpenWebUI RAG-стек (детали)¶
Компоненты (все на ragserver)¶
| Компонент | Где живёт | Порт | Роль |
|---|---|---|---|
| OpenWebUI | Docker rag-openwebui |
3000 |
Frontend + API + RAG-логика |
| PostgreSQL | Docker rag-postgres |
5432 |
Метаданные (пользователи, коллекции, файлы) |
| Qdrant | Docker rag-qdrant |
6333 HTTP, 6334 gRPC |
Векторное хранилище |
| Ollama | Host systemd (ollama.service) |
192.168.1.200:11434 |
Сервер моделей (LLM + embeddings) |
Важно: Ollama НЕ в докере — работает как systemd-service на хосте. Слушает на 192.168.1.200:11434, не на localhost. Поэтому curl localhost:11434 из ragserver не сработает — надо использовать 192.168.1.200:11434.
Настройки RAG (env в OpenWebUI)¶
RAG_EMBEDDING_ENGINE=ollama
RAG_EMBEDDING_MODEL=nomic-embed-text:latest
RAG_CHUNK_SIZE=1000 # символов на чанк
RAG_CHUNK_OVERLAP=200 # символов перекрытия
RAG_EMBEDDING_BATCH_SIZE=4 # ⚠ очень мало! ускоряется увеличением
RAG_TOP_K=5 # найти топ-5 при поиске
RAG_RERANKING_MODEL= # без реранкинга
VECTOR_DB=qdrant
QDRANT_URI=http://qdrant:6333 # через docker DNS
QDRANT_API_KEY=<хранится в docker-compose>
Модель эмбеддингов¶
nomic-embed-text — 137M параметров, генерирует 768-мерные векторы.
Хорошо работает с русским/английским текстом, но: - Требует Ollama (для загрузки/запуска) - Медленный на CPU без GPU: ~0.5-1 сек на чанк
Векторное хранилище (Qdrant)¶
Одна общая коллекция на все knowledge collections OpenWebUI:
open-webui_knowledge— все векторные точки от всех knowledge collections (не отдельные Qdrant-коллекции)open-webui_files— отдельная коллекция для файлов- Метрика: Cosine
- Размерность: 768 (соответствует nomic-embed-text)
- on_disk: false (векторы в RAM для скорости)
API-ключ Qdrant хранится в env-переменной QDRANT_API_KEY контейнера OpenWebUI и QDRANT__SERVICE__API_KEY контейнера Qdrant.
TODO: ротировать QDRANT_API_KEY (утёк в перплексити-чат 05.08.2026 при отладке).
Производительность¶
Первый синк 05.08.2026 — 10 файлов, ~200 KB, заняло ~9 минут 36 секунд.
Почему медленно¶
Причины:
- Двойная генерация эмбеддингов — OpenWebUI при
upload(POST /api/v1/files/) и потом приattach(POST /api/v1/knowledge/{id}/file/add) индексирует одно и то же дважды. Это баг архитектуры OpenWebUI, не наш. - Ollama на CPU — i3-7100U без GPU, ~0.5-1 сек на чанк для nomic-embed-text
RAG_EMBEDDING_BATCH_SIZE=4— очень маленький batch, слабая параллельностьcrm-objects-spec.md(50 KB) — 63 чанка × 2 захода = ~126 вызовов Ollama = ~2.5 мин на один этот файл
Оценка последующих запусков¶
- Если файлы не изменились — все
skippedв скрипте, синк занимает ~2-5 сек (толькоgit pull+ сравнение sha256) - Если один файл изменился — синк занимает ~30-60 сек (в зависимости от размера файла и количества чанков)
- Полная переиндексация (всё удалить и заново) — ~10 минут
Как ускорить (TODO)¶
По приоритету:
- 🟢 Увеличить
RAG_EMBEDDING_BATCH_SIZEс4до32— ускорит эмбеддинги +50-100% - 🟢 Увеличить
RAG_CHUNK_SIZEс1000до2000— вдвое меньше чанков, но крупнее контекст. Может ухудшить precision, но должно быть OK для документации - 🟡 Сменить
RAG_EMBEDDING_ENGINEсollamaнаsentence_transformers— встроенный движок с модельюall-MiniLM-L6-v2(22 MB, 384-dim). Синк ускорится в 20-30 раз, но модель хуже для русского языка - 🟡 Проверить если можно отключить двойную индексацию через API OpenWebUI (может есть флаг skip_embedding при upload)
- 🔵 Купить GPU для ragserver — ускорит эмбеддинги в 10-50 раз (но нужно ~500W БП и место в корпусе — сейчас i3 U-серии, вряд ли влезет)
Изменения в env — через docker-compose в /opt/rag-platform/docker-compose.yml, потом:
Cron / systemd (планирование запуска)¶
✅ Установлен 07.08.2026 (задача 6)¶
User cron от юзера oswold (не root, не в /etc/cron.d/) — владелец /opt/rag-sync/ всё равно oswold, а user cron проще аудировать через crontab -l.
*/10 * * * * /usr/bin/flock -n /tmp/sync-to-openwebui.lock /opt/rag-sync/sync-to-openwebui.sh 2>&1 | tee -a /opt/rag-sync/cron.log
Разбор:
- */10 — каждые 10 минут (не 5, т.к. первый синк 24 файлов занимает 15 мин, обычный delta-синк 20-30 сек)
- flock -n /tmp/sync-to-openwebui.lock — mutex, чтобы параллельный запуск не попортил state
- Скрипт сам пишет /opt/rag-sync/sync.log — cron.log нужен только для ошибок flock/cron-обёртки
Проверка:
crontab -l # строка на месте
tail -5 /opt/rag-sync/sync.log # последний запуск
tail -5 /opt/rag-sync/cron.log # пусто = ок
Вариант A (альтернатива): cron в /etc/cron.d/¶
Файл /etc/cron.d/rag-sync (требует sudo, мы не выбрали):
# rag-sync — синхронизация alatyr-infra-kb → OpenWebUI каждые 5 минут
*/5 * * * * oswold /opt/rag-sync/sync-to-openwebui.sh >> /opt/rag-sync/sync.log 2>&1
Плюс: - Одна строка - Автоматически запускается при старте системы
Минус: - Cron не отслеживает предыдущий запуск (но у нас есть lockfile)
Вариант B: systemd timer (аккуратнее)¶
/etc/systemd/system/rag-sync.timer:
[Unit]
Description=RAG sync from git
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Persistent=true
[Install]
WantedBy=timers.target
/etc/systemd/system/rag-sync.service:
[Unit]
Description=Sync alatyr-infra-kb to OpenWebUI knowledge base
[Service]
Type=oneshot
User=oswold
ExecStart=/opt/rag-sync/sync-to-openwebui.sh
Активация:
Рекомендую B — systemd timer чище (persistent, лучше логи через journalctl, можно посмотреть next-run через systemctl list-timers).
TODO: установить один из вариантов (после того как сделаем ещё несколько тестов вручную).
Ручной запуск¶
Запустить синк прямо сейчас (не дожидаясь cron):
Посмотреть последний лог:
Проверить state:
Проверить сколько файлов сейчас в OpenWebUI коллекции:
source /opt/rag-sync/.env
curl -sSf -H "Authorization: Bearer $OPENWEBUI_API_TOKEN" \
"$OPENWEBUI_URL/api/v1/knowledge/" | \
jq '.items[] | select(.name=="alatyr-infra-kb") | {id, file_count}'
unset OPENWEBUI_API_TOKEN
Восстановление после сбоя¶
Сценарий 1: скрипт упал во время выполнения¶
Проверить lockfile:
cat /opt/rag-sync/.lock # покажет PID
ps -p $(cat /opt/rag-sync/.lock) 2>/dev/null # проверить живой ли
Если процесс жив — подождать или убить:
Скрипт при следующем запуске сам увидит stale lock и удалит его.
Сценарий 2: OpenWebUI пересоздан / потеряны все файлы¶
Синхронизация "с нуля":
# 1. Очистить state
> /opt/rag-sync/state.json
# 2. Запустить синк — он создаст коллекцию и загрузит все файлы
/opt/rag-sync/sync-to-openwebui.sh
Займёт ~10 минут (полная переиндексация всех файлов).
Сценарий 3: state.json потерян, но файлы в OpenWebUI есть¶
Плохой сценарий — скрипт увидит "новые" файлы и загрузит их дубликатом, а старые останутся.
Решение: сначала удалить старую коллекцию через API, потом запустить синк.
source /opt/rag-sync/.env
COLL_ID=$(curl -sSf -H "Authorization: Bearer $OPENWEBUI_API_TOKEN" \
"$OPENWEBUI_URL/api/v1/knowledge/" | \
jq -r '.items[] | select(.name=="alatyr-infra-kb") | .id')
curl -sSf -X DELETE -H "Authorization: Bearer $OPENWEBUI_API_TOKEN" \
"$OPENWEBUI_URL/api/v1/knowledge/$COLL_ID/delete"
unset OPENWEBUI_API_TOKEN
# Также очистить связанные файлы (получить их из state.json если он ещё есть)
# либо через UI OpenWebUI → Files → удалить *.md
# И только потом:
> /opt/rag-sync/state.json
/opt/rag-sync/sync-to-openwebui.sh
TODO: добавить в скрипт --reset флаг который делает эти операции.
Использование knowledge в OpenWebUI¶
Через UI¶
- Открыть OpenWebUI (
http://192.168.1.200:3000или через VPN) - Создать новый чат
- В поле ввода написать
#— появится список коллекций - Выбрать
#alatyr-infra-kb - Задать вопрос:
OpenWebUI найдёт 5 наиболее релевантных чанков (RAG_TOP_K=5), передаст LLM как контекст, тот ответит.
Через API (для внешних агентов)¶
curl -X POST "http://192.168.1.200:3000/api/chat/completions" \
-H "Authorization: Bearer $OPENWEBUI_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5:7b",
"messages": [{"role":"user","content":"версия nginx"}],
"files": [{"type":"collection","id":"191ae5b9-2520-492e-b6ee-937646008658"}]
}'
TODO: интегрировать с локальными скриптами и CRM — чтобы AI-агент мог использовать эту knowledge для контекстных ответов.
Известные проблемы¶
1. Двойная генерация эмбеддингов при upload+attach¶
Что: OpenWebUI индексирует файл 2 раза — при POST /api/v1/files/ и потом при POST /api/v1/knowledge/{id}/file/add.
Импакт: синк 2x медленнее чем мог бы быть.
Обход: нет (баг архитектуры OpenWebUI). Можно попробовать skip_embedding параметр при upload (не проверял).
TODO: проверить есть ли флаг skip_embedding
2. Ollama на CPU медленная¶
Импакт: 10 файлов индексируются ~10 минут.
Обход: увеличить batch, chunk size, или сменить engine.
TODO: см. раздел "Как ускорить"
3. Nomic-embed-text может быть недоступен для русского¶
Модель nomic-embed-text работает для русского удовлетворительно, но не оптимально. Специализированные модели типа mxbai-embed-large или multilingual-e5-large могут дать лучший поиск.
TODO: сравнить качество поиска с другими embed-моделями (например mxbai-embed-large тоже через Ollama)
4. QDRANT_API_KEY утёк в чат 05.08.2026¶
Появлялся в выводе docker exec ... env который я показал в Perplexity-чате.
TODO: ротировать QDRANT_API_KEY — сгенерировать новый, обновить в docker-compose обоих сервисов.
TODO (сводка)¶
🔴 Приоритет 1 — безопасность¶
- Ротировать
QDRANT_API_KEY(утёк в чат 05.08.2026) - Продублировать OpenWebUI API-токен в Vaultwarden (сейчас только в
.envна ragserver) - Настроить бэкап
/opt/rag-sync/и/opt/rag-kb/— сейчас не бэкапится
🟡 Приоритет 2 — автоматизация¶
- Установить systemd timer для запуска синка каждые 5 минут (сейчас только вручную)
- Добавить в скрипт
--resetфлаг для полной пересинхронизации - Добавить в скрипт auto-update самого себя из
/opt/rag-kb/scripts/ - Настроить monitoring — email/telegram если синк упал N раз подряд
🟢 Приоритет 3 — ускорение¶
-
RAG_EMBEDDING_BATCH_SIZEс4→32 -
RAG_CHUNK_SIZEс1000→2000 - Проверить
skip_embeddingпри upload — если работает, избавиться от двойной индексации - Сравнить качество поиска nomic-embed-text vs mxbai-embed-large vs multilingual-e5
🔵 Приоритет 4 — расширение¶
- Интегрировать RAG в CRM — чтобы менеджеры могли задавать вопросы по знаниям через API
- Расширить KB на другие проекты — CRM, коробочка, alatyr-service platform
- Собрать веб-хук от git push → мгновенный синк (вместо ожидания cron)
Ссылки¶
- Репо: github.com/oswold1979/alatyr-infra-kb (private)
- Deploy keys: github.com/oswold1979/alatyr-infra-kb/settings/keys
- OpenWebUI docs: docs.openwebui.com
- Qdrant docs: qdrant.tech/documentation
- Ollama models: ollama.com/library
- Nomic-embed-text: ollama.com/library/nomic-embed-text
Связанные файлы¶
- ragserver-workstation.md — сам ragserver, железо, Docker
- amneziawg-tunnels.md — как AI-агенты снаружи будут добираться до RAG через VPN
- vaultwarden.md — хранение API-токенов
- crm-objects-spec.md — CRM которая будет использовать RAG
История изменений¶
| Дата | Что |
|---|---|
| 2026-08-05 | Первая версия. Развёрнут deploy key SSH, скрипт sync-to-openwebui.sh (bash, 199 строк), первый синк 10 файлов за 9m36s, коллекция alatyr-infra-kb (191ae5b9...) создана в OpenWebUI. Обнаружены: двойная индексация OpenWebUI при upload+attach, Ollama на хосте systemd не в докере, слушает 192.168.1.200:11434, размерность 768. Утечка QDRANT_API_KEY в чат — надо ротировать. Cron/timer пока не установлен. |