Знання — 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-графа). Холодний старт інстансу на першій операції бази → враховуй у латентності (прогрів/кеш).
# Сервіс 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 власника.