При проектировании RAG-системы инженер каждый раз сталкивается с множеством вопросов: как получать чанки, какую векторную базу использовать, как организовать получение релевантной информации из базы, да даже выбор эмбеддера может занять приличное время — и это лишь вершина айсберга. Идеальным решением является перебор основных вариантов, затем оценка качества и выбор подходящих для конкретной задачи. Ведь то, что хорошо работает, например, для техподдержки, может провалиться в юридическом анализе, и наоборот.
К счастью, на GitHub есть прекрасный репозиторий, где автор собрал популярные RAG-техники с кодом и объяснениями. Репозиторий доступен по ссылке. Обязательно зайдите и поддержите автора.
Но одного объяснения техник мне показалось мало. Опыт внедрения RAG-систем в различных сферах внушил скепсис: а как эти техники работают в жизни? Поэтому я решил не просто изучить приёмы, а реализовать их и протестировать, чтобы получить сопоставимые численные оценки.
В первой главе мы рассмотрим основные RAG-техники, поговорим о сферах применения. В следующей главе мы изучим их эффективность, посмотрим на графики с табличками и разойдёмся, чтобы переварить всё написанное.
Статья будет разбита на две части, так как она оказалась немного больше, чем я планировал. В первой части мы поближе познакомимся с техниками, а во второй (как она появится, я оставлю ссылку) обсудим метод сравнения и проведём оценку их эффективности.
Краткий план исследования
Что исследуем: различные способы проектирования RAG-систем.
Данные: датасет Natural Questions, который содержит в себе вопросы пользователей к Google и ответы, аннотированные на основе статей Википедии (+ сами статьи) .
-
Метрики:
RAGAS — LLM-based оценка разных аспектов RAG-системы (faithfulness, answer relevance и т.д.),
BertScore — Оценка релевантности контекста и соответствия между ответом системы и реальным ответом.,
LLM Модель: GigaChat Lite.
Глава 0. Датасет Natural Questions
Natural Questions — это датасет с реальными поисковыми запросами пользователей Google. Зачастую данные вопросы в датасете неполные, неоднозначные и требуют обработки длинного контекста. В качестве контекста выступают статьи из Википедии. Также для каждого вопроса существует короткий ответ и длинный ответ (отрывок из статьи, который лучше всего отвечает на вопрос). Однако, иногда встречаются вопросы, на которые нет ответов в приведённой статье.
Как несложно заметить, данный датасет очень хорошо ложится под сферу применения RAG-систем:
Вопросы написаны реальными пользователями, а не являются синтетикой.
Имеется большой набор документов (статьи из Википедии), которые, как ни крути, несут в себе много шума, из которого нужно выделить релевантную информацию.
На некоторые вопросы нет ответов. Система должна явно понимать, когда ответа нет и давать пользователю обратную связь.
Для кажого вопроса даются фрагменты статьи, которые наиболее полно отвечают на вопрос. Это позволяет проверять релевантность как извлечённого контекста, так и финального ответа
Датасет содержит ~300k примеров в обучающей выборке и ~7k примеров в валидационной и тестовой выборках.
Глава 1. RAG-техники
Перед началом исследования кратко проговорим про основные техники.
Простой RAG

Принцип работы довольно прост. Запрос пользователя векторизуется (1.), затем вектор сравнивается с векторами в базе данных с помощью косинусной близости(2.). Топ самых семантически близких векторов достаются из базы данных и подаются вместе с запросом пользователя подаются в контекст LLM, которая и выдаёт итоговый ответ (3.).
Резюме
Сильные стороны:
Хорошо работает «из коробки» на большинстве задач.
Простота реализации.
Работает как быстрый старт (MVP).
Слабые стороны:
Фиксированное количество чанков в контексте.
Сильная зависимость от эмбеддера.
Сферы применения:
Простые системы, где готовые ответы обычно есть в документации.
Раз уж мы проводим исследование, то давайте углубимся в данную технику, потому что даже здесь существует множество нюансов, о которых нужно подумать.
Почему именно косинусное сходство?
Как оказалось, довольно сложный вопрос, который я пытался раскрыть здесь.
Конечно, при проектировании RAG-системы можно попробовать провести эксперимент. Например, Qdrant поддерживает такие метрики, как метрику на основе скалярного произведения, косинусную метрику, евклидову метрику и манхэттенскую метрику. Но поменять метрику на уже существующей базе не получится.
Поэтому ради эксперимента мною были созданы 4 идентичные коллекции с разными метриками:

