Skip to content

Wiki RAG

shaerware edited this page Mar 23, 2026 · 8 revisions

Wiki RAG (База знаний)

Система контекстного поиска по документации с автоматической инжекцией в системный промпт LLM.

Workspace-фильтрация: Коллекции и документы фильтруются по workspace_id из JWT. In-memory BM25/embedding индексы остаются глобальными — фильтрация применяется на уровне API-эндпоинтов.

Скриншот

Wiki RAG

Концепция

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 Okapi

BM25 — это алгоритм ранжирования, улучшающий TF-IDF за счёт:

  • Насыщение TF (k1=1.5) — 10-е повторение слова не так важно, как 1-е
  • Нормализация по длине (b=0.75) — короткие точные секции не проигрывают длинным
  • Стемминг — "настройки", "настройка", "настроить" → одна основа "настройк"

Semantic Embeddings

Поверх 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 для поиска в конкретной коллекции.

Per-Instance RAG конфигурация

Каждый бот, виджет и WhatsApp-инстанс может иметь собственную настройку RAG:

Поле Тип Описание
rag_mode "all" / "selected" / "none" Режим RAG
knowledge_collection_ids JSON список Список ID коллекций (для mode=selected)

Приоритет разрешения RAG-конфигурации_resolve_rag_config()):

  1. Переопределение в запросе (LLMOverrideConfig)
  2. Настройки виджета (WidgetInstance)
  3. Настройки Telegram-бота (BotInstance)
  4. Настройки WhatsApp-бота (WhatsAppInstance)
  5. Настройки сессии (ChatSession)
  6. По умолчанию: "all" + все включённые коллекции

Во фронтенде: RAG mode dropdown + multi-select чекбоксы коллекций в формах редактирования Widget, Telegram и WhatsApp инстансов. В ChatView — селектор RAG mode (сохраняется в localStorage).

API коллекций

Метод 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 (относительный путь)
Действия Просмотр / Редактировать / Удалить

Загрузка документа

  1. Нажмите "Загрузить документ"
  2. Выберите файл .md или .txt
  3. Документ сохраняется в wiki-pages/ и индексируется автоматически

Синхронизация с диском

При первом обращении к API система автоматически сканирует wiki-pages/:

  • Новые файлы на диске → добавляются в БД
  • Файлы в БД, но отсутствующие на диске → помечаются как недоступные
  • Изменённые файлы (по timestamp) → переиндексируются

Редактирование

  1. Выберите документ из списка
  2. Откройте редактор (markdown)
  3. Сохраните — индекс обновится автоматически

Удаление

Удаление документа:

  • Из БД — запись удаляется
  • С диска — файл удаляется физически из wiki-pages/

Поиск и контекст

Поиск (Search)

API: POST /admin/wiki-rag/search

{
  "query": "как настроить telegram бота",
  "top_k": 5
}

Результат:

{
  "results": [
    {
      "title": "Настройка воронки в боте",
      "body": "Основная конфигурация происходит в Telegram → [Бот] → Sales.",
      "source_file": "Sales",
      "score": 8.141
    }
  ],
  "query": "как настроить telegram бота"
}

Контекст (Retrieve)

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/ и перестраивает индекс.

API эндпоинты

Управление системой

Метод 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} Удалить документ

RBAC

  • Admin — полный доступ (загрузка, редактирование, удаление)
  • User/Web — загрузка, редактирование и удаление своих документов
  • Guest — только чтение и поиск

Технические детали

Токенизация

  • Unicode-aware — корректно обрабатывает кириллицу
  • Case-insensitive — приведение к нижнему регистру
  • Стемминг — Snowball stemmer (русский + английский)
  • Разделители — пробелы и знаки пунктуации

BM25 формула

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

Интеграция с LLM

Когда включена функция Wiki RAG:

1. Пользователь: "Как настроить webhook для Telegram?"
2. Wiki RAG → retrieve("telegram webhook", top_k=7, max_chars=4000)
3. Системный промпт LLM:
   ---
   НЕ выдумывай информацию, которой нет в контексте ниже.
   [Документация по теме:]
   <найденные секции>
   ---
   <стандартный system_prompt>
4. LLM отвечает с учётом документации

Anti-hallucination

Если 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).

Clone this wiki locally