Про 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