И при сравнении результатов релевантности чанков с помощью метрики BertScore (про метод оценки будет в следующей части) оказалось, что разница метриках слишком мала, чтобы можно было уверенно говорить про превосходство одних метрик над другими.

Почему сначала должны идти самые релевантные чанки?
На первый взгляд довольно странный вопрос. Но давайте вспомним, что LLM хорошо используют информацию из начала и конца промпта, а информация в середине обрабатывается хуже (статья Lost in the Middle: How Language Models Use Long Contexts). И если учесть, что промпт в RAG-система часто выглядит так:
System промпт + инструкции + вопрос + контекст
То первый и самый релевантный (как мы предполагаем) чанк оказывается где-то в середине.
И такая проблема действительно есть. На просторах Arxiv можно найти прекрасную статью (Position of Uncertainty: A Cross-Linguistic Study of position bias in Large Language Models) от исследователей из ИТМО. В данной статье исследуется пристрастие LLM к определённым позициям релевантной информации в промпте.
Авторам удалость показать, что Qwen2.5-7B-Instruct точнее отвечает на вопросы, когда релевантные чанки находятся в конце. Llama3-8B-Instruct наоборот работает лучше, когда релевантные чанки находятся сверху. Причём данная особенность замечается как при работе с текстами на русском языке, так и на английском, немецком, хинди и даже
вьетнамском.
Подробнее я рассказывал про данную статью здесь.
Моё короткое тестирование GigaChat Lite показало, что качество ответов оказывается лучше, когда сначала идут релевантные чанки. Поэтому далее чанки будем располагать по убыванию предполагаемой релевантности.
Особое внимание нужно уделить выбору векторизатора, так как именно он отвечает за получение релевантной информации. Чаще всего FRIDA или BGE-M3 справляется с данной задачей на высоком уровне. Однако всё равно первым шагом настройки retrieval-модуля должна быть проверка качества разных векторизаторов. Также нужно настроить оптимальную длину чанков, которая тоже может колоссально повлиять на качество retrieval-модуля. Данные этапы в текущем исследовании опустим и будем использовать BGE-M3 с размером чанка 600 символов и перекрытием 50 символов.
Propositions Chunking

