Графы знаний — это дорого. Очень дорого.
Вы построили GraphRAG. Сущности летают, связи звенят, multi-hop запросы щелкаются как орешки. Но приходит счет от OpenAI или Claude — и эйфория сменяется холодным потом. NER (Named Entity Recognition) жрет токены на извлечение каждой сущности. Построение связей — еще столько же. А если у вас юридические документы с сотнями страниц и тысячами перекрестных ссылок? Счета за API становятся сопоставимы с арендой сервера.
Проблема известна — графы знаний тяжелы. В статье GraphRAG против слепоты векторного поиска я показывал, как граф спасает контекст. Но там не было ответа на вопрос цены. Сегодня разбираем механизм, который режет затраты на 60-70% — Proxy-Pointer RAG с Graphability Indexing. Никакой магии. Только инженерная хитрость.
Откуда берется перерасход? Три кита расточительности
Прежде чем хвататься за оптимизацию, давайте поймем, куда утекают токены. Я выделяю три основные дыры:
- NER на весь корпус. Вы гоняете LLM или специальную модель по каждому чанку, вытаскивая Person, Organization, Law. Если документ — это бессвязный набор технических спецификаций, NER выкачивает тонну шума.
- Построение связей между всеми парами сущностей. Алгоритм соединяет каждую встреченную сущность с каждой (или хотя бы в окне). Для документа в 50 страниц это миллионы потенциальных ребер — проверить их все LLM стоит как небольшой космический корабль.
- Хранение графа в оперативной памяти. Графы с десятками тысяч узлов требуют RAM, и если вы используете in-memory граф вроде Neo4j или Memgraph, цена инфраструктуры растет.
Звучит знакомо? Если да — вы готовы к Proxy-Pointer.
Типичная ошибка: считать, что NER дешев. Одна экстракция сущностей из страницы текста через GPT-4o обходится в ~0.01$. Для 1000 страниц — 10$. А если вы делаете это трижды (для разных типов сущностей)? Уже 30$ только на извлечение. Graphability Indexing призван отсечь документы, где эти затраты не оправданы.
Proxy-Pointer: указатели вместо графа
Идея Proxy-Pointer RAG пришла из мира баз данных: зачем тащить весь граф, если можно хранить только указатели на «горячие» сущности? Вместо того чтобы строить полноценный граф знаний для каждого документа, мы создаем легковесный индекс — Proxy-Pointer Map. Этот индекс содержит только те сущности и связи, которые действительно участвуют в multi-hop запросах пользователя. Остальное — пустая трата ресурсов.
Как это выглядит на практике:
- При индексации запускается быстрый NER, но не для построения полного графа, а для вычисления graphability score — насколько документ «графопригоден».
- Если score проходной — строится скелет графа: узлы — только именованные сущности, ребра — только явные ссылки (например, «в соответствии с пунктом 3»).
- Если score низкий — документ идет в простой векторный поиск. Никакого графа, никакого NER. Экономия 100% на этом документе.
- При запросе LLM получает не всё подряд, а только те указатели, которые релевантны. «Дай все связи для контракта №123» — Proxy-PointerMap возвращает только контракт и его прямые ссылки, а не миллион соседних узлов.
Выглядит логично? Теперь самое интересное — как посчитать тот самый graphability score.
Graphability Indexing: метрика жадности
Graphability Indexing (GI) — это алгоритм, который оценивает, насколько текст насыщен потенциальными сущностями и связями, пригодными для графового ретривала. Формально GI — это взвешенная комбинация трех факторов:
- Сущностная плотность — количество именованных сущностей на 100 токенов. Если плотность ниже порога (эмпирически 0.5), документ не стоит графа.
- Связность — количество явных перекрестных ссылок (номеров статей, дат, ссылок на другие разделы). Юридические документы — лидеры по связности.
- Семантическая энтропия — насколько разнообразны типы сущностей. Если в тексте только даты и числа — граф не нужен. Если есть смесь Persons, Organizations, Laws, Contracts — потенциал high.
Эти три параметра сворачиваются в одно число — index от 0 до 1. Порог отсечения выставляется эмпирически: для юридической сферы 0.4, для технической документации — 0.6. Всё, что ниже — в векторный поиск, выше — в Proxy-Pointer граф.
Кейс: юридические документы и multi-hop пытки
Возьмем реальный сценарий. В вашей базе 5000 договоров аренды. Каждый договор ссылается на 10-30 других документов: акты приема-передачи, допсоглашения, выписки из реестра. Вопрос пользователя: «Какие риски у арендатора, если в договоре нет пункта о праве субаренды, а в допсоглашении №2 сказано про передачу прав третьим лицам?» Это классический multi-hop: нужно пересечь три сущности (договор, допсоглашение №2, объект аренды) и понять, что противоречие.
Полный граф построил бы все связи для всех 5000 договоров — около 150 000 узлов и 500 000 ребер. Стоимость: ~2000$ на LLM для построения, плюс 20 000$ в месяц на Neo4j Aura. Proxy-Pointer RAG с GI:
- GI для каждого документа считает score. 70% документов имеют score < 0.4 (например, простые счета-фактуры или уведомления). Для них — только векторный поиск, граф не строится. Экономия 70%.
- Оставшиеся 30% документов (1500) обрабатываются через Proxy-Pointer: извлекаются только ключевые сущности (стороны, даты, номера, суммы) и только явные ссылки.
- Размер графа: 15 000 узлов вместо 150 000. Ребер: 50 000.
- Стоимость построения: 600$ вместо 2000$. Затраты на хранение: 200$ в месяц.
Результат: пользователь получает тот же ответ, но бюджет сохранен. Да, 30% документов не имеют графа — для них работает только векторный поиск. Но как показано в статье Knowledge Graph на практике, многие запросы не требуют multi-hop. Пользователи редко задают сложные перекрестные вопросы к простым документам.
Как внедрить: пять шагов без кода
Я не буду давать вам Python-скрипт — конкретная реализация зависит от стека (LangChain, LlamaIndex, Handmade). Вместо этого — алгоритм действий, который вы адаптируете под себя.
1 Калибровка GI на выборке
Возьмите 100 документов из вашей базы. Вручную разметьте, какие из них «графопригодны» (требуют связей для ответов). Прогоните compact NER, посчитайте плотность, связность, энтропию. Подберите веса и порог так, чтобы метрика правильно классифицировала хотя бы 85% документов.
2 Интеграция Proxy-Pointer в пайплайн индексации
При загрузке нового документа: сначала GI. Если score >= порога — запускаете NER и построение указателей (только явные ссылки, без умозрительных семантических связей). Если score < порога — документ уходит в обычный векторный индекс.
3 Ретривальная стратегия
При запросе: сначала векторный поиск по всем документам. Получаете топ-K чанков. Для тех, что имеют Proxy-Pointer, догружаете графовые соседи (их немного, потому что граф скелетный). Скармливаете LLM смесь: контекст из чанков + графовый контекст из соседей.
4 Мониторинг и достройка
Логируйте случаи, когда ответ не найден или найден плохо. Анализируйте GI-score таких документов. Возможно, порог надо сдвинуть. Или добавить аномальный детектор: если пользователь задал сложный multi-hop запрос, и все чанки из «легких» документов — подгрузите больше контекста или вызовите NER на лету.
5 Оценка качества
Сравните точность и полноту для группы с полным графом и с Proxy-Pointer. В 90% случаев разница несущественна, а экономия — значительна. Как показывают кейсы CodeGraph, отказ от избыточного вызова моделей — главный резерв экономии.
Что может пойти не так: три грабли
Грабли №1. Заниженный порог GI. Если порог слишком низкий, вы строите граф для документов, где он не нужен, и экономия нулевая. Если слишком высокий — теряете релевантность на сложных запросах. Решение: A/B тестирование на исторических логах.
Грабли №2. Плохой compact NER. Если ваш быстрый NER (например, GLiNER) плохо находит юридические сущности (судебные решения, номера законов), то GI насчитает низкий score, и вы отправите важный документ в векторную пустоту. Проверяйте качество NER на своей предметной области.
Грабли №3. Динамическая природа связей. Юридические документы меняются: выходят новые редакции, появляются допсоглашения. Граф с Proxy-Pointer нужно перестраивать только при изменении документа, иначе указатели ведут в никуда. Внедрите триггер на обновление.
Неочевидный совет: смотрите в сторону agentic-подхода
В будущем дополнение Proxy-Pointer RAG агентной логикой — например, когда агент сам решает, нужен ли multi-hop для данного запроса, и если нет — вообще не лезет в граф. Это еще один слой экономии. Но это уже тема для отдельного разговора. Пока попробуйте GI — это не сломает существующую систему, а бюджет скажет спасибо.
Кстати, в обзоре свежих исследований RAG есть похожие идеи про контекстную обрезку графа — можете заглянуть для вдохновения.