-
Notifications
You must be signed in to change notification settings - Fork 6
Wiki RAG
Система контекстного поиска по документации с автоматической инжекцией в системный промпт LLM.
Workspace-фильтрация: Коллекции и документы фильтруются по
workspace_idиз JWT. In-memory BM25/embedding индексы остаются глобальными — фильтрация применяется на уровне API-эндпоинтов.

Wiki RAG — это двухуровневая поисковая система по markdown-документам, встроенная в ИИ-секретаря:
- Semantic Embeddings (если доступен провайдер) — понимает смысл: «сколько стоит» → находит «тарифы и цены»
- BM25 Okapi (всегда доступен) — морфологический поиск с русским/английским стеммингом
- Автоматически индексирует все файлы
.mdиз каталогаwiki-pages/ - Разбивает документы на секции по заголовкам
##и### - При запросе к LLM автоматически инжектит релевантные секции документации в системный промпт
- Минимальные зависимости — BM25 работает без GPU и без внешних API
1. Парсинг markdown по заголовкам ## и ###
2. Токенизация текста (Unicode-aware, русский + английский)
3. Стемминг: "настройки" → "настройк", "settings" → "set"
4. Фильтрация стоп-слов (русские + английские)
5. Построение BM25 индекса (document frequency, avg doc length)
6. Токены из заголовков получают 4x вес
| Параметр | Значение |
|---|---|
| MIN_TOKEN_LEN | 2 символа |
| MIN_SCORE | 0.3 (порог минимальной релевантности) |
| Минимальная длина секции | 50 символов (короткие игнорируются) |
| Стоп-слова | Фильтруются для русского и английского |
1. Пользователь отправляет запрос LLM
2. Если доступны embeddings:
a. Эмбеддинг запроса через провайдер
b. Cosine similarity по всем секциям
c. Топ-k секций (similarity > 0.3)
3. Если embeddings нет или не нашли — BM25 fallback:
a. Токенизация + стемминг запроса
b. BM25 Okapi ранжирование → топ-k (score ≥ 0.3)
4. Форматирование в markdown-контекст (до max_chars символов)
5. Инжекция в начало системного промпта
6. Если контекст пуст — добавляется anti-hallucination инструкция
7. LLM отвечает с учётом найденной документации
BM25 — это алгоритм ранжирования, улучшающий TF-IDF за счёт:
- Насыщение TF (k1=1.5) — 10-е повторение слова не так важно, как 1-е
- Нормализация по длине (b=0.75) — короткие точные секции не проигрывают длинным
- Стемминг — "настройки", "настройка", "настроить" → одна основа "настройк"
Поверх BM25 работает семантический поиск на основе embedding-векторов:
| Провайдер | Модель | Размерность | Когда используется |
|---|---|---|---|
| Local (sentence-transformers) | paraphrase-multilingual-MiniLM-L12-v2 | 384 |
DEPLOYMENT_MODE=full + пакет установлен |
| Gemini | text-embedding-004 | 768 | Облачный LLM = Gemini |
| OpenAI-compatible | text-embedding-3-small | varies | Облачный LLM = OpenAI/DeepSeek/etc |
Приоритет: Local → Cloud → BM25 fallback
Эмбеддинги кэшируются в data/wiki_embeddings.json (~1.7MB для 573 секций). При перезапуске загружаются из кэша без повторного вычисления.
Документы группируются в коллекции — контейнеры для логического разделения базы знаний.
- Каждая коллекция имеет своё имя, slug, описание и отдельный каталог файлов (
base_dir) - Документы привязываются к коллекции через
collection_id - При первом запуске автоматически создаётся коллекция «Default» — все существующие документы попадают в неё
- Каждая коллекция индексируется отдельно (
CollectionIndexс собственным BM25-индексом) - Коллекцию «Default» нельзя удалить
Во вкладке Finetune → Cloud AI доступен селектор коллекций (pill-shaped кнопки):
| Действие | Описание |
|---|---|
| Выбор коллекции | Клик по названию — фильтрует таблицу документов |
| Создание | Inline-форма: имя + описание → POST /admin/wiki-rag/collections
|
| Перезагрузка | Кнопка Reload на коллекции → POST /admin/wiki-rag/collections/{id}/reload
|
| Удаление | Кнопка Delete (не для Default) → DELETE /admin/wiki-rag/collections/{id}
|
Функция retrieve_multi(query, collection_ids, top_k, max_chars):
- Запрашивает каждую коллекцию независимо
- Объединяет результаты по скору
- Возвращает top_k лучших секций из всех коллекций
Стандартный retrieve() и search() принимают опциональный collection_id для поиска в конкретной коллекции.
Каждый бот, виджет и WhatsApp-инстанс может иметь собственную настройку RAG:
| Поле | Тип | Описание |
|---|---|---|
rag_mode |
"all" / "selected" / "none"
|
Режим RAG |
knowledge_collection_ids |
JSON список | Список ID коллекций (для mode=selected) |
Приоритет разрешения RAG-конфигурации (в _resolve_rag_config()):
- Переопределение в запросе (
LLMOverrideConfig) - Настройки виджета (
WidgetInstance) - Настройки Telegram-бота (
BotInstance) - Настройки WhatsApp-бота (
WhatsAppInstance) - Настройки сессии (
ChatSession) - По умолчанию:
"all"+ все включённые коллекции
Во фронтенде: RAG mode dropdown + multi-select чекбоксы коллекций в формах редактирования Widget, Telegram и WhatsApp инстансов. В ChatView — селектор RAG mode (сохраняется в localStorage).
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/wiki-rag/collections |
Список всех коллекций |
| POST | /admin/wiki-rag/collections |
Создать коллекцию |
| GET | /admin/wiki-rag/collections/{id} |
Получить коллекцию |
| PUT | /admin/wiki-rag/collections/{id} |
Обновить коллекцию |
| DELETE | /admin/wiki-rag/collections/{id} |
Удалить коллекцию (кроме Default) |
| POST | /admin/wiki-rag/collections/{id}/reload |
Перезагрузить индекс коллекции |
-
scripts/migrate_knowledge_collections.py— таблицаknowledge_collections, FK вknowledge_documents -
scripts/migrate_rag_settings.py— поляrag_modeиknowledge_collection_idв инстансах -
scripts/migrate_multi_collection_rag.py— миграция наknowledge_collection_ids(множественный выбор)
Левая панель отображает все документы в базе:
| Элемент | Описание |
|---|---|
| Название | Имя файла или title из метаданных |
| Секций | Количество индексированных секций |
| Токенов | Уникальные токены |
| Источник |
source_file (относительный путь) |
| Действия | Просмотр / Редактировать / Удалить |
- Нажмите "Загрузить документ"
- Выберите файл
.mdили.txt - Документ сохраняется в
wiki-pages/и индексируется автоматически
При первом обращении к API система автоматически сканирует wiki-pages/:
- Новые файлы на диске → добавляются в БД
- Файлы в БД, но отсутствующие на диске → помечаются как недоступные
- Изменённые файлы (по timestamp) → переиндексируются
- Выберите документ из списка
- Откройте редактор (markdown)
- Сохраните — индекс обновится автоматически
Удаление документа:
- Из БД — запись удаляется
-
С диска — файл удаляется физически из
wiki-pages/
API: POST /admin/wiki-rag/search
{
"query": "как настроить telegram бота",
"top_k": 5
}Результат:
{
"results": [
{
"title": "Настройка воронки в боте",
"body": "Основная конфигурация происходит в Telegram → [Бот] → Sales.",
"source_file": "Sales",
"score": 8.141
}
],
"query": "как настроить telegram бота"
}API: POST /admin/wiki-rag/retrieve
{
"query": "telegram webhook",
"top_k": 7,
"max_chars": 4000
}Возвращает отформатированный markdown-контекст для инжекции в системный промпт:
[Документация по теме:]
## Telegram (Telegram боты)
Настройка Telegram-ботов через webhook или long polling...
## Payments (Платежи)
YooMoney webhook принимает POST /webhooks/yoomoney...API: GET /admin/wiki-rag/stats
{
"stats": {
"engine": "embeddings+bm25+vector_search",
"embedding_engine": "gemini",
"embedding_sections": 573,
"vector_search_available": true,
"vector_search_url": "http://localhost:8003",
"sections_indexed": 573,
"files_indexed": 32,
"unique_tokens": 2784,
"avg_doc_length": 36.0,
"available": true
}
}Если эмбеддинги не доступны, "engine": "bm25", "embedding_engine": null, "embedding_sections": 0.
Если Vector Search подключен, в engine добавляется +vector_search, и появляются поля vector_search_available и vector_search_url. См. Vector-Search для подробностей.
API: POST /admin/wiki-rag/reload
Пересканирует все файлы в wiki-pages/ и перестраивает индекс.
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/wiki-rag/stats |
Статистика индекса |
| POST | /admin/wiki-rag/reload |
Перестроить BM25 индекс + эмбеддинги |
| POST | /admin/wiki-rag/search |
Поиск по запросу (embeddings → BM25) |
| POST | /admin/wiki-rag/retrieve |
Получить контекст для промпта |
| POST | /admin/wiki-rag/reindex-embeddings |
Пересоздать все эмбеддинги с нуля |
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /admin/wiki-rag/documents |
Список всех документов |
| POST | /admin/wiki-rag/documents/upload |
Загрузить .md или .txt
|
| GET | /admin/wiki-rag/documents/{id} |
Просмотр документа |
| PUT | /admin/wiki-rag/documents/{id} |
Редактировать документ |
| DELETE | /admin/wiki-rag/documents/{id} |
Удалить документ |
- Admin — полный доступ (загрузка, редактирование, удаление)
- User/Web — загрузка, редактирование и удаление своих документов
- Guest — только чтение и поиск
- Unicode-aware — корректно обрабатывает кириллицу
- Case-insensitive — приведение к нижнему регистру
- Стемминг — Snowball stemmer (русский + английский)
- Разделители — пробелы и знаки пунктуации
BM25(q, d) = Σ IDF(t) × TF_norm(t, d)
IDF(t) = log((N - df(t) + 0.5) / (df(t) + 0.5) + 1)
N = всего секций
df(t) = в скольких секциях встречается стем t
TF_norm(t, d) = (tf × (k1 + 1)) / (tf + k1 × (1 - b + b × |d| / avg_dl))
tf = частота стема t в секции d
k1 = 1.5 (насыщение TF)
b = 0.75 (нормализация по длине)
|d| = длина секции в токенах
avg_dl = средняя длина секции
Токены из title секции добавляются в индекс четырежды (4x boost), повышая ранжирование по заголовкам.
- Индексация — ~1000 секций/сек
- Поиск — <10ms для запроса из 5-10 токенов
- Память — ~50KB на 1000 секций + стеммер ~100KB
Когда включена функция Wiki RAG:
1. Пользователь: "Как настроить webhook для Telegram?"
2. Wiki RAG → retrieve("telegram webhook", top_k=7, max_chars=4000)
3. Системный промпт LLM:
---
НЕ выдумывай информацию, которой нет в контексте ниже.
[Документация по теме:]
<найденные секции>
---
<стандартный system_prompt>
4. LLM отвечает с учётом документации
Если RAG-поиск не нашёл релевантных секций (пустой контекст), в системный промпт добавляется специальная инструкция:
--- ВАЖНО ---
По данному запросу в базе знаний не найдено релевантной информации.
НЕ выдумывай ответ. Если ты не уверен в точности информации —
честно скажи, что не нашёл данных в базе знаний, и предложи
обратиться к менеджеру или уточнить вопрос.
Это предотвращает ситуации, когда LLM «галлюцинирует» и выдаёт неверную информацию, не имея контекста из базы знаний.
| Параметр | Значение | Описание |
|---|---|---|
| top_k | 7 | Количество секций для поиска (embeddings и BM25) |
| max_chars | 4000 | Максимальный размер контекста в символах |
| max_tokens | 1024 | Лимит токенов ответа LLM (по умолчанию) |
Загрузите всю техническую документацию в wiki-pages/ → ИИ-секретарь будет отвечать на вопросы клиентов, ссылаясь на актуальную документацию.
Загрузите регламенты, инструкции, FAQ → боты в Telegram и виджеты на сайте смогут давать точные ответы.
Новые сотрудники задают вопросы ИИ-ассистенту, который ищет информацию в корпоративной wiki.
← FAQ | Agentic-RAG | Personas →
См. также: Agentic-RAG — режим, в котором LLM сам решает когда и что искать в базе знаний (tool calling).