RAG простыми словами: что это и когда он не нужен
RAG — это поиск плюс подстановка найденного в запрос. Разбираю, из чего он состоит, где ломается каждое звено и почему на небольшой базе он только вредит.
Короткий ответ: RAG (retrieval-augmented generation) — это когда перед обращением к модели вы ищете подходящие куски в своей базе и кладёте их прямо в запрос. Модель отвечает по приложенному тексту, а не по памяти. Никакого обучения при этом не происходит: база и модель остаются независимыми, и обновить базу можно за секунду.
И сразу вторая половина ответа, которую в руководствах обычно опускают: если ваши документы помещаются в контекстное окно целиком, RAG не нужен. Он добавляет звено поиска, а звено поиска умеет ошибаться.
Из чего он состоит
Четыре шага, и у каждого своя цена ошибки.
Нарезка. Документы режутся на куски. Это единственный шаг, который делается один раз и определяет потолок качества всей системы: если кусок разрезан посреди мысли, никакой поиск потом не соберёт её обратно.
Индексация. Каждый кусок превращается в вектор и кладётся в базу.
Поиск. Вопрос превращается в вектор, из базы достаются ближайшие куски.
Подстановка. Найденное кладётся в запрос вместе с вопросом, и модель отвечает.
Где ломается каждое звено
Нарезка — самое дорогое место, и его чинят последним. Я измерил это на собственном корпусе: при фиксированной нарезке по 500 знаков 95% смысловых разделов оказываются разрезаны между кусками, а 54% кусков не содержат ни одного заголовка. Ретривер приносит половину ответа, модель достраивает вторую половину сама. Подробности и цифры — в «Метрики поиска без магии».
Индексация промахивается по домену. Модель эмбеддингов, обученная на общем вебе, разложит ваши внутренние термины по общему смыслу слов. «Карточка» в вашей компании — конкретный документ, для модели это что-то между визиткой и банковской картой.
Поиск не видит отрицания. «Возврат возможен» и «возврат невозможен» употребляются в одинаковых контекстах и оказываются рядом в векторном пространстве. Для поиска они взаимозаменяемы, для пользователя — противоположны. Разбирал это подробно в «Эмбеддинги: что они меряют».
Ответ достраивает пропуск. Если в найденном куске половина ответа, модель допишет вторую по правдоподобию.
Когда RAG не нужен
Три случая, и они встречаются чаще, чем кажется.
Документов мало. Если вся база помещается в контекстное окно — кладите её целиком. Сотня страниц регламентов сегодня влезает в окно без всякого поиска, и вы разом убираете два звена из четырёх. Дороже по токенам, зато нечему промахнуться.
Данные не меняются и их немного. Тогда нужное можно просто зашить в системную часть запроса, где оно ещё и попадёт в кеш префикса — то есть будет стоить в разы дешевле.
Вопросы не про поиск. RAG отвечает на «что написано про X». Он не отвечает на «сколько всего договоров с просрочкой» — это запрос к базе данных, и никакой векторный поиск его не заменит. Смешение этих двух типов вопросов — самая частая причина, по которой «RAG не работает».
Что усиливает RAG сильнее смены модели
Порядок по отношению эффекта к трудозатратам:
- Резать по структуре, а не по счётчику знаков.
- Приклеивать путь заголовков к каждому куску: десять строк кода.
- Складывать с полнотекстовым поиском — векторный теряет артикулы, коды ошибок и названия функций.
- Ставить реранкер на полсотни кандидатов.
- Требовать цитату-основание в ответе, чтобы проверка была механической.
Смена модели эмбеддингов в этом списке отсутствует намеренно: на моей практике до неё доходит редко.
Условие несогласия
Если ваш контент на языке или в узком домене, который модель почти не видела при обучении, порядок меняется: смена модели эмбеддингов становится первым пунктом, а не последним. Проверяется за полчаса — возьмите двадцать реальных вопросов и посмотрите выдачу. Если она выглядит случайной, а не «похожей, но не той», дело в модели.
Чего я делать не стал бы
Не стал бы поднимать RAG раньше, чем появились двадцать реальных вопросов от людей. Без них вы будете настраивать поиск под вопросы, которые придумали сами, — а они всегда удобнее настоящих.
Не стал бы увеличивать k, чтобы «наверняка попало». В контекст приедет двадцать кусков, из которых девятнадцать не по делу, и качество ответа упадёт по причине, которая выглядит как проблема модели.
Не стал бы хранить векторы без исходного текста рядом. Рано или поздно придётся пересчитать всё на другой модели, и без исходников это отдельный проект.
Открытый вопрос
Нарезка по структуре опирается на то, что структура есть. В аккуратной документации она есть; в переписке, расшифровках созвонов и выгрузках из старых систем — нет. Модель, которую просят расставить границы, справляется прилично, но это ещё один вызов на каждый документ при загрузке, и я не знаю, окупается ли он: эталонной нарезки для такого текста никто не размечал, а значит сравнить не с чем.