Продвинутые техники RAG иллюстрированный обзор

Продвинутые техники RAG иллюстрированный обзор

Гронинген, Martinitoren, где статья была написана в спокойствии Noorderplatsoen

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

Поскольку целью этого поста является обзор и объяснение доступных алгоритмов и техник RAG, я не буду углубляться в детали реализации кода, просто ссылаясь на них и оставляя это огромному объему документации и учебников, доступных.

Введение

Если вы знакомы с концепцией RAG, пожалуйста, перейдите к разделу Advanced RAG.

Retrieval Augmented Generation, также известный как RAG, предоставляет LLM информацию, полученную из некоторого источника данных, чтобы обосновать сгенерированный ответ. В основном RAG представляет собой поиск + подсказку LLM, где вы просите модель ответить на запрос, предоставив информацию, найденную с помощью алгоритма поиска, в качестве контекста. Как запрос, так и полученный контекст внедряются в подсказку, которая отправляется в LLM.

RAG является наиболее популярной архитектурой систем на основе LLM в 2023 году. Существует множество продуктов, основанных почти исключительно на RAG – от сервисов по ответам на вопросы, объединяющих веб-поисковые системы с LLM, до сотен приложений для общения с вашими данными.

Даже область векторного поиска проникла этой модой, хотя сферы поиска на основе векторных отображений были созданы с использованием faiss в 2019 году. Стартапы баз данных по векторам, такие как chroma, weavaite.io и pinecone, были построены на основе существующих открытых поисковых индексов – главным образом faiss и nmslib – и добавлены дополнительные хранилища для вводных текстов и некоторого другого инструментария в последнее время.

Существуют две наиболее известные библиотеки с открытым исходным кодом для пайплайнов и приложений на основе LLMLangChain и LlamaIndex, основанные с разницей в месяц в октябре и ноябре 2022 года соответственно, вдохновленные запуском ChatGPT и получившие массовую популярность в 2023 году.

Целью этой статьи является систематизация ключевых передовых методов RAG с ссылками на их реализации – в основном в LlamaIndex – для облегчения погружения других разработчиков в технологию.

Проблема заключается в том, что большинство учебников выбирают одну или несколько техник и подробно объясняют, как их реализовать, а не описывают полное многообразие доступных инструментов.

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

Наивный RAG

Стартовая точка конвейера RAG в этой статье будет состоять из корпуса текстовых документов – мы пропускаем все, что находится до этого момента и оставляем это удивительным загрузчикам данных с открытым исходным кодом, которые подключаются к любому возможному источнику от Youtube до Notion.

Схема автора, а также все схемы далее в тексте

Vanilla RAG case вкратце выглядит так: вы разделяете свои тексты на фрагменты, затем встраиваете эти фрагменты в векторы с помощью некоторой модели Transformer Encoder, помещаете все эти векторы в индекс и, наконец, создаете подсказку для LLM, которая говорит модели отвечать на запросы пользователей, исходя из контекста, найденного на этапе поиска. Во время выполнения мы преобразуем запрос пользователя в вектор с помощью той же модели Encoder, а затем выполняем поиск этого вектора запроса по индексу, находим топ-k результатов, извлекаем соответствующие фрагменты текста из нашей базы данных и передаем их в качестве контекста в LLM.

Подсказка может выглядеть так:

пример подсказки RAG

Инженеринг подсказок – самая дешевая вещь, которую вы можете попробовать для улучшения вашего RAG-пайплайна. Убедитесь, что вы ознакомились с достаточно полным руководством по инженерии подсказок от OpenAI.

Очевидно, несмотря на то, что OpenAI является рыночным лидером среди поставщиков LLM, существует ряд альтернатив, таких как Claude от Anthropic, недавно появившиеся модели меньшего размера, но очень функциональные, такие как Mixtral от Mistral, Phi-2 от Microsoft, а также множество вариантов с открытым исходным кодом, таких как Llama2, OpenLLaMA, Falcon, так что у вас есть выбор для своего RAG-пайплайна.

Расширенный RAG

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

Некоторые ключевые компоненты расширенной архитектуры RAG. Это скорее выбор доступных инструментов, чем чертеж.