Принцип работы таков:
LLM получает чанк и разбивает его на предложения, содержащие точные факты.
LLM оценивает полученные предложения. Они, как минимум, должны нести в себе полезную информацию, быть точными и ясными.
Полученные предложения загружаются в векторную базу данных. Дальше простой RAG.
Данный метод ориентирован на простые точные вопросы. Благодаря второму этапу отсеивается потенциальный шум, который хранится в тексте. А благодаря первому этапу мы получаем семантически насыщенные чанки, вместо простых кусков текста, которые могут "размывать" семантику. Поэтому факты в таком формате ближе к атомарным единицам смысла — это помогает retrieval-модулю быть точнее.
Резюме
Сильные стороны:
Каждая запись в базе несёт концентрированную смысловую нагрузку, что упрощает работу retrieval-модуля.
Уменьшение нагрузки на контекст LLM. Из-за удаления "воды" LLM расходует меньшее количество токенов. Это также сказывается на скорости.
Слабые стороны:
Увеличение вычислительной стоимости подготовки базы данных. Каждый чанк нужно прогнать через LLM для получения разметки.
Зависимость от качества работы LLM на этапе разбиения и фильтрации. Ошибки влекут за собой потерю фактов.
Потенциальная фрагментация знаний. Длинные логические связи между предложениями могут потеряться.
Сферы применения:
Системы с простыми вопросами, требующими точного факта. Справочники и словари, в которых каждый факт самодостаточен.
Query Transformation
В данной технике мы пытаемся бороться с неточными запросами к системе путём их переформулирования. Первым делом, запрос попадает в LLM, которая должна сделать его более конкретным и полным. Далее этот запрос попадает в стандартную RAG систему.
Пример: "Машина Шумахера?" → "Какую машину использовал Михаэль Шумахер во время гонок в Формуле-1?"
Резюме
Сильные стороны:
Запросы становятся более релевантными базовым документам.
Снижает вероятность промаха из-за слишком короткого или неконкретного вопроса.
Слабые стороны:
Ошибка на этапе переформулировки ведёт к неправильному контексту.
Иногда система начинает искать то, чего пользователь не имел в виду.
Сферы применения:
Чат-боты для широкой аудитории (пользователи часто пишут кривые запросы).
Поиск по большим шумным базам знаний, где важно уточнять контекст.
Query Decomposition
Особую сложность RAG-система может испытывает, когда поступает составной вопрос. Например:
"Как мне попасть в офис и во сколько я должен там быть?". Логичным решением является обработка вопроса LLM моделью, которая разобьёт составной вопрос на простые вопросы ("Как попасть в офис?" и "Во сколько нужно быть в офисе?"). Далее на каждый вопрос находится ответ с помощью обычной RAG, а в конце все ответы вместе с вопросом передаются LLM, которая их агрегирует и выдаёт финальный ответ.
Резюме
Сильные стороны:
Позволяет работать со сложными, составными запросами.
Дробление на подзадачи снижает нагрузку для retrieval-модуль и LLM.
Слабые стороны:
Ошибки в разбиении приводят к ошибкам в ответе.
Увеличение вычислительных затрат: для каждого подзапроса делается retrieval-запрос и генерация.
Сферы применения:
Аналитические системы, в которых запрос затрагивает несколько тем (многоаспектный анализ).
Системы с комплексными документами (юридические, медицинские).
В более серьёзных системах Query Transformation и Query Decomposition объединяются, что делает RAG более устойчивым к живым пользовательским вопросам, далеким от идеальных запросов. В случаях, когда баз с документами несколько, то можно закинуть в контекст LLM, отвечающей за расширение/декомпозирование запросов, названия этих баз и их описание (это уже шаг к routing RAG). В таком случае, LLM будет понимать предметную область и сможет эффективнее обработать запрос.
HyDE (Hypothetical Document Embedding)

Ещё один метод расширения запроса. Однако, в данной технике LLM на основании запроса пользователя генерирует потенциальный документ, который даёт ответ на запрос. Данный документ служит мостом между запросом и реальными документами, снижая семантический разрыв. Потому что с точки зрения векторизатора вопрос "Кто впервые получил нобелевскую премию по физике?" и ответ "Вильгельм Конрад Рентген впервые получил нобелевскую премию по физике" хоть и близки, но всё равно имеют семантическую разницу.
Резюме
Сильные стороны:
Улучшает релевантность, особенно при разрыве между формулировкой вопроса и текстами документов.
Слабые стороны:
Ошибки в сгенерированном документе порождают мусор в retrieval.
Неэффективно для сложных, многопредметных вопросов, где один гипотетический документ не покрывает всю информацию.
Сферы применения:
Системы с точными вопросами и короткими фактологическими ответами.
Ситуации с разными формулировками текста в источниках (например, статьи, новости, базы знаний).
Стоит отметить, что некоторые векторизаторы (например BGE-M3) умеют работать с подобными ситуациями, вводя в качестве префиксов фразы:
query: — обозначает, что мы подаём на вход текст запроса пользователя,
passage: — обозначает, что мы подаём текст документа или отрывка (часть статьи, заметки, FAQ и т.д.).
А если заглянуть в карточку модели FRIDA, то можно найти ещё больше полезных префиксов.
HyPE (Hypothetical Prompt Embeddings)
А что если не генерировать каждый раз гипотетический ответ, а в момент занесения чанков в базу данных сгенерировать к ним гипотетические вопросы? Именно так и работает HyPE:
К каждому чанку генерируем вопросы.
Поиск в векторной базе данных происходит только по сгенерированным вопросам (получаем семантическую близость, без необходимости дополнительных генераций в момент обращения).
В качестве контекста подтягиваем чанк, по которому был задан вопрос.
Пример: "Вильгельм Конрад Рентген получил Нобелевскую премию по физике в 1901 году".
Генерируемый гипотетический вопрос: Кто стал первым лауреатом Нобелевской премии по физике?
Теперь поиск по векторной базе происходит по этому вопросу, что упрощает сравнение с запросом пользователя, а чанк подтягивается уже после.
Также мы получаем экономию времени относительно HyDE для пользователей, ведь теперь не нужно ждать, пока сгенерируется гипотетический ответ. Однако, процесс внесения текстов в базу данных существенно затягивается и становится куда более дорогостоящим. Поэтому в данном исследовании метод HyPE тестироваться не будет.
Relevant Segment Extraction (RSE)
Одной из главных проблем retrieval модуля в предыдущих техниках является фиксированная длина чанка. Давайте представим график, в котором по оси X идут чанки, а по оси Y — их семантическая близость какому-то конкретному запросу.

