← Назад к статьям

Всё ещё ли нужен RAG?

технологии
llmragcontext

Существует фундаментальная истина о больших языковых моделях (LLM): они «заморожены во времени». Они знают всё о нашем мире вплоть до даты окончания своего обучения - и абсолютно ничего о том, что произошло пять минут назад. Равно как и ничего о ваших приватных данных, внутренних вики-системах или проприетарной кодовой базе. И если мы хотим, чтобы модель обладала доступом к любой из этой информации, нам необходимо решить задачу инъекции контекста: как доставить нужные данные в модель в нужный момент?

На сегодняшний день существуют два принципиально разных подхода к решению этой задачи.

Retrieval-Augmented Generation

Первый - это, условно говоря, инженерный путь: RAG, или Retrieval-Augmented Generation (генерация с подкреплением извлечением). Схема выглядит так: у нас есть LLM и входящий пользовательский запрос. Заранее мы берём документы, которые хотим предоставить модели - это могут быть PDF-файлы, исходный код или целые книги - разбиваем их на небольшие фрагменты (чанки) и пропускаем через эмбеддинг-модель. Эта модель преобразует фрагменты в векторы, которые затем сохраняются в специализированной векторной базе данных.

Когда пользователь задаёт вопрос, система выполняет семантический поиск, извлекает наиболее релевантные фрагменты и встраивает их в контекстное окно модели. Таким образом, контекстное окно содержит не только пользовательский запрос, но и все извлечённые из векторной базы фрагменты - вместе они формируют итоговый контекст.

Этот подход работает, но опирается на одно важное допущение: что ваша логика извлечения действительно нашла нужную информацию в векторной базе.

Long Conext

Второй подход - более «грубый», но при этом нативный для самой модели. Он называется «длинный контекст» (Long Context). Здесь мы полностью обходимся без базы данных и эмбеддинг-модели: просто берём документы и загружаем их напрямую в контекстное окно, позволяя механизму внимания модели самостоятельно проделать тяжёлую работу по поиску ответа.

Долгое время такой «силовой» метод был практически нереализуем: изначально контекстные окна были крошечными. Ранние LLM поддерживали всего около 4 тысяч токенов - туда не поместится даже роман, не говоря уже о корпоративной базе знаний. Приходилось использовать RAG. Однако современные модели обладают значительно более вместительными контекстными окнами: некоторые поддерживают свыше миллиона токенов.

Для наглядности: миллион токенов - это примерно 700 тысяч слов. В такой промпт можно уместить всю трилогию «Властелин колец» и ещё останется место для «Хоббита».

Столь резкий скачок в возможностях заставляет нас задаться сложным архитектурным вопросом: если мы можем просто скопировать всю документацию в контекстное окно модели, действительно ли нам по-прежнему нужна инфраструктурная нагрузка в виде эмбеддинг-моделей и векторных хранилищ? Не становится ли RAG излишним уровнем сложности?

Если допустить, что любые необходимые данные действительно помещаются в контекстное окно, то алгоритм работы сводится к одному слову: простота. Три аргумента в пользу того, что прямая загрузка контекста может оказаться оптимальным решением.

Аргумент первый: упрощение инфраструктуры.

Продакшн-система на базе RAG - это серьёзная инженерная нагрузка. Вам нужна стратегия чанкинга: фиксированный размер, скользящее окно или рекурсивное разбиение? Потребуется эмбеддинг-модель для кодирования данных, векторная база для их хранения, реранкер для сортировки результатов. Необходимо постоянно синхронизировать векторы с исходными данными. В итоге - множество движущихся частей и точек отказа.
Long Context предлагает то, что можно назвать «стек без стека»: убираем базу данных, эмбеддинги, логику извлечения. Архитектура сводится к простой задаче: получить данные и отправить их модели.

Аргумент второй: «лотерея извлечения».