Зеленые элементы на схеме – это основные техники RAG, о которых будет рассказано дальше, синие элементы – тексты. Не все идеи RAG легко визуализировать на одной схеме, например, различные подходы к увеличению контекста опущены – мы рассмотрим это по ходу.

1. Разбиение на фрагменты и векторизация

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

1.1 Разбиение на фрагменты Модели Transformer имеют фиксированную длину входной последовательности, и даже если окно контекста ввода большое, вектор предложения или нескольких предложений лучше представляет их семантическое значение, чем вектор, усредненный по нескольким страницам текста (зависит также от модели, но верно в общем случае), поэтому разделите свои данные на фрагменты – разбейте исходные документы на фрагменты некоторого размера, не потеряв их смысл (разделение текста на предложения или параграфы, а не разделение предложения на две части). Существуют различные реализации разделителя текста, способные справиться с этой задачей.

Размер фрагмента – это параметр, о котором нужно подумать – он зависит от используемой модели встраивания и ее емкости в токенах, стандартные модели трансформера Encoder, такие как BERT-based Sentence Transformers, берут не более 512 токенов, OpenAI ada-002 способна обрабатывать более длинные последовательности, например, до 8191 токена, но здесь компромисс между достаточным контекстом для рассуждения LLM и специфичным встраиванием текста для эффективного выполнения поиска. Здесь вы можете найти исследование, иллюстрирующее вопросы выбора размера фрагмента. В LlamaIndex это покрыто классом NodeParser с некоторыми дополнительными возможностями, такими как определение вашего собственного разделителя текста, метаданные, связи между узлами/фрагментами и т.д.

1.2 Векторизация Следующим шагом является выбор модели для встраивания наших фрагментов – есть достаточно вариантов, я выбираю оптимизированные модели поиска, такие как bge-large или семейство встраиваний E5 – просто проверьте доску MTEB для последних обновлений.

Для реализации этапа фрагментации и векторизации end2end проверьте пример полной системы ввода данных в LlamaIndex.

2. Поиск индекса 2.1 Векторное хранилище индекса

В этой схеме и далее в тексте я пропускаю блок кодировщика и отправляю наши запросы напрямую в индекс для простоты схемы. Запрос всегда сначала векторизуется, конечно же. То же самое с k лучшими фрагментами - индекс извлекает k лучших векторов, а не фрагменты, но я заменяю их фрагментами, так как получение их - это тривиальный шаг.

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

Правильный поисковый индекс, оптимизированный для эффективного извлечения более чем 10000 элементов, является векторным индексом, таким как faiss, nmslib или annoy, использующий некоторую реализацию приближенного поиска ближайших соседей, такую как кластеризация, деревья или алгоритм HNSW.

Также существуют управляемые решения, такие как OpenSearch или ElasticSearch и векторные базы данных, которые заботятся о процессе ввода данных, описанном на первом шаге, под капотом, такие как Pinecone, Weaviate или Chroma.

В зависимости от выбора индекса, данных и потребностей в поиске вы также можете хранить метаданные вместе с векторами и затем использовать фильтры метаданных, чтобы искать информацию в определенных датах или источниках, например.

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

2. Иерархические индексы

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

2.3 Гипотетические вопросы и HyDE

Другой подход заключается в том, чтобы попросить LLM сгенерировать вопрос для каждого фрагмента и встроить эти вопросы векторы во время выполнения запроса поиска в этом индексе вопросов (замена векторов фрагментов векторами вопросов в нашем индексе), а затем после получения маршрутизировать к исходным текстовым фрагментам и отправить их в качестве контекста для получения ответа от LLM. Этот подход повышает качество поиска за счет большей семантической схожести между запросом и гипотетическим вопросом по сравнению с реальным фрагментом.

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

2.4 Обогащение контекста

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

2.4.1 Извлечение предложений из окнаВ этой схеме каждое предложение в документе встраивается отдельно, что обеспечивает высокую точность косинусного расстояния между запросом и контекстом. Чтобы лучше рассуждать по найденному контексту после выборки наиболее релевантного предложения мы расширяем окно контекста на k предложений до и после выбранного предложения, а затем отправляем этот расширенный контекст в LLM.

Зеленая часть – это встраивание предложения, найденного при поиске в индексе, а весь черный + зеленый абзац передается в LLM для расширения его контекста при рассуждении на основе предоставленного запроса