На графике видны резкие перепады. Если мы просто возьмём топ семантически близких чанков, то мало того, что они все перемешаются, так ещё и потеряются важные фрагменты информации. Например, если посмотреть на два самых релевантных чанка (это чанки под номером 31 и 33, которые имеют близость к запросу ~0.6), то между ними можно заметить ещё один чанк, который может нести в себе полезный для ответа контекст. И, кроме того, эти три чанка больше похожи на единый смысловой фрагмент, который оказался разбитым из-за фиксированной длины чанков. Применяя метод RSE, мы можем соединять подобные чанки в единый смысловой фрагмент, как это показано на графике ниже.

Работает метод следующим образом:
Генерируются все возможные сегменты. Это могут быть любые окна длинны не большей определённой максимальной длины окна.
Для каждого сегмента считается его ценность. В качестве ценности выступает комбинированная метрика, которая учитывает максимальное значение релевантности, среднее значение релевантности на сегменте и бонус за длину (чтобы отдавать предпочтение цельным кускам).
Выбор функции ценности очень влияет на качество работы. Так, если использовать простую сумму релевантностей (как это сделано в репозитории, который я упоминал вначале), то предпочтение будет почти всегда отдавать длинным сегментам со средней релевантностью (чанки под номерами 50-80), а обособленные, но релевантные фрагменты будут игнорироваться. Если взять просто среднее, то предпочтение будет наоборот отдаваться только маленьким фрагментам с высокими значениями релевантностей.Из всех кандидатов выбираются оптимальные сегменты так, чтобы они не пересекались и в сумме не превышали общий лимит длины.
На последнем шаге сегменты можно слегка расширить и объединить близкие друг к другу, чтобы вместо множества мелких фрагментов получилось меньше, но более длинных и связных сегментов.
Чтобы не вдаваться в подробности, потому что они займут слишком много места, я предлагаю посетить репозиторий, в котором можно ознакомиться с работой алгоритма поближе.
Таким образом, RSE решает две ключевые боли простого чанкования:
Разрыв смысловых единиц (когда один логический кусок текста оказывается порезанным).
Потеря релевантного контекста между чанками.
Резюме
Сильные стороны:
Устраняет проблему разбитых смысловых кусков текста.
Уменьшает проблему фиксированной длины чанков.
Гибкость: можно настраивать функцию ценности под конкретные задачи.
Повышает качество retrieval-модуля без необходимости менять векторизатор или модель.
Слабые стороны:
Для формирования сегментов нужно получить все чанки из базы данных, что влечёт за собой дополнительные вычисления при формировании сегментов.
Зависимость от функции ценности: если выбрать неудачную метрику, сегменты будут либо слишком длинные (и засорять контекст), либо слишком мелкие (и терять связь).
Сферы применения:
QA-системы, где ответ зависит от нескольких близких по смыслу фрагментов документа.
Аналитические задачи (отчёты, резюме длинных текстов), где важна связность контекста.
Semantic Chunking
Ещё одним методом, как уйти от фиксированной длины чанков, является разбиение чанков на семантически близкие блоки. В данной технике чанки бьются с помощью SemanticChunker из библиотеки langchain_experimental
.
Краткий принцип работы:
Разбиваем текст на предложения.
Для каждого предложения получаем его векторное представление.
Считаем косинусное расстояние между соседними предложениями. Например, между первым и вторым предложениями, между вторым и третьим, третьим и четвёртым и так далее.
Составляем распределение расстояний. Если расстояние попадает в 95-й перцентиль (эвристика и её можно менять в зависимости от желаемой длины чанков), то считаем, что данные предложения не имеют смысловой связности и между ними ставим точку разрыва.
Точки разрыва показывают, где заканчивается чанк и начинается новый.
Чанки загружаются в векторную базу данных.
Далее принцип работы не отличается от простого RAG.
Более подробнее про принцип работы можно прочитать в RetrievalTutorials или здесь.
Резюме
Сильные стороны:
Автоматическое разбиение текста по смысловым единицам. Это даёт меньше разрыва контекста.
Подходит для документов разной структуры и длины.
Каждый чанк несёт более цельную информацию.
Слабые стороны:
Вычислительно дороже фиксированного чанкинга (нужно строить векторные представления всех предложений и считать косинусное расстояние).
Эвристика не всегда идеально работает. Иногда разрезаются логически связанные предложения или объединяются разные темы.
Сферы применения:
QA-системы, где тексты содержат логические блоки разной длины.
Также стоит учесть, что данная техника хорошо комбинируется с RSE. Semantic Chunking формирует смысловые чанки, а RSE объединяет несколько близких по смыслу чанков в один сегмент.
Context Enrichment Window

