Про LLM-wiki здесь уже было несколько хороших статей (1, 2 и 3), поэтому подробно останавливаться на идее Andrej Karpathy не буду. В двух словах: вместо RAG-ретривера – wiki-агент, вместо чанков из сырых документов – связанные концепт-страницы, вместо обновления – перекомпиляция и поиск «битых» ссылок.
Насколько LLM-wiki лучше, или может быть хуже чем RAG, пусть даже простейший, с обычным векторным поиском? И как их можно сравнивать? Кажется, общепринятой методики оценки ещё не сложилось. Тем не менее я попробовал, и получил неожиданные результаты. Об этом и расскажу, а ещё о методике оценки, о wiki-агенте для тестов, о том что получилось, что – нет, и даже сколько это стоило.
Качество RAG систем в ряде методик определяется по оценке выдачи ретриверов с учетом вопроса и правильного ответа, однако прямо сравнить найденные в wiki страницы с чанками из RAG у меня не получилось. Поэтому я решил сравнивать ответы LLM, причём не между собой, а с эталоном. В качестве эталона выбрал ответ LLM, которая «видела» весь исходный текст целиком. Чтобы можно было посчитать метрики, пришлось из ответов сначала выделить факты. Получилось две группы сравнений – факты эталона с фактами из ответа на основе wiki и факты эталона с фактами от RAG-агента. Вот так выглядит архитектура получившейся у меня системы оценки:
Исходный текст
В качестве исходного текста во всех экспериментах был использован синтетический документ Директива 401, вымышленный корпоративный правовой акт, устанавливающий режим абсолютной собственности могущественного консорциума над клонированными и синтетическими живыми существами.
Пять глав и 24 статьи ледяного формализма с перекрестными ссылками. Документ охватывает два домена – корпоративное право и биотехнологии, даже скорее биопанк. Сама Директива была подготовлена gemma4:31b. Подробности здесь.
Вопросы для тестов
Все вопросы были синтезированы моделью gpt-5.1. Вместе с формулировкой модель возвращала перечень номеров статей, которые по её мнению использовались при синтезе. Я подготовил две группы вопросов – простые, фактологические, для них использовался контекст только одной статьи документа, и кейсовые. При генерации кейсов модель получала тему и видела весь документ. Сначала синтезировал по 40 вопросов каждого типа, отфильтровал несколько вопросов со слишком длинным перечнем использованных статей. Из оставшегося набора сделал выборку 20 + 20 и далее этот вопросник использовал во всех тестах.
Примеры формулировок
Факт-вопрос:
Опишите, какие обязанности возлагаются на Носителя в отношении процедуры инвентаризации белковых структур и какие последствия наступают в случае попытки препятствовать её проведению или искажать данные. Уточните, какие корпоративные структуры отвечают за техническую реализацию данной процедуры.
Кейс-вопрос:
Я на базовом тарифе, недавно система зафиксировала у меня метаболический дебит и «НЕЙРОКОМ» запустил протокол биологических санкций — этот ваш «Пульсирующий стресс». Я уже вышел в плюс по показателям и закрыл долг, но санкционный режим не снимается, а саппорт говорит, что я еще должен оплатить какой то «Пакет когнитивного восстановления». Насколько законно удерживать меня в этом состоянии после погашения дебита и могу ли я отказаться от оплаты этого пакета, раз санкции уже отыграли свою роль?
Wiki
Для построения wiki исходный документ был разбит на 25 частей: 24 статьи + титульный лист. Это было сделано, чтобы потенциальный wiki-агент мог обращаться к той или иной статье для уточнения или верификации. Далее я создал хранилище в Obsidian, добавил туда две папки raw и wiki, и в raw переписал все части исходного документа. Затем записал в хранилище файл AGENTS.md, который позаимствовал из репозитория хабровчанина @chasing_nlp. Открыв новую сессию в Claude Code, привязал папку с хранилищем к сессии и попросил построить википедию в соответствие с инструкцией из AGENTS.md. Получилось 32 страницы, включая журнал изменений, индекс и список источников:
Весь процесс занял от силы 20 минут, а расход токенов не дотянул даже до половины пятичасового лимита. Общий размер контекста сессии – 208K. Для ориентира, исходный документ целиком – около 100К символов.
Wiki-агент
Мне трудно представить Claude Code в качестве ретривера для тестов, если это возможно технически, то как минимум, дорого. Поэтому я решил сделать собственный wiki-агент. Провёл несколько сессий с ответами по wiki, понял, какие инструменты нужны для агента и написал короткий бриф, a Claude помог сделать из этого полноценное ТЗ. Дальше мы вместе собрали агента за пару дней на базе langchain.agents и langchain_openai. Отдельное спасибо Claude за юнит-тесты.
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 |
Можно заключить, что доступ к исходникам реально помогает именно на фактографических вопросах. И это логично, там часто нужна точная формулировка статьи, а не компиляция. При этом выборки в 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 рублей.
Ссылки
-
Репозиторий wiki-агента, скрипты, бенчмарки и результаты оценки качества
-
Репозиторий RAG-системы
-
Статья про Директиву 401
-
Парный непараметрический критерий Уилкоксона
-
Библиотека для расчета критерия
-
Примеры с langchain.agents
Автор: khmelkoff


