Модель сущностей GraphRAG
Форма данных knowledge graph — GraphNode, GraphEdge, evidence-чанки и ограничения, обеспечивающие безопасный мультитенантный graph-запрос.
GraphRAG-enabled Knowledge space хранит направленный размеченный граф рядом с KnowledgeChunk. Эта страница — справочник по схеме, LLM-проходам, которые её наполняют, и ограничениям при прямых запросах.
Схема
Две таблицы в packages/database/prisma/schema.prisma:
GraphNode
model GraphNode {
id String @id @default(cuid())
knowledgeSpaceId String
knowledgeSpace KnowledgeSpace @relation(fields: [knowledgeSpaceId], references: [id], onDelete: Cascade)
canonicalName String
nodeType String
metadata Json @default("{}")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@unique([knowledgeSpaceId, canonicalName, nodeType])
@@index([knowledgeSpaceId, nodeType])
@@map("graph_node")
}| Поле | Назначение |
|---|---|
canonicalName | Нормализованная метка сущности («OpenAI», «Wallet API», «PrestaShop Module»). Решается LLM при ingest. |
nodeType | Семантический тип: "Product", "Person", "Concept", "API", "Organization", "Document", "Event". |
metadata | Свободный JSON. Сейчас: { aliases: string[], firstSeenChunkId: string }. Эволюционирует аддитивно. |
(spaceId, canonicalName, nodeType) | Уникальный ключ. «OpenAI/Organization» — одна нода; «OpenAI/Product» — отдельная. |
GraphEdge
model GraphEdge {
id String @id @default(cuid())
knowledgeSpaceId String
knowledgeSpace KnowledgeSpace @relation(fields: [knowledgeSpaceId], references: [id], onDelete: Cascade)
fromNodeId String
toNodeId String
relationType String
weight Float @default(1)
evidenceChunkId String?
metadata Json @default("{}")
createdAt DateTime @default(now())
deletedAt DateTime?
@@index([knowledgeSpaceId, fromNodeId, relationType])
@@index([knowledgeSpaceId, toNodeId, relationType])
@@map("graph_edge")
}| Поле | Назначение |
|---|---|
fromNodeId / toNodeId | Направленная пара. Порядок важен: «OpenAI provides GPT-4» — from=OpenAI, to=GPT-4, rel=provides. |
relationType | Глагол: "provides", "owns", "depends_on", "deprecates", "replaces", "integrates_with". |
weight | Confidence × частота. Нормализуется в [0, 1] per ingest. Несколько упоминаний — суммируются. |
evidenceChunkId | Чанк-источник связи. Используется graphragExplain для цитирования. |
metadata | Свободный JSON: { confidence: number, model: string, extractedAt: ISO }. |
Глобальной уникальности на edges нет — несколько (from, to, rel) могут сосуществовать, у каждой свой evidence-чанк. Агрегации суммируют weight.
Каскадные удаления
Всё каскадит на KnowledgeSpace.id:
- Удалить space → все nodes и edges.
- Удалить документ → его чанки каскадят, но edges, указывавшие на них, сохраняют
evidenceChunkIdчерезonDelete: SetNull— связь живёт, просто без цитаты. Намеренно: удаление одного документа не должно убивать граф, выведенный из двадцати других.
Как наполняются nodes и edges
Драйвер — buildGraphFromChunks в packages/api/modules/knowledge/lib/graphrag.ts. Два LLM-прохода:
Проход 1 — entity resolution
resolveEntitiesFromChunks(chunks) в entity-resolution.ts отправляет каждый чанк в модель с промптом, требующим:
canonicalName— нормализованная форма.type— один из допустимыхnodeType.aliases— surface forms в чанке, маппящиеся в эту сущность.
Дедуп — внутри чанка и через чанки по (canonicalName, type). Существующие ноды переиспользуются через upsertGraphNode. Aliases мерджатся в metadata.aliases.
Проход 2 — relation typing
В дело идут только чанки с ≥ 2 разными сущностями. extractRelationsFromChunks запрашивает у модели для каждого:
from,to— канонические имена, выданные на проходе 1.relationType— глагол в lower snake_case из небольшого типизованного словаря.confidence—0..1.
Принятая связь → новый GraphEdge с evidenceChunkId. Edges ниже confidence-порога (сейчас 0.5) — отбрасываются.
Прямой запрос графа
Граф можно дёргать через Prisma-хелперы из @repo/database — для кастомных дашбордов или evaluations:
import { db, listGraphEdgesForNodes } from "@repo/database";
// Все edges из ноды:
const outgoing = await db.graphEdge.findMany({
where: { knowledgeSpaceId: spaceId, fromNodeId: nodeId },
});
// Двунаправленный fan-out из набора anchor-нод:
const edges = await listGraphEdgesForNodes({
knowledgeSpaceId: spaceId,
nodeIds: anchorIds,
});Для мультитенант-безопасности каждый запрос ДОЛЖЕН содержать knowledgeSpaceId (Инвариант 5 на Knowledge). Репозиторные хелперы это форсят; прямой db.graphEdge.findMany без него — баг.
Confidence и шум
Два повода видеть «странные» связи:
- Hallucinated relation. Модель выдумала глагол.
confidenceобычно низкий; фильтруйтеmetadata.confidence > 0.7, если рендерите edges пользователю напрямую. - Реальное, но противоречивое. Два чанка не согласны.
weightнакапливается, edges живут — ноgraphragExplainиногда процитирует оба. Лечить надо контент, не граф.
Job сообществ (graphragCommunities) учитывает только edges с weight ≥ 0.5.
Эволюция схемы
Схема заморожена (Инвариант 9). Ожидается аддитивно через:
- Новые
relationType— без миграции; колонкаString. - Новые ключи в
metadataJSON — аддитивно, валидация при записи. - Новые
nodeType— без миграции; считайте множество открытым.
Переименование/удаление существующих — Gate A (явный аппрув), плюс ingest-time migration plan; молча переписывать historical edges нельзя.
Инспекция в дашборде
Дашборд Knowledge → Graph (Beta) показывает список нод, счётчики edges по relation type и обнаруженные сообщества. Визуальный explorer — roadmap.
Канонический путь инспекции пока — Postgres напрямую:
SELECT relationType, count(*) AS edges, avg(weight) AS avg_weight
FROM graph_edge
WHERE knowledgeSpaceId = '…'
AND deletedAt IS NULL
GROUP BY 1
ORDER BY 2 DESC;Что нужно держать в голове
- 2-hop горизонт.
graphragExplainходит максимум 2 hops по умолчанию. Дальше шум перевешивает сигнал. - Нет поиска по атрибутам edge. Запрос «edges с
metadata.confidence > 0.9» через public API недоступен — только через Prisma. - Нет write API. Edges и nodes создаются только ingest-пайплайном. Прямого user-facing создания нет.
- Один граф на space. Cross-space джойны не поддерживаются.
Связанные страницы
- Обзор GraphRAG
- GraphRAG use cases
- Knowledge sources — путь ingest-а, наполняющий граф
- Knowledge evaluation — измерение пользы графа
Обзор GraphRAG
Граф-aware retrieval, добавляющий рассуждение по сущностям и связям поверх Knowledge RAG. Когда тянуться за этим и чем отличается от plain RAG.
Сценарии использования GraphRAG
Конкретные паттерны, где GraphRAG выигрывает у plain RAG — продуктовые знания, поддержка, compliance, внутренние доки — с примерами вопросов и тем, что добавляет граф.