- BrainTools - https://www.braintools.ru -

LLM-wiki против RAG: Оцениваем и сравниваем

Про LLM-wiki здесь уже было несколько хороших статей (1 [1], 2 [2] и 3 [3]), поэтому подробно останавливаться на идее [4] Andrej Karpathy не буду. В двух словах: вместо RAG-ретривера – wiki-агент, вместо чанков из сырых документов – связанные концепт-страницы, вместо обновления – перекомпиляция и поиск «битых» ссылок.

Насколько LLM-wiki лучше, или может быть хуже чем RAG, пусть даже простейший, с обычным векторным поиском? И как их можно сравнивать? Кажется, общепринятой методики оценки ещё не сложилось. Тем не менее я попробовал, и получил неожиданные результаты. Об этом и расскажу, а ещё о методике оценки, о wiki-агенте для тестов, о том что получилось, что – нет, и даже сколько это стоило.

Качество RAG систем в ряде методик определяется по оценке выдачи ретриверов с учетом вопроса и правильного ответа, однако прямо сравнить найденные в wiki страницы с чанками из RAG у меня не получилось. Поэтому я решил сравнивать ответы LLM, причём не между собой, а с эталоном. В качестве эталона выбрал ответ LLM, которая «видела» весь исходный текст целиком. Чтобы можно было посчитать метрики, пришлось из ответов сначала выделить факты. Получилось две группы сравнений – факты эталона с фактами из ответа на основе wiki и факты эталона с фактами от RAG-агента. Вот так выглядит архитектура получившейся у меня системы оценки:

Архитектура системы оценки

Архитектура системы оценки

Исходный текст

В качестве исходного текста во всех экспериментах был использован синтетический документ Директива 401, вымышленный корпоративный правовой акт, устанавливающий режим абсолютной собственности могущественного консорциума над клонированными и синтетическими живыми существами.

Пять глав и 24 статьи ледяного формализма с перекрестными ссылками. Документ охватывает два домена – корпоративное право и биотехнологии, даже скорее биопанк. Сама Директива была подготовлена gemma4:31b. Подробности здесь [5].

Вопросы для тестов

Все вопросы были синтезированы моделью gpt-5.1. Вместе с формулировкой модель возвращала перечень номеров статей, которые по её мнению использовались при синтезе. Я подготовил две группы вопросов – простые, фактологические, для них использовался контекст только одной статьи документа, и кейсовые. При генерации кейсов модель получала тему и видела весь документ. Сначала синтезировал по 40 вопросов каждого типа, отфильтровал несколько вопросов со слишком длинным перечнем использованных статей. Из оставшегося набора сделал выборку 20 + 20 и далее этот вопросник использовал во всех тестах.

Примеры формулировок

Факт-вопрос:
Опишите, какие обязанности возлагаются на Носителя в отношении процедуры инвентаризации белковых структур и какие последствия наступают в случае попытки препятствовать её проведению или искажать данные. Уточните, какие корпоративные структуры отвечают за техническую реализацию данной процедуры.

Кейс-вопрос:
Я на базовом тарифе, недавно система зафиксировала у меня метаболический дебит и «НЕЙРОКОМ» запустил протокол биологических санкций — этот ваш «Пульсирующий стресс». Я уже вышел в плюс по показателям и закрыл долг, но санкционный режим не снимается, а саппорт говорит, что я еще должен оплатить какой то «Пакет когнитивного восстановления». Насколько законно удерживать меня в этом состоянии после погашения дебита и могу ли я отказаться от оплаты этого пакета, раз санкции уже отыграли свою роль?

Wiki

Для построения wiki исходный документ был разбит на 25 частей: 24 статьи + титульный лист. Это было сделано, чтобы потенциальный wiki-агент мог обращаться к той или иной статье для уточнения или верификации. Далее я создал хранилище в Obsidian, добавил туда две папки raw и wiki, и в raw переписал все части исходного документа. Затем записал в хранилище файл AGENTS.md, который позаимствовал из репозитория [6] хабровчанина @chasing_nlp. Открыв новую сессию в Claude Code, привязал папку с хранилищем к сессии и попросил построить википедию в соответствие с инструкцией из AGENTS.md. Получилось 32 страницы, включая журнал изменений, индекс и список источников:

Wiki «Директива 401»

Wiki «Директива 401»

Весь процесс занял от силы 20 минут, а расход токенов не дотянул даже до половины пятичасового лимита. Общий размер контекста сессии – 208K. Для ориентира, исходный документ целиком – около 100К символов.

Wiki-агент

Мне трудно представить Claude Code в качестве ретривера для тестов, если это возможно технически, то как минимум, дорого. Поэтому я решил сделать собственный wiki-агент. Провёл несколько сессий с ответами по wiki, понял, какие инструменты нужны для агента и написал короткий бриф, a Claude помог сделать из этого полноценное ТЗ. Дальше мы вместе собрали агента за пару дней на базе langchain.agents и langchain_openai. Отдельное спасибо Claude за юнит-тесты.

