← все записи

RAG ты мне или не RAG


Госпади, какой я креативный, ну что за прекрасное название у статьи (нет).

В этом доке я начну цикл статей про использование векторных баз данных (они же RAG) для документации.

Если вы исповедуете подход doc-as-code, то для вас тема RAG может быть очень близка. Но даже для любителей Confluence и ведения документации в мессенджерах, данное решение может быть полезным.

Какой у меня план:

  • рассказать, что это за зверь такой;
  • сравнить RAG с обычным поиском;
  • поведать, когда вам нужен RAG;
  • привести немного советов о том, как лучше готовить текст, чтобы RAG был доволен;
  • рассказать, как поднять свой вектор (гусары, молчать);
  • провести серию экспериментов, чтобы узнать, что влияет на качество;
  • подвести итоги и выпить вина (кого я обманываю, пить вино я собираюсь на каждом этапе).

В начале был поиск

Если уж я начал использовать клише в заголовках, то меня не остановить.

Давайте немного отмотаем назад. У нас есть какие-то тексты, и мы хотим сделать поиск по ним. Подход в лоб: мы загоняем все тексты в хранилище (база данных) и при поиске тупо ищем те же слова в этом хранилище, что ввели в поисковую строку. Работает плохо, долго, всех бесит.

Поиск получше — мы не просто загоняем наш текст в базу данных, а для начала анализируем его и составляем индекс. В результате наш поиск знает, в каких документах у нас встречается нужное нам слово, умеет поднимать выше в выдаче статьи, где это слово встречается чаще или входит в заголовок. Если вдруг вы любите математику, то можно почитать про BM25 (Best Matching 25) и его разновидности. Это как раз о том, как всё работает под капотом.

Да кто такой этот ваш RAG?

RAG — это векторная база данных. Почему векторная? Потому что состоит из векторов. С вас пять тысяч, вот ваш сертификат.

Ладно, едем дальше. И вот однажды у нас появились LLM. Инженер Борисов, проснувшись утром с бодуна, решил, что хватит ему страдать от поиска в Confluence, нужно что-то менять. Он взял и прогнал текст с помощью специального скрипта, задача которого — взять кусок текста, скормить его в LLM и получить на выходе набор цифр. Этот набор цифр знающие люди и называют — вектор. Никто его никогда в природе не видел, но математики в него верят, а чувства верующих мы уважаем.

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

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

  • “красные кроссовки”
  • “обувь для бега”
  • “смартфон”

Мы засовываем их через наш скрипт в LLM, а она, не будь дура, понимает, что первые две фразы близки по смыслу, а третья вообще далека (если только у вас не текст про обычный день в Лондоне). И вот она выдаёт результат:

“красные кроссовки” → [0.82, 0.15, 0.91, 0.05, 0.77]

“обувь для бега” → [0.79, 0.18, 0.88, 0.04, 0.74]

“смартфон” → [0.12, 0.93, 0.20, 0.85, 0.33]

Видите эти цифры в квадратных скобках? Это и есть векторы. Заметили, что для первых двух фраз значения ближе друг к другу, чем у третьей?

И вот наш инженер Борисов берёт эти векторы и делает новый поиск, который ищет уже не слова или фразы, а сравнивает между собой векторы. Опять же, мы выкидываем тут подробности про математику этих сравнений, там всякие косинусы между векторами. Вы молодые, дерзкие, оно вам не надо.

Что же нам даёт такой подход? А даёт он нам возможность искать смыслы. Правда, смысла жизни пока никто так и не нашел, но мы не сдаёмся. Так вот, если взять фразы из нашего примера, то при запросе в поиск “спортивная обувь” LLM создаст для него вектор. После чего сравнит его с нашими векторами и вернёт “красные кроссовки” и “обувь для бега”, а “смартфон” не вернёт (ну прям как в Лондоне опять).

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

Сколько вешать в RAG-ах

Что ж это получается — сжечь обычный поиск, даёшь RAG в каждый дом? Эх, если бы. Проблема в том, что для создания индекса обычному поиску требуется в десятки раз меньше времени, чем для создания векторной базы данных. А ещё в том, что поиск в RAG идёт через LLM, а это больше денег/ресурсов и дольше, чем работа обычного поиска.

Пытливый читатель спросит меня, так какой поиск стоит выбрать? Факторов много, но если кратко, то так:

  • Если у вас хорошая база знаний, которую ведёт умелый технический писатель или лицо, выполняющее функции умелого технического писателя, то в 99% случаев классический BM25F поиск для вас будет работать отлично. Потому что у вас есть хорошо структурированные статьи с ответами на большинство вопросов, которые задают ваши пользователи.
  • Если же у вас много различных статей со сложными смыслами, нужно не просто искать информацию, а формулировать ответы на вопросы на основе статей из базы знаний, то вам стоит попробовать RAG.

Естественно, если у вас вообще нет базы знаний, то RAG вам не поможет. Но я, наверное, мог бы об этом и не говорить.

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

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

Ну и вброс на будущее — инженеру Борисову в очередной раз было скучно, и он решил, что просто RAG — это для слабаков. Поэтому он придумал GraphRAG — это вектор, но с графами связей над данными. Вот и живите теперь с этим.