Corrective RAG: как исправлять плохой поиск — это подход, при котором качество найденных документов оценивают до генерации ответа и по оценке выбирают действие: принять, переписать запрос, искать вовне или остановиться. Ниже — разбор исходного алгоритма, прикладных упрощений и заполненный учебный пример.
Зачем исправлять retrieval до генерации
Генератор опирается на то, что ему передали. Если в контекст попал нерелевантный фрагмент, модель либо ответит по нему, либо начнёт достраивать пробел собственными параметрами. Первичная работа Yan и соавторов прямо связывает это с галлюцинациями: точность сгенерированного текста нельзя обеспечить только параметрическими знаниями модели. RAG задуман как дополнение к модели, но он «опирается на релевантность найденных документов», и авторы ставят вопрос, как ведёт себя модель, когда поиск сработал плохо.
Отсюда практический вывод: точка контроля находится между поиском и генерацией. Пока документы ещё не превратились в ответ, их можно отбросить, заменить или дополнить. После генерации исправлять дороже — придётся либо переписывать ответ, либо объяснять пользователю, почему он неверен.
В исходной работе для этого вводится лёгкий evaluator релевантности. Он оценивает общее качество найденных документов под конкретный запрос и возвращает степень уверенности, по которой запускаются разные действия с знаниями. Это отдельный компонент: он смотрит на пару «запрос — документы» и выносит решение о качестве выдачи.
Практический смысл для команды: появляется измеримая точка, где можно вмешаться. Логируется, что именно вернул поиск, как это оценено и какое действие выбрано. Без такой точки плохой ответ невозможно отличить от плохого поиска, и любая правка превращается в угадывание.
Исследовательские Correct, Incorrect и Ambiguous
В репозитории CRAG подготовка знаний разбита на три ветки: correct, incorrect и ambiguous. Команда run_knowledge_preparation.sh собирает знания для инференса по этим трём классам, а каждый класс можно запустить отдельно.
Для класса correct документы декомпозируются, и нерелевантные части отфильтровываются. В README перечислены три режима разбиения пассажей: fixed_num режет текст на фиксированное число слов, excerption делит по границам предложений, а selection оставляет пассаж целиком. Режим задаётся параметром --decompose_mode.
Для класса incorrect применяются переформулировка вопроса и веб-поиск. Здесь нужны openai_api_key и search_key; в эксперименте авторы использовали стороннюю платформу Google Search API. Доступны два режима: wiki в первую очередь обходит страницы, связанные с Википедией, а all обходит все страницы одинаково.
Класс ambiguous собирается объединением: combined_knowledge_preparation.py берёт пути к correct и incorrect и формирует ambiguous. Логика здесь та же, что и в исходной статье: неоднозначная выдача получает смешанный набор знаний.
Важное различие для читателя: это исследовательский код с обучением evaluator и подготовкой данных. В README описаны отдельные шаги — препроцессинг данных, дообучение evaluator, подготовка знаний, инференс CRAG и Self-CRAG, оценка. Каждый шаг запускается своим скриптом.
Что упрощают прикладные workflow
Прикладные реализации сокращают исходную схему. В документации LlamaIndex corrective RAG описан как последовательность шагов: загрузка данных в индекс и настройка Tavily, поиск наиболее релевантных узлов, оценка релевантности через LLM, извлечение релевантных узлов, преобразование запроса и веб-поиск, генерация ответа. Если узел признан нерелевантным, LLM переписывает запрос под веб-поиск, и Tavily ищет ответ.
Оценка в этом примере бинарная. Промпт-шаблон просит выставить оценку yes или no и отдельно оговаривает, что проверка не должна быть чрезмерно строгой: цель — отсеять явно нерелевантные результаты. Это заметно проще трёх классов исходной работы.
Ветвление тоже устроено иначе. В коде LlamaIndex веб-поиск запускается, если хотя бы один документ получил no: проверка идёт по строке if "no" in relevancy_results. В исходном CRAG действие выбирается по степени уверенности evaluator.
В CRAG отдельный evaluator оценивает найденные документы и направляет пересборку знаний перед генерацией. По разбору LangChain, Self-RAG использует обученные reflection-токены на нескольких стадиях: решает, нужен ли поиск, оценивает релевантность документов, опору и полезность генерируемого текста. Сравнивать подходы следует по этим механизмам управления поиском и генерацией.
Заполненная таблица маршрутов по базе Руты
Возьмём учебную базу D-ruta. В ней лежит строка: «Команда Рута принимает заявки через форму поддержки. Внутренний регламент хранится только в корпоративной базе». Запрос пользователя: «Куда отправить заявку Руты?»
| Что вернул поиск | Оценка | Действие | Результат |
|---|---|---|---|
| Строка D-ruta про форму поддержки | Релевантно | Сохранить строку, подготовить ответ | Ответ с document_id |
| Реклама другой команды | Нерелевантно | Переписать запрос на «Рута форма поддержки», повторить поиск по разрешённой базе | Новая выдача по тому же вопросу |
| Текущая и архивная инструкции без явной даты | Неоднозначно | Запросить актуальный документ | Документы не смешиваются молча |
| Ничего по вопросу о сроке ответа | Пробел | Остановиться | Сообщение о пробеле |
Внешний поиск в этом сценарии запрещён владельцем базы. Это настройка конкретного примера: исходный CRAG как раз расширяет поиск веб-запросами, когда статичный корпус даёт лишь субоптимальные документы.
Третья строка таблицы — самая частая ловушка. Два противоречащих документа без версий не позволяют выбрать действующий, и молчаливое смешивание даёт ответ, который выглядит уверенным, но опирается на устаревшую инструкцию. Правильное действие — запросить актуальный документ.
Уточнение запроса, выбор источников и граница внешнего поиска
Переформулировка запроса — не косметика. В LlamaIndex для неё есть отдельный шаблон: модель должна понять смысловой интент исходного вопроса и переписать его так, чтобы поиск сработал лучше, ответ — только оптимизированный запрос. В учебном сценарии задаём плохую выдачу для вопроса «Куда отправить заявку Руты?» и выбираем новую формулировку «Рута форма поддержки» для повторного поиска. Читатель проверяет, вернулась ли нужная строка. Редакция workflow не запускала.
Выбор источников определяется политикой владельца базы. В учебном сценарии разрешён повторный поиск по внутренней базе, а внешний поиск закрыт. В исходном CRAG веб-поиск — штатное расширение, потому что статичный ограниченный корпус возвращает лишь субоптимальные документы. Прикладной пример LlamaIndex тоже ходит в Tavily, когда находит нерелевантный узел.
Границу внешнего поиска задают явно и до запуска. Если база содержит внутренние регламенты, веб-поиск может принести внешние советы, которые противоречат внутреннему порядку. Тогда внешний канал либо выключают, либо ограничивают списком доменов, либо помечают результаты как внешние и не смешивают их с внутренними документами в одном ответе.
Промпт для переформулировки запроса под поиск:
Ты готовишь поисковый запрос для внутренней базы знаний.
Исходный вопрос: [вопрос пользователя]
Перепиши его так, чтобы поиск вернул нужный документ.
Сохрани смысл вопроса, убери разговорные обороты, добавь
ключевые термины организации, если они известны.
Верни только переформулированный запрос, без пояснений.
Под себя меняют [вопрос пользователя] и список известных терминов организации. Варианты той же задачи: переформулировка под архивную базу, переформулировка с указанием отдела, переформулировка под поиск по номерам документов, переформулировка для внешнего поиска с ограничением по домену.
Условия остановки при недостающей или противоречивой информации
Остановка — полноценный исход маршрута. В учебном примере запрос о неизвестном сроке ответа заканчивается сообщением о пробеле: база не содержит срока, и повторный поиск по ней ничего не добавит.
Условия остановки формулируют заранее, до запуска. Первое: повторный поиск по разрешённой базе не дал новых документов. Второе: найденные документы противоречат друг другу, а версии или даты отсутствуют. Третье: вопрос выходит за границы базы, а внешний поиск закрыт политикой. Четвёртое: исчерпан предел повторов.
Предел одного повторного поиска задан только для учебного сценария. В рабочей системе число повторов задают отдельно и логируют, чтобы маршрут не зацикливался.
Сообщение о пробеле должно быть полезным. Вместо общего «не найдено» лучше указать, что именно искали, по какой базе и что нужно уточнить у владельца документа. Тогда пользователь понимает следующий шаг, а команда видит, каких документов не хватает.
Как измерять релевантность и качество итогового ответа отдельно
Две метрики живут в разных местах и не заменяют друг друга. Релевантность измеряют на выходе поиска: evaluator сравнивает пару «запрос — документы» и выносит оценку. Качество ответа измеряют на выходе генератора: соответствует ли текст исходному вопросу и опирается ли он на переданные документы.
Карточка журнала для каждого прохода содержит исходный вопрос, источник, оценку релевантности с коротким основанием, выбранное действие и итоговую ссылку на документ. Такая карточка позволяет разобрать инцидент: был ли поиск плохим, была ли оценка неверной или генератор ушёл от контекста.
Числовой порог classifier не задают без собственной калибровки. Бинарная оценка из примера LlamaIndex и три класса исходной работы — разные схемы, и переносить пороги между ними нельзя.
Для оценки ответов в репозитории CRAG предлагается отдельный инструмент: для Bio-датасета авторы отсылают к официальному репозиторию FactScore и команде factscore.factscorer. В README отмечено, что прежние результаты FactScore получены на text-davinci-003, который заменён на gpt-3.5-turbo-instruct, поэтому оценка может отличаться. Для остальных датасетов запускается run_eval.sh с метрикой match.
Частые вопросы
Что такое Corrective RAG простыми словами?
Это надстройка над RAG, которая оценивает качество найденных документов до генерации ответа и по этой оценке выбирает действие. Если выдача релевантна, документы идут в генератор. Если нет — запрос переписывают, ищут заново или останавливаются с сообщением о пробеле.
Чем CRAG отличается от Self-RAG?
В CRAG отдельный evaluator направляет исправление найденных знаний перед генерацией. Self-RAG использует обученные reflection-токены для решения о поиске, проверки релевантности документов, опоры и полезности генерации.
Обязателен ли веб-поиск в Corrective RAG?
В исходной работе веб-поиск — штатное расширение, потому что статичный корпус даёт субоптимальные документы. В учебном примере с базой Руты внешний поиск закрыт политикой владельца. Границу внешнего поиска задают под конкретную базу.
Что делать, если поиск вернул два противоречащих документа?
Запросить актуальный документ. Два противоречащих документа без версий не позволяют выбрать действующий, и молчаливое смешивание даёт уверенный ответ на устаревшей инструкции. В журнал записывают оба источника и выбранное действие.
Как понять, что пора остановить исправление?
Когда повторный поиск по разрешённой базе не дал новых документов, найденные документы противоречат друг другу без версий, вопрос выходит за границы базы или исчерпан предел повторов. Маршрут заканчивается сообщением о пробеле с указанием, что именно искали.