2.4.2 Автоматическое объединение запросов (также известное как извлечение родительского документа)

Идея здесь очень похожа на извлечение предложений из окна — искать более частные информационные фрагменты и затем расширять окно контекста перед отправкой этого контекста в LLM для рассуждения. Документы разделяются на более мелкие дочерние фрагменты, относящиеся к более крупным родительским фрагментам.

Documents are splitted into an hierarchy of chunks and then the smallest leaf chunks are sent to index. At the retrieval time we retrieve k leaf chunks, and if there is n chunks referring to the same parent chunk, we replace them with this parent chunk and send it to LLM for answer generation.

Сначала получите более мелкие фрагменты при извлечении, а затем, если в топ k найденных фрагментах связано больше, чем n фрагментов с одним и тем же родительским узлом (большим фрагментом), замените контекст, подаваемый в LLM, этим родительским узлом — работает по принципу автоматического объединения нескольких найденных фрагментов в более крупный родительский фрагмент, отсюда и название метода. Просто отметим, что поиск выполняется только в индексе дочерних узлов. Посмотрите руководство LlamaIndex по рекурсивному извлечению + ссылки на узлы для более подробной информации.

Относительно старая идея, которая позволяет вам взять лучшее от обоих миров — старомодный поиск на основе ключевых слов — алгоритмы разреженного извлечения, такие как tf-idf или отраслевые стандарты поиска, такие как BM25, — и современный семантический или векторный поиск и объединить их в один результат поиска. Единственная хитрость в том, чтобы правильно объединить полученные результаты с разными оценками сходства — эту проблему обычно решают с помощью алгоритма Reciprocal Rank Fusion, пересортировки полученных результатов для окончательного вывода.

В LangChain это реализовано в классе Ensemble Retriever, который объединяет список созданных вами ретриверов, например, базирующихся на векторном индексе faiss и базирующихся на BM25 ретриверах, и использует RRF для переранжировки.

В LlamaIndex это делается в довольно похожем стиле done.

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

3. Переранжировка и фильтрация

Итак, у нас есть результаты поиска с помощью любого из описанных выше алгоритмов, теперь пришло время уточнить их с помощью фильтрации, повторной ранжировки или преобразования. В LlamaIndex есть разнообразие доступных Постпроцессоров, которые фильтруют результаты на основе балла схожести, ключевых слов, метаданных или переранжируют их с помощью других моделей, таких, как LLM, перекодировщик предложений на основе sentence-transformer, Cohere переранжирующий эндпоинт или на основе метаданных, таких, как свежесть данных — в общем, все, что вы можете представить.

Это последний шаг перед передачей извлеченного контекста в LLM для получения итогового ответа.

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

4. Преобразование запроса

Преобразование запроса — это семейство техник, использующих LLM в качестве резонирующего движка для модификации пользовательского ввода с целью улучшения качества поиска. Здесь есть разные варианты.

Query transformation principles illustrated

Если запрос сложный, LLM может разделить его на несколько подзапросов. Например, если вы спрашиваете: — “Какой фреймворк имеет больше звезд на Github, LangChain или LlamaIndex?”, скорее всего нам не удастся найти прямое сравнение в тексте нашего корпуса, поэтому имеет смысл разложить этот вопрос на два подзапроса, предполагающих более простой и конкретный информационный поиск: — “Сколько звезд у LangChain на Github?” — “Сколько звезд у LlamaIndex на Github?” Они будут выполняться параллельно, а затем полученный контекст будет объединен в одну подсказку для LLM, чтобы синтезировать окончательный ответ на исходный запрос. Обе библиотеки реализовали эту функцию — как многократный поисковик запросов в LangChain и как подзапросный поисковик запросов в LlamaIndex.

  1. Шаг обратной подсказки использует LLM для генерации более общего запроса, для которого мы получаем более общий или высокоуровневый контекст, полезный для обоснования ответа на наш исходный запрос. Также выполняется поиск для исходного запроса, и оба контекста передаются в LLM на этапе генерации конечного ответа. Здесь представлена реализация в LangChain implementation.
  2. Переписывание запроса использует LLM для переформулирования исходного запроса с целью улучшения поиска. В LangChain и в LlamaIndex есть реализации, которые, правда, немного отличаются, но я считаю решение LlamaIndex более мощным в этом случае.

