Вы спрашиваете ассистента: «что мы решили по проекту в апреле» — и получаете уверенный, связный, полностью выдуманный ответ. Тот же ассистент на вопрос «сколько будет 17 % от 4200» отвечает верно. Разница не в сложности вопроса. Разница в том, что во втором случае вся нужная информация была в самом вопросе, а в первом — лежала где-то в архиве, и никто её оттуда не достал.
RAG — это механизм, который её достаёт. И его полезно понимать не как «технологию», а как конвейер с тремя местами, где он рвётся.
#Короткий ответ
RAG (retrieval-augmented generation, «генерация с дополнением через поиск») — это когда перед тем, как модель начнёт писать ответ, программа ищет в вашем хранилище подходящие куски текста и вклеивает их в запрос. Модель не «вспоминает» — она читает подложенную шпаргалку и отвечает по ней.
Ключевое следствие сразу: качество ответа определяется качеством шпаргалки, а не умом модели. Если нужный фрагмент не нашёлся, самая сильная модель придумает правдоподобный ответ, потому что ей нечего читать.
#Как это устроено: четыре шага
Конвейер удобно держать в голове как четыре действия, из которых первое происходит заранее, а остальные — на каждый ваш вопрос.
Шаг 0 (заранее, один раз на каждый документ). Текст режется на куски и складывается в хранилище. Если планируется поиск по смыслу — каждый кусок дополнительно прогоняется через модель-эмбеддер и рядом с текстом кладётся его вектор. Как выбирать размер куска и почему «512 токенов» — не универсальный ответ, разобрано в материале про стратегии чанкинга текста.
Шаг 1. Запрос превращается в поисковый запрос. Тут развилка: либо из вопроса выдёргиваются ключевые слова, либо вопрос целиком превращается в вектор, либо и то и другое сразу. Persona по умолчанию делает первое: _recall_terms в app/chat/sessions.py берёт из вопроса имена собственные и слова длиной от четырёх букв, отбрасывает стоп-слова и оставляет не больше шести терминов.
Шаг 2. Поиск возвращает кандидатов. Ключевые слова ищутся полнотекстовым индексом с ранжированием bm25, векторы — поиском ближайших соседей. Оба способа возвращают список «похожего», отсортированный по своей мере похожести.
Шаг 3. Отобранные куски вклеиваются в промпт. Обычно с пометкой, откуда они и когда сказаны. Дальше модель пишет ответ, видя эти куски как часть входа.
Именно из шага 3 следует неприятная вещь, которую редко проговаривают: фрагменты вашей памяти уходят туда же, куда уходит сам вопрос. С локальной моделью — остаются на вашем железе; с ключом облачного провайдера — уезжают этому провайдеру вместе с вопросом. RAG не делает приватность лучше, он увеличивает объём личного текста в каждом запросе.
#Три места, где конвейер ломается
Почти все жалобы вида «RAG не работает» сводятся к одному из трёх отказов. Различить их можно за десять минут, если знать, что смотреть.
| Отказ | Как выглядит снаружи | Как проверить |
|---|---|---|
| Нужного текста нет в хранилище | Ассистент уверенно выдумывает | Найдите факт поиском по базе напрямую. Не нашли — проблема не в RAG |
| Текст есть, но не нашёлся | Ответ «не знаю» или мимо темы | Задайте тот же вопрос дословными словами из документа. Нашлось — проблема в формулировке запроса и в режиме поиска |
| Текст нашёлся, но модель его проигнорировала | В ответе есть фрагмент, но вывод ему противоречит | Посмотрите, где фрагмент оказался в промпте. Середина длинного контекста — известная слепая зона |
Первый отказ лечится не поиском, а дисциплиной записи. Второй — сменой или комбинацией режимов поиска, и это тема отдельного разбора о том, почему ключевые слова всё ещё нужны рядом с векторами. Третий — порядком фрагментов и их количеством: чем больше вы подложили, тем выше шанс, что важное утонет.
#Что из этого следует на практике
Начинайте с ключевых слов, а не с векторов. Это звучит против моды, но проверяется дёшево: полнотекстовый индекс в SQLite настраивается одной миграцией и работает без единой внешней зависимости, а векторный поиск требует установленного расширения, запущенной модели-эмбеддера и однократной индексации всего накопленного. В Persona поэтому векторный режим — надстройка, а не основание: при отсутствии любого из трёх условий система тихо возвращается к поиску по ключевым словам, и ничего не ломается.
Считайте не «сколько нашли», а «что попало в промпт». Полезная метрика для персональной памяти — доля вопросов, на которые нужный фрагмент оказался в первых шести выданных. Собрать её можно вручную: возьмите двадцать реальных вопросов к своему архиву, для каждого заранее выпишите, какой фрагмент обязан найтись, и посчитайте попадания. Двадцати хватает, чтобы увидеть систематический перекос.
Не путайте объём хранилища с качеством памяти. Механику слоёв — контекстное окно, внешнее хранилище, извлечение, карточки — подробно разбирает статья о том, как устроена память у ИИ. RAG в этой схеме отвечает ровно за одно звено: доставку.
#Где интуиция подводит
Кажется, что RAG — это способ «научить модель вашим данным». Это не так, и разница практическая. Модель после RAG не знает ничего нового: в следующем запросе, без подложенной шпаргалки, она снова ничего не помнит. Знание живёт в хранилище, а не в весах. Если вам нужно поменять именно поведение модели — тон, формат, стиль рассуждения, — RAG бесполезен, и выбор между двумя подходами разобран в сравнении RAG или дообучение под свою задачу.
Второе заблуждение — что векторный поиск «понимает смысл» и потому всегда лучше. Он возвращает наиболее похожее, а похожее и правильное — разные вещи. На запросе «ошибка E-4021» поиск по смыслу с удовольствием вернёт три абзаца про похожие коды ошибок и ни одного про нужный. Почему так получается, объясняет разбор того, как текст превращается в числа.
#Частые вопросы
#Чем RAG отличается от обычного поиска по документам?
Обычный поиск отдаёт вам список ссылок, дальше вы читаете сами. RAG отдаёт найденные куски не вам, а модели, и она пишет по ним ответ. Поисковая часть в обоих случаях одна и та же — отличается только потребитель результата.
#Нужна ли для RAG векторная база данных?
Не обязательно. Полнотекстовый индекс — тоже полноценный retrieval, и на персональных объёмах он часто даёт результат не хуже при нулевых накладных расходах. Отдельная векторная база оправдана, когда запросы формулируются не теми словами, что записаны в документах, и когда объём перестаёт помещаться в один файл.
#Почему ассистент отвечает «не знаю», хотя факт точно записан?
Скорее всего, сработал второй отказ из таблицы: текст есть, но запрос до него не дотянулся. Проверяется дословным поиском — если по точным словам из записи фрагмент находится, дело в формулировке запроса, а не в хранилище.
#Убирает ли RAG галлюцинации полностью?
Нет. Он резко снижает выдумывание там, где нужный фрагмент найден, и никак не помогает там, где не найден: модель всё равно обязана что-то ответить. Более того, RAG добавляет свой класс ошибок — когда в шпаргалку попал похожий, но неверный фрагмент, и модель уверенно цитирует именно его.
#Сколько фрагментов подкладывать в промпт?
Обычно единицы, а не десятки. Persona в режиме по умолчанию отдаёт в промпт до шести найденных сообщений. Больше — не всегда лучше: растёт цена запроса, а важный фрагмент с большей вероятностью оказывается в середине контекста, где модели используют его хуже всего.
#Вывод
RAG — это конвейер: нарезать, найти, вклеить, ответить. Если у вас проблема с ответами ассистента, диагностируйте её как поломку конвейера, а не как «слабую модель»: сначала проверьте, есть ли факт в хранилище, потом — находится ли он поиском, и только потом смотрите на модель. Если знания в вашей задаче меняются часто — вам нужен RAG. Если меняется не знание, а манера — RAG вам не поможет, и никакие настройки поиска этого не исправят.