Данная техника строится на том, что для каждого релевантного чанка (на картинке выше это чанк 3) добавляются соседние чанки (чанки 2 и 4). Делается это для того, чтобы сохранить логическую целостность информации, потому что один релевантный чанк может быть бессмысленным без соседних предложений или абзацев.
Если информация для векторной базы данных берётся из документов, которые имеют страницы (PDF, Docx и т.д), то хорошей практикой также является сохранение для каждого чанка номера страницы, из которой он взят. Это позволяет сначала получить релевантные чанки, а затем из данных чанков подтянуть целые страницы документов (удалив дубликаты).
Например, такой метод использовался автором данной прекрасной статьи. К слову, его решение заняло первое место в RAG Challenge, поэтому обязательно почитайте статью, там много интересного.
Резюме
Сильные стороны:
Повышает полноту и качество контекста.
Слабые стороны:
Увеличение размера контекста.
Риск добавить нерелевантную информацию, если соседние чанки не несут нужного смысла.
Сферы применения:
RAG системы, информация для которых берётся из документов с абзацами или страницами (PDF, Word, отчёты, учебники).
Fusion Retrieval

Сравнительно недавно вышла статья от Google про фундаментальные ограничения embedding-моделей. Если кратко, то при увеличении документов модели упираются в потолок своей вместимости (capacity) и не могут справиться даже с простыми задачами. Чего не наблюдается у полнотекстовых моделей поиска (например, BM-25).
Поэтому резонным является использование двух retrieval модулей: embedding-модели для семантического поиска и модели полнотекстового поиска для подбора по ключевым словам. Полученные из них чанки собираются и очищаются от дубликатов. Далее они либо реранжируются, либо сразу подаются в LLM. Таким образом, удаётся уменьшить недостатки этих двух методов.
Резюме
Сильные стороны:
Комбинируются сильные стороны как семантического поиска, так и полнотекстового.
Снижает эффект "потолка вместимости" эмбеддеров при больших базах данных.
Слабые стороны:
Появляется риск дублирования, поэтому требуется тщательная дедубликация и реранжирование.
Сферы применения:
Крупные корпоративные базы знаний с большим количеством документов.
QA-системы, где важно покрыть все возможные варианты формулировки ответа.
Reranking