Ссылки на источники

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

Есть несколько способов сделать это:

  1. Вставьте эту задачу ссылки в нашу инструкцию и попросите LLM указать идентификаторы используемых источников.
  2. Сравните части сгенерированного ответа с оригинальными текстовыми фрагментами в нашем индексе — llamaindex предлагает эффективное решение на основе нечеткого сопоставления для этого случая. Если вы не слышали о нечетком сопоставлении, это очень мощный метод сопоставления строк.

5. Чат-движок

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

Как всегда, существует несколько подходов к сжатию контекста — популярный и относительно простой ContextChatEngine первоначально находит контекст, соответствующий запросу пользователя, а затем отправляет его в LLM вместе с историей чата из буфера памяти для того, чтобы LLM мог учитывать предыдущий контекст при генерации следующего ответа.

Немного более сложный случай — CondensePlusContextMode — здесь в каждом взаимодействии история чата и последнее сообщение сжимаются в новый запрос, который затем отправляется в индекс, а полученный контекст передается в LLM вместе с исходным пользовательским сообщением для генерации ответа.

Важно отметить, что также поддерживается Чат-движок на основе агентов OpenAI в LlamaIndex, обеспечивающий более гибкий режим чата, и Langchain также поддерживает функциональное API OpenAI.

Иллюстрация различных типов и принципов чат-движков

Существуют и другие типы чат-движков, например, ReAct Agent, но давайте перейдем к самим агентам в разделе 7.

6. Маршрутизация запросов

Маршрутизация запросов – это этап принятия решения системой LLM о том, что делать дальше, основываясь на запросе пользователя – опции обычно состоят в том, чтобы выполнить сводку, выполнить поиск по некоторому индексу данных или попробовать несколько разных путей, а затем синтезировать их результат в один ответ.

Маршрутизаторы запросов также используются для выбора индекса или, в более широком смысле, хранилища данных, куда отправить запрос пользователя – либо у вас есть несколько источников данных, например, классическое векторное хранилище и графовая база данных или реляционная БД, либо у вас есть иерархия индексов – для много-документного хранилища классическим примером будет индекс сводок и другой индекс векторов фрагментов документов, например.

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

И LlamaIndex, и LangChain поддерживают маршрутизацию запросов.

7. Агенты в RAG

Агенты (поддерживаемые как LangChain, так и LlamaIndex) существуют практически с момента выпуска первого LLM API – идея заключалась в том, чтобы предоставить LLM с возможностью рассуждения набор инструментов и задание для выполнения. Инструментарий может включать в себя некоторые детерминированные функции, такие как любая функция кода, внешний API, или даже другие агенты – эта идея цепочки LLM также объясняет происхождение названия проекта LangChain.

Агенты – это огромная тема сама по себе, и невозможно углубиться достаточно глубоко в эту тему в рамках обзора RAG, поэтому я продолжу с примером выборки документов на основе агентов с учетом контекста, а также сделаю короткую остановку на станции OpenAI Assistants, поскольку это относительно новое явление, представленное на недавней конференции разработчиков OpenAI как GPTs, и работает под капотом описанной ниже системы RAG.

OpenAI Assistants в основном реализовали набор необходимых инструментов вокруг LLM, которые ранее были доступны в открытом доступе – история переписки, хранилище знаний, интерфейс для загрузки документов и, что, возможно, самое важное, API вызовы функций. Последний предоставляет возможности преобразования естественного языка в вызовы API для внешних инструментов или запросов в базу данных.

В LlamaIndex есть класс OpenAIAgent, объединяющий эту продвинутую логику с классами ChatEngine и QueryEngine, обеспечивая общение на основе знаний с учетом контекста и возможность множественных вызовов функций OpenAI за один раз в ходе разговора, что действительно придаёт агентскому поведению интеллект.

Давайте рассмотрим схему с множеством документов агентов – довольно сложное настройка, которая включает инициализацию агента (OpenAIAgent) на каждый документ, способного к суммированию документов и классической механике QA, а также верхний агент, ответственный за маршрутизацию запросов к агентам-документам и синтез окончательного ответа.

