RAG (Retrieval Augmented Generation) — это техника, которая подмешивает к вопросу пользователя свежую или специфичную информацию из внешних источников. Всё вместе отправляется в языковую модель, и она выдаёт ответ, опираясь именно на эти данные.
Проще говоря, вы берёте вопрос, находите к нему нужную справку, склеиваете их в один пакет и скармливаете нейросети. Она уже не гадает, а отвечает по фактам, которые вы ей подсунули.
Живой пример. Представьте, что кто-то спрашивает: «Какой сейчас курс доллара?» Модель понятия не имеет — у неё нет доступа к биржевым котировкам. Но мы можем на лету открыть сайт ЦБ, вытащить оттуда цифры и склеить их с вопросом. Модель увидит вопрос и эти цифры и скажет: «Сейчас доллар стоит столько-то». Вуаля.
Пример посерьёзнее. Допустим, вы делаете чат-бота для техподдержки. У вас есть база знаний — куча статей с ответами на частые вопросы. Если пользователь спрашивает «Как сбросить пароль?», вы находите в базе нужную статью, добавляете её текст к вопросу и отдаёте модели. Она читает статью и формирует чёткую пошаговую инструкцию. Гораздо дешевле и быстрее, чем переобучать модель под каждое обновление базы знаний.
Почему «просто найти и добавить» — только начало
>Когда я объясняю RAG новичкам, они часто говорят: «Ну и что тут сложного? Нашёл кусок текста, подложил модели — и готово». И они правы — в теории всё просто. На практике же сразу вылезает куча нюансов.
Вот три проблемы, с которыми вы столкнётесь на первом же часе работы:
Нечёткий поиск. Если пользователь написал «как восстановить доступ», а в базе статья называется «Сброс пароля», точное совпадение не сработает. Нужен умный поиск по смыслу, а не по буквам.
>Размер кусков. На какие куски резать статьи? Слишком маленькие — потеряете смысл. Слишком большие — модель захлебнётся информацией и начнёт путаться.
>Много статей. Что, если по запросу нашлось пять подходящих кусков, и все длинные? Как их склеить, чтобы не переполнить контекстное окно модели?
>Это только вершина айсберга. Но хорошая новость в том, что уже есть базовый рецепт, с которого можно начать. А дальше — как в сборке мебели из Икеи: берёте готовую конструкцию и начинаете её дорабатывать под себя.
Как устроен стандартный RAG-пайплайн (тот самый «паровоз»)
Если говорить сухо, алгоритм выглядит так:
Берёте всю базу знаний и режете её на небольшие фрагменты — чанки. Обычно по 100–1000 слов, от пары строк до нескольких абзацев.
>Каждый чанк прогоняете через специальную модель — эмбеддер. Она превращает текст в набор чисел (вектор). Считается, что в этих числах закодирован смысл фрагмента.
>Все векторы складываете в базу данных — векторное хранилище.
>Когда приходит запрос от пользователя, вы точно так же превращаете его вопрос в вектор.
>Затем ищете в хранилище векторы, наиболее близкие к вектору вопроса (обычно по косинусной близости). Достаёте соответствующие им чанки.
>Склеиваете эти чанки с вопросом пользователя и отправляете всё вместе в большую языковую модель.
>Модель получает не просто вопрос, а вопрос плюс релевантные материалы. Она отвечает, опираясь на них.
Вроде бы просто. И во многих библиотеках этот пайплайн уже реализован «из коробки». Но, как вы догадываетесь, в реальности первый же запуск покажет, что всё работает совсем не так, как вы хотели.
Допиливаем RAG: где собака зарыта
Начинается самое интересное — настройка. Вот основные рычаги, за которые придётся дёргать, чтобы система заработала как надо.
Размер чанков и их количество. Это первый и самый важный пункт. Если подадите слишком много мусора — модель запутается. Если слишком мало — ей будет нечем ответить. Экспериментируйте: маленькие чанки дают точное попадание, большие — более глубокий смысл. Также важно, чтобы чанки частично перекрывали друг друга, иначе вы рискуете вырвать фразу из середины абзаца, где теряется половина смысла. И обязательно следите, чтобы чанк начинался и заканчивался на естественной границе — лучше всего на абзаце.
Поиск не только по смыслу. Бывает, что векторный поиск (по эмбеддингам) плохо находит специфические термины или сокращения. Тогда подключают классические методы вроде TF‑IDF или ранжирование по BM25. Объединяют результаты в определённой пропорции — и это даёт более стабильный результат.
Перефразировка запроса. Один запрос можно превратить в три-пять вариантов (с помощью той же LLM) и искать чанки по каждому из них. Затем объединить найденное. Часто это повышает полноту поиска.
Сжатие найденного. Если чанков набралось слишком много и они не влезают в контекст, можно попросить LLM сделать краткую выжимку из них и подать уже эту сжатую версию. Так вы сохраняете суть, не теряя главного.
Дообучение модели под RAG. Можно объяснить модели в системном промпте, что она получает две части: вопрос и контекст. А можно даже дообучить её на специальных примерах, чтобы она привыкла к такому формату. На старте чаще всего хватает грамотного системного промпта.
Как проверить, что RAG работает хорошо
Самая частая ошибка начинающих — настраивать всё на глазок и проверять ответы вручную на паре-тройке примеров. Это путь в никуда.
Вы будете менять размер чанков, эмбеддер, модель генерации — и каждый раз нужно проверять, улучшился ли результат. И проверять надо не на трёх вопросах, а на десятках, а лучше сотнях. Вручную это нереально.
Что делают профессионалы:
Пишут тестовые вопросы. Их должны составлять люди — вы или ваши заказчики, потому что только они знают, что будут спрашивать.
>Готовят эталонные («золотые») ответы. Их тоже пишут люди, а если сил нет — можно воспользоваться ассистентами OpenAI на мощных моделях, но несколько раз прогнать один и тот же вопрос и усреднить.
>Сравнивают ответы модели с эталонами. Используют специальные метрики: BERTScore, BLEURT, METEOR или даже старый добрый ROUGE. Из них собирают что-то вроде средневзвешенной оценки, которая показывает, насколько ответ похож на идеальный.
>И самое важное: не забывайте проверять, что именно нашёл ретривер. Ведь 80% качества ответа зависит от того, насколько релевантные куски вы подали модели на вход. Поэтому сначала настройте поиск чанков, а уже потом — генерацию ответов.
Вместо заключения
>RAG — это не магия и не rocket science. Это набор простых итераций: режете текст, ищете по смыслу, склеиваете, подаёте модели, смотрите на результат, меняете параметры и повторяете. Дьявол, как водится, в деталях, но если у вас есть терпение и системный подход — у вас всё получится.