Wiki-агент включает в себя четыре компонента – Навигатор по wiki, Линкер, Сборщик контекста и Синтезатор ответа:

Архитектура wiki-агента

Архитектура wiki-агента

Навигатор – это агент с инструментами на недорогой модели (gpt-4.1-mini), у него есть доступ к list_wiki_files, search_wiki и search_raw. Поиск – просто grep по файлам вики и исходникам. Работу с исходниками можно отключить в конфигурации. Задача Навигатора: вернуть список путей к релевантным файлам с кратким обоснованием. Ответ строго типизирован (Pydantic-схема с полями path, source, reason), своего рода адресная книга для следующего шага. На первом шаге Навигатор читает wiki-индекс и главную страницу. Этот контекст всегда подмешивается в первое сообщение в агентском цикле и Навигатор просто не может его игнорировать.

Первую версию Синтезатора я сделал в виде агента с более мощной моделью (gpt-4.1) и с возможностью ходить по вики-ссылкам. Здесь возникла проблема. Если оставить модели выбор, читать или нет найденные файлы через инструменты, она иногда «ленится» и несмотря на запрет в промпте, пишет правдоподобный ответ с якобы настоящими цитатами не обращаясь к файлам. Пришлось гарантировано подставлять содержимое всех файлов-кандидатов в Синтезатор через Сборщик контекста. В результате Синтезатор стал просто вызовом модели с промптом. Задача проверить вики-ссылки никуда не исчезла, я просто вынес её из Синтезатора в отдельный агент. Так появился Линкер. Его также можно отключить через параметр в конфигурации. Линкер работал на gpt-4.1-mini.

Страницы wiki ссылаются друг на друга в обе стороны. Чтобы Линкер не уходил в рекурсию, в wiki-агент добавлен модуль, который хранит набор «пройденных» путей и считает число обращений к инструментам. Я решил, что 20 обращений для небольшой wiki достаточно. Но этот лимит Линкер делит с Навигатором.

RAG-система

Во всех тестах была использована простейшая RAG-система с векторным ретривером на связке LangChain + ChromaDB + FastAPI. Сегментация исходного текста сделана по второму уровню нумерации в статьях документа. Комментарии юриста, встречающиеся в тексте, считались за отдельный чанк. Общее количество чанков – 144.

Единственное улучшение, которое я сделал для RAG – адаптивное количество чанков в выдаче. Решил, что будет некорректно зафиксировать max_k и считал его по формуле: количество уникальных положений второго уровня, использованных при синтезе вопроса, увеличенное на единицу. Список положений у меня уже был в вопроснике. Можно было бы собрать и адаптивный ретривер с LLM-судьёй, но я решил не усложнять.

Метрики и результаты

По традиции я считал две метрики – Precision и Recall для каждой пары ответов, соответствующих одному вопросу. Чтобы не было разночтений, Precision это доля фактов из ответа, совпадающих с эталоном, а Recall – доля фактов из эталона, покрытых ответом.

Попробовал разные конфигурации параметров, в итоге остановился на следующих вариантах:
1. Нет ни доступа к исходникам, ни линкера – “no_raw”
2. Есть доступ к исходникам, нет линкера – “raw”
3. Есть доступ к исходникам и линкер – “raw, linker”

Несмотря на установленный seed и нулевую температуру, ответы моделей несколько «плавали», поэтому для каждой конфигурации я сделал по три «прогона» для wiki-агента, у него самая длинная цепь моделей, а также каждый раз заново запускал экстракцию фактов и их сравнение. Эталонные ответы и ответы RAG от теста к тесту не менялись. Разброс значений метрик по таким ответам полностью определяется нестабильностью экстрактора фактов и LLM-судьи.

Disclaimer: Выводы далее касаются только результатов, полученных на наборе данных «Директива 401». В других доменах, с другим объемом текста и с другой структурой знаний результат может быть кардинально иным. Для использования wiki-агента с новым корпусом необходимо скорректировать промпты и указать актуальные индекс и hub-страницу wiki в конфигурации.

Вот так выглядят медианные значения метрик по трём конфигурациям, по три теста в каждой:

wiki-агент config

LLM-wiki

RAG

Precision

Recall

Precision

Recall

no_raw

0.718

0.727

0.688

0.538

raw

0.739

0.727

0.690

0.573

raw, linker

0.696

0.721

0.727

0.567

По этим цифрам можно заключить, что LLM-wiki работает не хуже чем вопрос-ответная система на базе RAG, а по полноте ответа – возможно и лучше. Это не вывод, а скорее гипотеза. Для статистической оценки значимости результатов я воспользовался парным непараметрическим критерием Уилкоксона.

Сравнение по полноте (recall):

N

config

median RAG

median WIKI

mean Δ

лучше/хуже/равно

Wilcoxon p

120

no_raw

0.538

0.727

+0.150

86 / 18 / 16

1.459e-11

120

raw

0.573

0.727

+0.146

81 / 20 / 19

1.206e-09

120

raw, linker

0.567

0.721

+0.121

74 / 34 / 12

4.418e-08