Мощный метод, который позволяет оценить релевантность полученных чанков и (или) изменить порядок их следования в контексте (про важность порядка уже говорили выше). Также данный метод позволяет избавиться от ограничений, связанных с фиксированным количеством чанков. Ведь, чтобы дать ответ на некоторые вопросы, иногда хватает 1-2 чанков, а все остальные не относящиеся к теме чанки не только добавляют шума в контекст, но и раздувают его. А, как мы знаем, сложность работы механизма внимания растёт квадратично относительно размера контекста. Поэтому все нерелевантные чанки можно удалить с помощью реранкера. Однако, в случае удаления релевантного чанка, вся RAG-система потеряет эффективность. И чтобы этого не происходило, нужно уделить много времени его настройке.
Делать реранжирование можно либо с помощью LLM, либо с помощью кросс-энкодеров.
В случае работы с LLM мы просим её оценить конкретный чанк запросу. Причём важно прописать конкретные критерии оценивания и шкалу. С помощью Structured Output мы получаем оценки и уже по ним ранжируем документы.
В случае работы с кросс-энкодерами мы подаём в модель запрос и конкретный чанк, а на выходе получаем оценку релевантности между ними, по которой происходит ранжировка.
Резюме
Сильные стороны:
Удаление шума из контекста LLM.
Позволяет использовать переменное количество чанков.
Улучшает качество генерации за счёт более правильного порядка релевантных фрагментов.
Слабые стороны:
Неверно настроенный реранкер может удалять релевантные чанки.
Каждый чанк прогоняется через LLM или cross-encoder, что увеличивает вычислительные затраты.
Требует правильной шкалы оценивания и критериев релевантности для LLM.
Dartboard RAG
В случаях, когда документы пересекаются, в контексте появляется избыточность информации. Разные чанки несут в себе одно и тоже. Чтобы этого избежать, вводится функция, которая оценивает как релевантность, так и разнообразие чанков. Оценка функцией помогает получить более всесторонний ответ, удалив из контекста схожие по смыслу чанки.
Работает всё следующим образом:
Вычисляется косинусное расстояние между запросом и каждым документом (делается автоматически при работе с векторными базами данных).
Вычисляется косинусное расстояние между каждой парой документов (получается матрица расстояний).
Выбирается самый релевантный чанк.
-
В цикле выбирается чанк, который имеет лучшую оценку, зависящую от его близости к запросу и удалённости от уже выбранных чанков:
Здесь:
— коэффициент важности схожести между запросом
и конкретным чанком
,
— коэффициент важности удалённости конкретного чанка
от уже выбранных чанков
,
— функция близости, основанная на косинуской метрике,
— выбранные на прошлых шагах чанки.
Резюме
Сильные стороны:
Уменьшает дублирование информации в контексте для LLM.
Позволяет получить более всесторонний и разнообразный ответ на вопрос.
Слабые стороны:
Не всегда необходим для малых баз, где дублирования мало.
Появляется сложность настройки параметров схожести и разнообразия.
Сферы применения:
RAG-системы, с большим количеством пересекающихся документов.
Итоги первой части.
Мы перечислили основные RAG-техники, разобрались в их принципах работы, сильных и слабых сторонах, а также сферах применения. Помимо этого, мы определились с датасетом — Natural Questions, который позволит нам протестировать RAG-техники на реальных пользовательских вопросах.
В следующей части мы будем проводить экспериментальное сравнение техник, чтобы понять, какие подходы дают наилучшую точность, полноту и релевантность в разных сценариях. Это позволит получить не только теоретическое понимание техник, но и наглядное сравнение их эффективности.
Стоит ещё раз напомнить, что сфер использования RAG-систем очень много и глобально судить о мощности той или иной техники по итогам данной статьи не стоит. Как мы увидели, разнообразие техник обусловлено разнообразием особенностей документов. Задачей инженера является выявление данных особенностей и адаптации системы к ним. Поэтому экспериментируйте, исследуйте и не бойтесь пробовать разные подходы. Только через практику и тестирование на ваших данных вы сможете выявить, какие техники действительно подходят для вашей конкретной задачи и достичь максимальной эффективности RAG-системы.
Всем спасибо за прочтение первой части статьи!