Hybrid Retrieval на LightRAG

RAG-контур в этом проекте построен вокруг LightRAG. Его задача не просто «положить документы в базу», а превратить подготовленный текст в основу, по которой можно задавать живые вопросы и получать ответы с опорой на базу знаний.

В простом RAG часто всё сводится к цепочке «файл → embeddings → ближайшие чанки». Такая схема понятна, но в реальных документах смысл редко лежит только в одном похожем фрагменте. Важны соседние понятия, связи между сущностями, повторяющиеся темы и то, как один документ объясняет другой. Поэтому здесь используется гибридный retrieval: embeddings находят близкие фрагменты по смыслу, а граф помогает не потерять отношения между сущностями.

Основные хранилища

RAG-сервер поднимается с несколькими backend-хранилищами, и у каждого из них своя роль в общей картине:

  • Qdrant — векторный слой для embeddings и семантического поиска;
  • Neo4j — граф знаний для сущностей и связей;
  • PostgreSQL — метаданные документов, статусы, сессии и история чата.

LightRAG соединяет Qdrant и Neo4j как retrieval engine: один слой отвечает за смысловую близость, другой — за связи. PostgreSQL не заменяет поисковый индекс, зато делает систему управляемой: помогает понимать, какие документы загружены, что с ними происходит и к какому диалогу относится конкретный запрос.

Ingestion pipeline

Документ попадает в RAG через POST /api/v1/ingest. На входе сервер вычисляет MD5-хеш, проверяет дубликат в PostgreSQL, извлекает текст из поддержанных форматов и создаёт запись со статусом PENDING.

Дальше индексация уходит в фон. Это важно для production-пайплайна: загрузка документа не должна превращаться в непрозрачную операцию, после которой непонятно, готова база к вопросам или нет.

  1. статус обновляется на INDEXING;
  2. LightRAG запускает ainsert(text);
  3. текст разбивается на чанки;
  4. embeddings сохраняются в Qdrant;
  5. сущности и связи извлекаются через LLM и сохраняются в Neo4j;
  6. статус становится COMPLETED или ERROR;
  7. если указан webhook, сервер отправляет уведомление о завершении.

PFRAG может отдавать в этот контур уже очищенный Markdown. Для retrieval это не косметика, а качество входа: чем меньше в тексте навигационного шума, дублей и плохо распознанных фрагментов, тем меньше вероятность, что LightRAG построит индекс вокруг случайного мусора.

Query modes

Для чата доступны режимы поиска:

  • naive — простой векторный поиск;
  • local — поиск с локальным контекстом графа;
  • global — глобальный обход графа;
  • hybrid — комбинированный режим.

hybrid полезен как режим по умолчанию, потому что вопрос пользователя не всегда попадает точно в формулировку исходного документа. Иногда нужен ближайший по смыслу чанк, иногда — связь между сущностями, а часто и то и другое. Комбинированный режим даёт retrieval больше шансов собрать контекст, который действительно поможет ответить.

Остальные режимы при этом не становятся лишними. Они полезны как диагностические инструменты: можно сравнить, где векторный поиск уже справляется сам, где граф добавляет недостающий контекст, а где конкретной базе знаний нужно иначе готовить данные или чанки.

Multi-turn chat

RAG-сервер хранит историю чата в PostgreSQL. Если в запросе передать session_id, backend подгружает последние сообщения сессии и добавляет их в контекст. Это нужно для нормального человеческого диалога: пользователь может спросить «а подробнее?» или уточнить предыдущий вопрос без повторения всей темы.

Если session_id не передан, сервер создаёт новый UUID. Для внешнего UI это простой контракт: сохранять один session id на диалог и передавать его в следующих запросах.

REST, SSE и WebSocket

Чат можно подключать несколькими способами:

  • POST /api/v1/chat — обычный JSON-ответ;
  • POST /api/v1/chat/stream — SSE-стриминг, когда текст появляется по частям;
  • WS /api/v1/ws/chat — WebSocket для real-time сценариев.

Это делает backend гибким не ради красивой архитектурной схемы, а ради разных способов использования. Telegram-боту часто достаточно REST: пользователь отправил вопрос и получил ответ. Web UI удобнее подключать через SSE или WebSocket, чтобы ответ появлялся постепенно и интерфейс не выглядел зависшим во время генерации.

Управление документами и healthcheck

Кроме чата, RAG-контур даёт endpoints для списка документов, статуса по хешу, удаления и переиндексации. Есть статистика и healthcheck, который проверяет PostgreSQL, Qdrant и Neo4j.

Для базы знаний это важно не меньше самого чата. Если ответ плохой, причина может быть не в модели, а в данных: документ ещё индексируется, упал один из backend-слоёв, загрузился дубль или в индекс попал не тот текст. Оператору нужны статусы и проверки, чтобы видеть такие проблемы до того, как они станут «магическими» ошибками retrieval.

Роль LightRAG в общей системе

LightRAG в этом pipeline — не замена подготовке данных. Он хорошо работает как retrieval engine, когда получает нормальный текст и может разложить его на чанки, embeddings и графовые связи.

Поэтому лучший результат рождается на границе двух контуров: PFRAG отвечает за чистый вход, а RAG — за индекс, query modes и интерфейсы ответа. Hybrid Retrieval здесь нужен именно для этой связки: дать системе несколько способов найти полезный контекст, а не заставлять весь ответ зависеть от одного канала поиска.