RAG: как устроен и где ломается
RAG - самый массовый LLM-продукт, и вопросы по нему быстро отделяют строивших от читавших: «RAG галлюцинирует - что делать?» имеет правильный первый шаг, и это не промпт.
// Мантра темы: сначала мерь retrieval, потом чини generation.
Скелет RAG и чанкование
RAG (retrieval-augmented generation): запрос → retrieval релевантных кусков базы знаний → генерация ответа по ним. Факты живут в индексе, не в весах: обновление знаний - переиндексация, а не дообучение.
Чанкование - главный тихий убийца качества: слишком мелкие куски теряют контекст, слишком крупные тащат шум и съедают контекст модели. Резать по структуре документа (заголовки, абзацы) с перекрытием.
// Прод-мелочи, которые решают: фильтры доступа (юзер видит только свои документы), свежесть индекса, метаданные - даты и версии - прямо в чанках.
- чанк
- кусок документа в индексе; размер и границы решают качество
Гибридный поиск и реранкер
Dense-эмбеддинги ловят семантику («как вернуть товар» ≈ «оформление возврата»), но теряют точные термины: артикулы, имена, коды ошибок. BM25 - наоборот. Гибрид со слиянием результатов (RRF - reciprocal rank fusion) закрывает оба типа запросов.
Реранкер (cross-encoder) пересортировывает топ-N ретривера: читает пару «запрос-документ» целиком и точнее bi-encoder'а, но дорог - ставится на короткий список.
// Эмбеддер общего домена на специфичном корпусе - лотерея: близость «по-вебовски» может не совпадать с твоей. Оценивай retrieval на своих запросах до выбора модели.
- bi-encoder / cross-encoder
- раздельные вектора (быстро) / пара целиком (точно, дорого)
- RRF
- reciprocal rank fusion - слияние выдач dense и BM25
Оценка двух слоёв и защита от отсебятины
Оценивай слои раздельно. Retrieval: recall@k - «достали ли нужный документ в топ-k» на размеченных парах запрос-документ. Generation: faithfulness - «ответ следует из документов, без отсебятины».
Смешаешь слои - будешь чинить не то: галлюцинации при плохом retrieval - проблема поиска, и никакой промпт не заставит модель отвечать по документу, которого нет в контексте.
// Базовая защита поверх: просить цитировать источники и отвечать «не знаю» при пустой или нерелевантной выдаче - дешёво и заметно режет галлюцинации.
- recall@k
- доля запросов, где нужный документ попал в топ-k
- faithfulness
- ответ следует из поданных документов, без отсебятины
Как отвечать: «RAG галлюцинирует. Как будешь чинить?»
Сначала диагноз по слоям. Мерю retrieval: recall@k на размеченных парах запрос-документ - чаще всего окажется, что нужный документ просто не достаётся, и это чинится чанкованием, гибридом dense+BM25 и реранкером, а не промптом. Если retrieval в порядке, иду в generation: faithfulness-оценка, инструкция отвечать только по документам с цитатами и «не знаю» как валидный ответ при пустой выдаче. И проверяю грязные кейсы: конфликтующие версии документов и устаревший индекс тоже выглядят как «галлюцинации».
Правильный первый шаг (мерить retrieval), лечение по слоям и неочевидные причины - маршрут человека, который дебажил живой RAG.
На чём валят
- −Чинить галлюцинации промптом при сломанном retrieval - сначала recall@k.
- −Только dense-поиск - артикулы, имена и коды теряются; нужен гибрид с BM25.
- −Эмбеддер общего домена на специфичном корпусе без оценки - близость не твоя.
- −Индекс без контроля доступа - RAG процитирует чужой документ.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 10, остальные разбираются в тренажёре.
- Плотный (dense) векторный поиск находит релевантное, чего не может ключевой (BM25). Что именно?A)Документы, в которых искомое ключевое слово буквально встречается чаще всего по частотеB)Точные совпадения по подстроке в тексте документаC)Самые свежие по дате публикации документыD)Семантически близкие фрагменты, даже если слова другие (синонимы, перефраз)
показать ответ и разбор
+D)Семантически близкие фрагменты, даже если слова другие (синонимы, перефраз)// разбор: Dense retrieval сравнивает эмбеддинги запроса и чанков: близость в векторном пространстве отражает смысл, поэтому находит перефразы и синонимы, где точного совпадения слов нет («авто» ↔ «машина»). BM25/ключевой поиск силён в точных терминах, редких словах, кодах, но слеп к синонимии. Отсюда гибрид: dense + sparse дополняют друг друга.
- Зачем в проде часто комбинируют dense-поиск и BM25 (hybrid retrieval)?A)Чтобы примерно вдвое сократить итоговый размер векторной базы и стоимость её обслуживанияB)Они закрывают разные провалы: dense ловит смысл, BM25 — точные термины и редкие словаC)Чтобы отказаться от эмбеддингов в пайплайнеD)Гибрид быстрее одиночного поиска
показать ответ и разбор
+B)Они закрывают разные провалы: dense ловит смысл, BM25 — точные термины и редкие слова// разбор: Dense силён в семантике, но промахивается на точных сущностях: артикулы, коды ошибок, редкие имена, где важен буквальный токен. BM25 наоборот. Гибрид объединяет их скоры (например, reciprocal rank fusion), покрывая оба класса запросов — стабильнее на разнородных вопросах. Цена — две системы поиска и настройка слияния.
- Зачем поверх векторного поиска ставят реранкер на cross-encoder?A)Чтобы ускорить первичный поиск по всей базе документовB)Чтобы заменить собой векторную базу и не хранить предпосчитанные эмбеддинги документовC)Точно переупорядочить топ-N кандидатов, совместно кодируя пару (запрос, документ)D)Чтобы сжать документы перед подачей в LLM
показать ответ и разбор
+C)Точно переупорядочить топ-N кандидатов, совместно кодируя пару (запрос, документ)// разбор: Bi-encoder кодирует запрос и документ независимо → быстрый ANN-поиск по всей базе, но грубоват. Cross-encoder подаёт пару (запрос, документ) вместе, видит их взаимодействие на уровне токенов → куда точнее оценивает релевантность, но дорого (вызов на каждую пару). Отсюда двухступенчатость: bi-encoder дёшево достаёт топ-N, cross-encoder переранжирует только их.
- Что измеряет faithfulness (грунтованность) в RAG-эвале, в отличие от answer relevance?A)Насколько ответ опирается на извлечённый контекст, а не выдуман сверх негоB)Насколько быстро система вернула ответ пользователюC)Сколько всего документов физически хранится в векторной базе на момент запросаD)Насколько грамматически правилен текст ответа
показать ответ и разбор
+A)Насколько ответ опирается на извлечённый контекст, а не выдуман сверх него// разбор: Faithfulness проверяет, что каждое утверждение ответа выводится из поданного контекста — то есть модель не галлюцинирует поверх источников. Answer relevance — отвечает ли ответ на вопрос по существу. Их меряют порознь: ответ бывает релевантным, но выдуманным, или верным по источнику, но не отвечающим на вопрос. Ещё меряют context precision/recall — качество самого извлечения.
- Наивный RAG плохо отвечает на многошаговые вопросы (составные, с несколькими фактами). Почему и что делают?A)Векторная база не поддерживает такие запросыB)Один retrieve не собирает все нужные факты; помогают декомпозиция запроса, итеративный retrieval, query rewritingC)Нужно просто увеличить top-k до нескольких тысяч чанковD)Многошаговые вопросы решаются полным дообучением модели
показать ответ и разбор
+B)Один retrieve не собирает все нужные факты; помогают декомпозиция запроса, итеративный retrieval, query rewriting// разбор: Составной вопрос требует несколько разных фактов, а одиночный семантический поиск по исходному запросу вытащит чанки, похожие на весь вопрос целиком, а не каждое звено цепочки. Решения: разложить вопрос на подвопросы и извлекать под каждый, итеративный retrieval (retrieve→reason→retrieve), переписывание запроса (query rewriting/HyDE), иногда structured retrieval. Просто раздуть top-k — засорить контекст шумом.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.