У каждого агента документа есть два инструмента – векторный индекс хранилища и сводный индекс, и на основе маршрутизованного запроса агент решает, который использовать. Что касается верхнего агента, то все агенты документов являются соответствующими инструментами.

Эта схема иллюстрирует сложную архитектуру RAG с множеством принимаемых решений каждым агентом. Преимуществом такого подхода является возможность сравнить различные решения или сущности, описанные в разных документах и их сводках, вместе с классическими механизмами суммирования одного документа и QA – этот подход в основном охватывает самые частые случаи общения с коллекцией документов.

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

Сложность такой сложной схемы можно предполагать по картинке – она немного медленна из-за множественных обратных итераций с LLM внутри наших агентов. В случае чего, вызов LLM всегда является самой долгой операцией в конвейере RAG – поиск оптимизирован для скорости по своему дизайну. Поэтому для большого хранилища многих документов я бы порекомендовал подумать о некоторых упрощениях данной схемы, чтобы сделать ее масштабируемой.

8. Синтезатор ответа

Это финальный этап любого RAG пайплайна – генерация ответа на основе всего контекста, который мы тщательно собрали, и исходного запроса пользователя. Самый простой подход заключается в простом объединении и применении всех полученных контекстов (выше некоторого порога релевантности) вместе с запросом к LLM одновременно. Но, как всегда, существуют и другие более сложные варианты, включающие множественные вызовы LLM для уточнения полученного контекста и генерации более качественного ответа.

Основные подходы к синтезу ответа:1. Итеративное уточнение ответа путем пошаговой отправки полученного контекста в LLM 2. Суммирование полученного контекста для соответствия запросу3. Генерация нескольких ответов на основе разных частей контекста, а затем их объединение или суммирование. Для более подробной информации обратитесь к документации модуля Response Synthesizer.

Fine-Tuning энкодера и LLM

Этот подход включает тонкую настройку двух DL моделей, используемых в нашем RAG пайплайне — либо трансформера энкодера, отвечающего за качество векторных представлений и, таким образом, качество извлечения контекста, либо LLM, отвечающего за оптимальное использование предоставленного контекста для ответа на запрос пользователя — к счастью, последний является эффективным обучаемым модулем.

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

Тонкая настройка энкодера

Я также была немного скептически настроена по отношению к подходу тонкой настройки энкодера, так как последние оптимизированы для поиска довольно эффективно. Поэтому я проверила, насколько возросла производительность после настройки модели bge-large-en-v1.5 (топ 4 в таблице MTEB на момент написания) во время работы над записью LlamaIndex, и это показало увеличение качества извлечения в размере 2%. Ничего революционного, но всегда полезно знать о такой возможности, особенно если у вас есть узкоспециализированный набор данных, для которого вы создаете RAG.

Тонкая настройка ранжировщика

Другой старый, но хороший вариант – использование перекрестного энкодера для переоценки ваших полученных результатов, если вы не полностью доверяете своему базовому энкодеру. Это работает следующим образом: вы передаете запрос и каждый из k лучших восстановленных текстовых фрагментов в перекрестный энкодер, разделенный символом SEP, и тонко настраиваете его для вывода 1 для релевантных фрагментов и 0 для нерелевантных. Хорошим примером такого процесса настройки является это, где результаты говорят, что попарный балл был улучшен на 4% при тонкой настройке перекрестного энкодера.

Тонкая настройка LLM

Недавно OpenAI начали предоставлять API для тонкой настройки LLM и LlamaIndex имеет учебное пособие по тонкой настройке GPT-3.5-turbo в рамках составления RAG для “извлечения” некоторых знаний из GPT-4. Идея состоит в том, чтобы взять документ, сформировать ряд вопросов с использованием GPT-3.5-turbo, затем использовать GPT-4 для генерации ответов на эти вопросы на основе содержимого документа (создать пайплайн RAG на базе GPT-4) и затем провести тонкую настройку GPT-3.5-turbo на этом наборе пар вопрос-ответ. Фреймворк ragas, используемый для оценки пайплайна RAG, показывает увеличение показателей достоверности на 5%, что означает, что модель GPT 3.5-turbo, настроенная в результате, лучше использует предоставленный контекст для генерации ответа, чем первоначальная модель.