RAG вносит критическую точку отказа - сам этап извлечения. Когда пользователь задаёт вопрос, система работает с математическими представлениями данных - векторами, то есть последовательностями чисел в массиве - и пытается найти ближайшее совпадение. Это и есть семантический поиск. Но он вероятностный по своей природе. По множеству причин процесс извлечения может не найти релевантный документ. У этого явления даже есть название - «тихий сбой» (silent failure): ответ существовал в данных, но модель его не увидела, потому что этап извлечения вернул неверные результаты.В подходе Long Context этапа извлечения просто нет: модель видит всё.

Аргумент третий: проблема «целой книги» и смещение полноты.

RAG по своей сути предназначен для извлечения того, что уже существует: он ищет семантическое соответствие между запросом и конкретным фрагментом текста в базе. Но что, если ответ кроется в том, чего в базе нет?
Представим: у вас есть документ с требованиями к продукту и отдельно - документ с релиз-нотами. Вы спрашиваете: «Какие требования по безопасности были упущены в финальном релизе?»

При использовании RAG векторный поиск найдёт фрагменты, где упоминаются «безопасность» и «требования», извлечёт отрывки из обоих документов - но не сможет извлечь разрыв между ними. RAG показывает модели лишь изолированные «снимки», не давая ей увидеть целостную картину, необходимую для выявления пробелов. Чтобы выполнить сравнение, модели действительно нужны оба документа целиком - именно это и обеспечивает Long Context, загружая «всю книгу»: полные требования и полные релиз-ноты - в контекстное окно.

Значит ли это, что RAG мёртв и векторные базы данных отправляются в музей технологий 2024 года? Не совсем. Несмотря на преимущества Long Context в простоте, у RAG по-прежнему есть своё место. И вот ещё три аргумента в его поддержку.

Аргумент первый: повторное чтение текста.

Long Context создаёт серьёзную вычислительную неэффективность. Возьмём, к примеру, руководство на 500 страниц - это порядка 250 тысяч токенов. Если вы помещаете этот документ в промпт при каждом пользовательском запросе, модель вынуждена обрабатывать его заново каждый раз.
RAG тоже должен обработать руководство, но платит за это лишь единожды - на этапе индексации. Кэширование промптов может частично компенсировать затраты для статичных данных, но для динамических потоков, где контент часто меняется, вы вынуждены платить полную «цену» при каждом запросе.

Аргумент второй: проблема «иголки в стоге сена».

Интуитивно кажется: если данные находятся в контекстном окне, модель обязательно их использует. Однако исследования показывают обратное. По мере роста контекста - скажем, до 500 тысяч токенов - механизм внимания модели может «размываться». Если вы зададите конкретный вопрос об одном абзаце, затерянном где-то в середине 2000-страничного документа, модель часто либо не найдёт его, либо начнёт «галлюцинировать», выдумывая детали из окружающего текста.
В RAG мы подаём модели меньше «шума»: извлекая, скажем, только топ-5 наиболее релевантных фрагментов, мы убираем «стог сена» и оставляем только «иголки». Это заставляет модель фокусироваться на сигнале, а не на фоне.

Аргумент третий: бесконечный объём данных.

Контекстное окно в миллионы токенов звучит впечатляюще, но в масштабах корпоративных данных это - капля в море. Корпоративное озеро данных, как правило, измеряется в терабайтах, а то и петабайтах. Если вы хотите работать с по-настоящему безграничным набором данных, вам действительно необходим уровень извлечения, который отфильтрует информацию до объёма, помещающегося в контекстное окно LLM.

Так где же мы оказываемся в итоге?

Если ваша задача работает с ограниченным набором данных и требует сложного глобального анализа - например, изучение конкретного юридического контракта или суммаризация книги - я считаю, что Long Context будет оптимальным выбором. Он упрощает стек технологий и улучшает качество рассуждений модели.

Но если вам приходится искать по бесконечному пространству корпоративных знаний, векторная база данных остаётся единственным жизнеспособным хранилищем для ваших данных.

Поделиться