ADR 0001 — GraphRAG: отложенное внедрение и условия включения
ADR 0001 — GraphRAG: отложенное внедрение и условия включения
Section titled “ADR 0001 — GraphRAG: отложенное внедрение и условия включения”- Статус: Accepted (defer-with-seam)
- Дата: 2026-05-30
- Контекст-аудиты:
docs/audits/audit_claude_30_05_26.md(§3.1 — GraphRAG отсутствует, обоснованно отложен),docs/research/rag-landscape-2026.md(§2 — GraphRAG «для корпусного понимания») - Связано: демо-корпус
data/uploads/aircargo/(201 док, ~7K чанков),docs/plans/2026-05-30-demo-corpus-and-rag-grounding.md
Контекст
Section titled “Контекст”Продукт позиционируется как универсальный гибкий RAG, а не как support-бот на 3 дока. До 2026-05-30 KB содержал 3 игрушечных дока (warranty/returns/errors). Сейчас в проект заведён реальный демо-корпус из 201 документа (HR-политики, договоры, претензии, транспортная логистика, комплаенс, FAQ; RU; медиана ~21 200 символов на документ; ~7000 чанков при текущем chunking). Это первый момент, когда «масштаб» перестал быть гипотезой.
Вопрос: нужен ли GraphRAG, и если да — когда и в какой форме, чтобы он был предусмотрен архитектурно, а не прикручен задним числом.
Что такое GraphRAG и почему он дорогой
Section titled “Что такое GraphRAG и почему он дорогой”Классический Microsoft-style GraphRAG строит граф сущностей/отношений поверх корпуса:
- По каждому чанку — LLM извлекает сущности и связи (entity/relation extraction).
- Граф кластеризуется (Leiden community detection).
- По каждому сообществу — LLM пишет summary (community report).
- Запрос: local search (по сущностям) или global search (map-reduce по community-summaries).
Цена: шаг 1 — это один LLM-вызов на чанк на этапе индексации. Для нашего корпуса
(~7000 чанков) это ~7000 LLM-вызовов только на построение графа — ровно тот fan-out,
который аудит (R3/R4) уже отмечает как болевую точку даже на одном ответе. На текущем
железе (Windows-ноут — thin client; Mac — слабый; см. AGENT_STATE.md thin-client boundary)
полная индексация GraphRAG локально нереалистична — это Colab/remote-only задача.
Польза при этом реальна, но узкая: multi-hop recall +6.4 п., снижение галлюцинаций 20–30 % (arxiv 2506.00054) — на «глобальных» вопросах («как связаны A и B?», «какие темы проходят через корпус?»). На фактологических single-hop вопросах поддержки (90 %+ реального трафика) hybrid+rerank уже даёт верный ответ дешевле.
Решение
Section titled “Решение”Отложить полный GraphRAG как дефолт, но заложить архитектурный шов сейчас.
1. Шов в коде (предусмотреть, не включать)
Section titled “1. Шов в коде (предусмотреть, не включать)”- Ввести настройку
RAG_RETRIEVAL_STRATEGY ∈ {vector, hybrid, graph}(дефолтhybrid). СейчасHybridRetrieverжёстко зашит; вынести за интерфейсRetriever.retrieve(query) -> docs, чтобы graph-ретривер подключался как третья реализация без правки графа LangGraph. - Узел
classify_complexityуже существует и уже различает сложность запроса. Добавить классglobal/multi_hopи ветку маршрутизации:global → graph_retrieve, иначе → hybrid. Это превращает GraphRAG в опциональный путь для подмножества запросов, а не в замену основного ретривера.
2. Условия включения (trigger)
Section titled “2. Условия включения (trigger)”Включать graph-путь, когда выполнено И то, и другое:
- Масштаб корпуса: > ~2 000 документов ИЛИ > ~50 000 чанков на тенант. (Текущие 201 / ~7K — ниже порога; для них hybrid+rerank достаточно и дешевле.)
- Класс запроса:
classify_complexityпометил запрос как глобальный/multi-hop.
Оба условия защищают от того, чтобы платить graph-цену на трафике, который её не требует.
3. Чем строить, когда дойдём (НЕ катать руками)
Section titled “3. Чем строить, когда дойдём (НЕ катать руками)”Приоритет — по стоимости индексации, от дешёвого к дорогому:
- Дешёвый промежуточный слой (можно сделать без LLM-extraction уже сейчас):
metadata/relational граф из уже имеющейся структуры корпуса — категория (
01_hr,03_legal,05_tlog…), тип документа, явные перекрёстные ссылки между документами. Это «граф документов», а не «граф сущностей»: 0 LLM-вызовов, строится из метаданных loader’а. Покрывает часть multi-hop («покажи все документы, связанные с договором X»). - LightRAG / nano-graphrag — на порядок дешевле MS GraphRAG (dual-level retrieval, инкрементальные апдейты, кратно меньше LLM-вызовов на индексацию). Рекомендованный первый «настоящий» GraphRAG для этого проекта.
- LlamaIndex PropertyGraphIndex — если нужен зрелый property-graph с готовыми экстракторами.
- Microsoft GraphRAG — только если заказчику нужен именно его global-search map-reduce и бюджет на индексацию это оправдывает.
Во всех случаях: использовать готовую библиотеку, не реализовывать извлечение графа руками.
4. Бюджетные guardrails
Section titled “4. Бюджетные guardrails”- Построение графа — Colab/remote-only (GPU + отсутствие RAM-лимита локальной машины).
- Уважать
DAILY_COST_LIMIT_USD; индексировать инкрементально (только новые/изменённые документы —DocumentChangeTrackerуже есть вingestion/loader.py). - Кэшировать промежуточные артефакты графа (узлы/рёбра/summaries) как parquet/jsonl, не пересчитывать на каждый прогон.
Последствия
Section titled “Последствия”- (+) Продукт «предусматривает» GraphRAG: шов + trigger + выбранный стек задокументированы; включение — это смена флага и подключение реализации, а не переписывание пайплайна.
- (+) Не платим graph-цену на текущем масштабе и на single-hop трафике.
- (+) Дешёвый metadata-граф из структуры корпуса доступен уже сейчас как первый шаг.
- (−) До включения multi-hop «глобальные» вопросы обслуживаются хуже (ограничение hybrid). Принимаем: такой трафик в support-сценарии редок.
- (−) Шов (
RAG_RETRIEVAL_STRATEGY+ веткаglobal) — это код, который надо написать и покрыть тестами до того, как graph-реализация появится; иначе шов протухнет.
Критерий пересмотра
Section titled “Критерий пересмотра”Вернуться к включению graph-пути, когда любой тенант перешагнёт ~2 000 документов / ~50 000 чанков, или когда eval (R7) покажет систематический провал на multi-hop классе вопросов, который hybrid+rerank не закрывает.