Немного более утонченный подход демонстрируется в недавней статье RA-DIT: Расширение двухкратного исправления с помощью усиленной рекомендации от Meta AI Research, предлагающей технику настройки как LLM, так и Retriever (двухкодировщик в исходной статье) на тройках запросов, контекста и ответов. По подробностям реализации обратитесь к этому руководству. Эта техника была использована как для настройки OpenAI LLM с помощью API калибровки, так и модели с открытым исходным кодом Llama2 (в исходной статье), что привело к приросту показателей задач, требующих интеллектуальных знаний (по сравнению с Llama2 65B с RAG), а также к нескольким процентам прироста в задачах рассуждения на здравый смысл.

Если вы знаете более эффективные подходы к калибровке LLM для RAG, поделитесь своими знаниями в разделе комментариев, особенно если они применяются к меньшим моделям LLM с открытым исходным кодом.

Оценка

Существует несколько каркасов для оценки производительности RAG-систем, основанных на идее использования нескольких отдельных метрик, таких как общая релевантность ответа, опорная способность ответа, достоверность ответа и релевантность извлеченного контекста.

Ragas, упомянутый в предыдущем разделе, использует метрики качества сгенерированного ответа, такие как достоверность и релевантность ответа, а также классические метрики контекстной точности и полноты для части, связанной с извлечением.

В недавно опубликованном отличном кратком курсе Построение и оценка продвинутых RAG от Эндрю НГ, LlamaIndex и каркас оценки Truelens предлагают триаду RAGрелевантность извлеченного контекста для запроса, опорную способность (насколько ответ LLM подтверждается предоставленным контекстом) и релевантность ответа для запроса.

Ключевая и наиболее контролируемая метрика — это релевантность извлеченного контекста — в основном части 1–7 продвинутого RAG-пайплайна, описанного выше, а также калибровка кодировщика и ранжировщика направлены на улучшение этой метрики, в то время как часть 8 и калибровка LLM фокусируются на релевантности ответа и опорной способности.

Хорошим примером довольно простого пайплайна оценки извлекателя является здесь, и он применяется в разделе калибровки кодировщика. Более развитый подход, учитывающий не только показатель попадания, но и среднюю взаимную ранговую оценку — общую метрику поисковой системы, а также метрики качества сгенерированного ответа, такие как достоверность и релевантность, продемонстрирован в книге рецептов OpenAI cookbook.

LangChain имеет довольно развитый фреймворк оценки LangSmith, где можно реализовать пользовательские оценщики, а также отслеживать процессы, запускаемые внутри вашего RAG-пайплайна для обеспечения большей прозрачности системы.

Если вы строите с помощью LlamaIndex, существует llama pack оценщика, предоставляющий быстрый инструмент для оценки вашего пайплайна с использованием общедоступного набора данных.

Заключение

Я попытался обрисовать основные алгоритмические подходы к RAG и проиллюстрировать некоторые из них, надеясь, что это может возбудить некоторые новые идеи для попробовать в вашем RAG процессе, или принести некоторую систему в огромное разнообразие техник, которые были изобретены в этом году – для меня 2023 год был самым захватывающим годом в области машинного обучения до сих пор.

Есть еще много других вещей, которые следует учесть, таких как поиск основанный на веб-ресурсах RAG (RAG от LlamaIndex, webLangChain, и др.), углубленное изучение агентивных архитектур (и недавний интерес OpenAI к этой сфере) и некоторые идеи о долговременной памяти LLM.

Основная проблема в производстве для систем RAG помимо актуальности и достоверности ответа – это скорость, особенно если вы выбираете более гибкие схемы на основе агента, но это уже тема для другого поста. Эта функция потоковой передачи, которую используют ChatGPT и большинство других помощников, не случайна в стиле киберпанка, а просто способ сократить время генерации ответа. Вот почему я вижу очень светлое будущее для меньших LLM, и недавние релизы Mixtral и Phi-2 ведут нас в этом направлении.

Большое спасибо за прочтение этого длинного поста!

Основные источники собраны в моей базе знаний, есть также соавтор для общения с этим набором документов: https://app.iki.ai/playlist/236.

Найдите меня на LinkedIn или Twitter