Wiki стабильно обгоняет RAG по полноте и это не статистический шум. Во всех трёх конфигурациях медианная полнота wiki держится около 0.72, у RAG 0.54-0.57. Парный тест по 120 наблюдениям даёт p-value от 10⁻⁸ до 10⁻¹¹ Разрыв воспроизводится не выборочно, а системно. Wiki выигрывает у RAG на конкретном вопросе примерно в 4 раза чаще, чем проигрывает.

Сравнение по точности (precision):

N

config

median RAG

median WIKI

mean Δ

лучше/хуже/равно

Wilcoxon p

120

no_raw

0.688

0.718

+0.056

65 / 54 / 1

0.009427

120

raw

0.690

0.739

+0.054

62 / 51 / 7

0.03212

120

raw, linker

0.727

0.696

+0.036

56 / 59 / 5

0.3484

По точности разрыв намного слабее. В базовых конфигурациях (no_raw, raw) wiki тоже немного лучше (p-value меньше 0.05). Эффект в разы меньше, чем влияние на полноту. А в конфигурации с линкером разница вообще пропадает и статистически неотличима от нуля. Wiki не «просто лучше по всем метрикам», выигрыш локализован в полноте ответа, а не в точности отбора контекста.

Линкер, дочитывающий пропущенные кросс-ссылки, не показал статистически значимого сдвига ни по точности, ни по полноте, ни в среднем по 40 вопросам, ни при разбивке на fact/case. Почему? Возможно, потому что срабатывает он лишь на 1/5–1/6 вопросов и эффект тонет в шуме на выборке. Плюс хотя бы в том, что его добавление в пайплайн ничего не сломало.

Влияет ли доступ к исходникам (raw)?

Query

Metric

median no_raw

median raw

mean Δ

лучше/хуже/равно

Wilcoxon p

fact

Recall

0.727

0.750

+0.032

29 / 19 / 12

0.065

fact

Precision

0.692

0.757

+0.047

35 / 22 / 3

0.071

case

Recall

0.727

0.692

−0.006

24 / 24 / 12

0.821

case

Precision

0.767

0.714

−0.028

27 / 33 / 2

0.213

Можно заключить, что доступ к исходникам реально помогает именно на фактографических вопросах. И это логично [7], там часто нужна точная формулировка статьи, а не компиляция. При этом выборки в 60 пар не хватает, чтобы формально подтвердить это на уровне p-value меньше 0.05. Эффект пограничный и недоказанный.

Примечание про N = 120

N = 120 в Wilcoxon-таблицах – 40 вопросов × 3 коррелированных «прогона». Это не 120 независимых наблюдений, реальное независимое N ближе к 40. И это нужно учитывать для пограничных значений p-value (0.065, 0.071, 0.032).

Немного про стоимость экспериментов

Стоимость построения wiki в Claude Code на Sonnet 5 для исходных файлов размером в 25K токенов составила менее 3.7 долларов. RAG-система работала локально на CPU с локальным эмбеддингом, поэтому ноль затрат.

Для доступа к GPT я пользовался прокси-провайдером. Самое дорогое занятие – генерация ответов по полному тексту документа. В начале процесса – по 6 рублей за вопрос, потом промпт видимо кешируется и стоимость падает до 1.5 руб. Ответы по RAG-контексту дешевле, что-то в районе 0.6 рублей, на заметку тем, кто рассматривает большое контекстное окно как потенциальную замену RAG.

«Прогон» на 40 вопросов через wiki-агент с доступом к исходным материалам оценивается примерно в 150 руб (3,75 за вопрос). Экстракция фактов – от 13 до 15 рублей на 40 вопросов с тремя ответами (wiki, rag, full_context), сравнение фактов стоило около 80 рублей.

Ссылки

  1. Репозиторий [8] wiki-агента, скрипты, бенчмарки и результаты оценки качества

  2. Репозиторий [9] RAG-системы

  3. Статья [5] про Директиву 401

  4. Парный непараметрический критерий Уилкоксона [10]

  5. Библиотека [11] для расчета критерия

  6. Примеры с langchain.agents [12]

Автор: khmelkoff

Источник [13]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/33096

URLs in this post:

[1] 1: https://habr.com/ru/articles/1031970/

[2] 2: https://habr.com/ru/articles/1047610/

[3] 3: https://habr.com/ru/companies/raft/articles/1054050/

[4] идее: https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f

[5] здесь: https://habr.com/ru/articles/1030684/

[6] репозитория: https://github.com/evylegzhanin/test-second-brain

[7] логично: http://www.braintools.ru/article/7640

[8] Репозиторий: https://github.com/khmelkoff/wiki-agent

[9] Репозиторий: https://github.com/khmelkoff/naive-rag-mcp

[10] критерий Уилкоксона: https://en.wikipedia.org/wiki/Wilcoxon_signed-rank_test

[11] Библиотека: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.wilcoxon.html

[12] langchain.agents: https://docs.langchain.com/oss/python/langchain/agents

[13] Источник: https://habr.com/ru/articles/1058252/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1058252

www.BrainTools.ru

Rambler's Top100