Знания — 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 владельца.