Skip to content

Знания — LightRAG

Что и зачем

knowledge = LightRAG (библиотека HKUDS), взятая свежо (greenfield — не порт кастомной 1.x реализации на OpenSearch + Neo4j). Это graph-RAG движок: чанкинг → LLM-извлечение сущностей/связей → граф знаний → multi-mode retrieval (naive / local / global / hybrid).

Деплой: отдельный сервис

LightRAG — Python, а api — NestJS. Поэтому:

  • LightRAG крутится отдельным сервисом (Python, server-режим) в Hetzner k8s.
  • agent/knowledge — тонкий gateway к нему: CRUD баз знаний, заливка документов, прокси retrieval, экспозиция через mcp. Заботы ingestion / query / graph схлопываются внутрь LightRAG — это не наши сабслайсы.

Storage-бэкенд (РЕШЕНИЕ ОТКРЫТО)

LightRAG абстрагирует хранилища KV / vector / graph. Два кандидата:

  • Unified Postgres (pgvector + Apache AGE) — app-данные + KV + вектор + граф в одном Postgres. Убирает отдельный infra/vector и Neo4j. Требует self-host Postgres на Hetzner (managed Neon скорее всего не даст расширение AGE). Лучше для small/medium размеров баз.
  • Neo4j (граф) + выделенный vector-DB (Qdrant/Milvus) — для больших баз; снова открывает Neon для app-данных.

Выбор зависит от ожидаемой формы масштаба (ниже).

Масштаб: стена — это индексация

Для миллионов файлов ограничение — индексация, а не хранение. LightRAG делает на каждый чанк LLM-извлечение сущностей/связей → миллионы файлов = большие токены + время (свойство graph-RAG). Поэтому:

  • индексация обязана быть async / в очереди (tasks + BullMQ), инкрементальной, rate-limited, с бюджетом токенов;
  • держим дешёвый naive vector-RAG путь — граф включаем только где он окупается;
  • мультитенантность спасает: это не один гигантский граф, а много баз (LightRAG workspaces), в основном небольших → естественный шардинг. Тяжёлый кейс — миллионы в одной базе.

Бэкенд по форме масштаба: много небольших баз → unified PG(pgvector+AGE) ок; миллионы в одной базе → pgvector напрягается (~несколько M), а AGE не обкатан на огромных графах → лучше Neo4j + Qdrant/Milvus.

Референс (уже работает в Ranch): cleanslice/ranch/k8s/platform/lightrag/* крутит ghcr.io/hkuds/lightrag на Postgres с pgvector + AGE (LIGHTRAG_{KV,VECTOR,GRAPH,DOC_STATUS}_STORAGE=PG*). Нюанс: у стокового CNPG нет AGE, поэтому LightRAG-БД — отдельный Postgres (образ gzdaniel/postgres-for-rag), отдельно от app-БД на CNPG — пока нет кастомного CNPG-with-AGE. EMBEDDING_DIM фиксируется при первом индексе (смена ⇒ реиндекс). См. GitOps.

WARNING

LightRAG молодой (2024). Бенчмаркай на целевом масштабе до коммита и пинь версию (схема стораджа меняется между релизами).

Мультитенантность через workspace

Параметр workspace у LightRAG даёт логическую изоляцию внутри общего стораджа (подпапка для файловых бэкендов; префикс / неймспейс / label графа для БД-бэкендов — проверяй per backend & version).

Дизайн:

  • 1 workspace = 1 база знаний.
  • Сервис LightRAG держит пул инстансов LightRAG по workspace (lazy-init + LRU/idle-эвикшн), все делят креды одного бэкенда.
  • Безопасность: api (agent/knowledge) выводит workspace из аутентифицированного team/kb — никогда не доверяй workspace от клиента — и является единственным, кто зовёт внутренний сервис LightRAG. Всегда непустой workspace (пустой = общий дефолт → утечка между тенантами).
  • Жизненный цикл: удаление базы сносит её workspace (delete-by-doc + зачистка бэкенда, напр. drop AGE-графа). Холодный старт инстанса на первой операции базы → учитывай в латентности (прогрев/кэш).
python
# Сервис LightRAG (Python), упрощённо
_pool: dict[str, LightRAG] = {}             # workspace -> instance (LRU)

async def get_rag(workspace: str) -> LightRAG:
    if workspace not in _pool:
        rag = LightRAG(
            working_dir=f"/data/{workspace}",
            workspace=workspace,             # ← изоляция
            kv_storage="PGKVStorage",
            vector_storage="PGVectorStorage",
            graph_storage="PGGraphStorage",  # AGE
            # llm / embedding функции ...
        )
        await rag.initialize_storages()
        _pool[workspace] = rag               # + эвикшн по размеру/idle
    return _pool[workspace]
# эндпоинты: POST /insert {workspace, docs} ; POST /query {workspace, query, mode}

Gateway в api зовёт эти эндпоинты с workspace = kb_id владельца.