В сфере искусственного интеллекта технологии генерации ответов на основе расширенной выборки (RAG) стали стандартом для адаптации больших языковых моделей под частные данные. В детальном руководстве от инженера Пауло на платформе freeCodeCamp.org подробно разбирается эволюция от базовой архитектуры RAG до продвинутых техник борьбы с шумом и галлюцинациями. Материал представляет собой пошаговый разбор практической реализации систем поиска с примерами кода и графическим анализом векторных пространств.
🧩 Основы RAG: зачем языковым моделям внешняя память 0:00
Большие языковые модели (LLM) обладают колоссальным объемом знаний, однако они строго ограничены данными, на которых проходили обучение. Если спросить у базовой версии ChatGPT столицу Франции, модель мгновенно выдаст правильный ответ. Однако попытка узнать у нее кличку вашей первой собаки предсказуемо закончится провалом.
Концепция RAG (Retrieval Augmented Generation) элегантно решает эту проблему. Вместо дорогостоящего и сложного процесса дообучения (fine-tuning) всей нейросети, RAG позволяет «впрыскивать» (inject) сторонние структурированные или неструктурированные данные напрямую в контекст модели. В результате LLM получает доступ к актуальной информации пользователя и формирует точные ответы на специфические вопросы.
По определению автора курса, RAG представляет собой фреймворк, объединяющий сильные стороны поисковых систем и генеративных моделей для создания контекстуально релевантных ответов. Архитектура системы опирается на два фундаментальных элемента:
- Искатель (Retriever): отвечает за сканирование, идентификацию и извлечение релевантных документов из внешнего хранилища.
- Генератор (Generator): принимает извлеченные фрагменты данных вместе с исходным запросом пользователя и синтезирует связный, логичный ответ.
🛠️ Настройка окружения и первый практический запуск 2:17
Для развертывания базовой системы RAG потребуется стандартный стек инструментов разработчика. Автор курса рекомендует использовать редактор VS Code и разворачивать код на языке Python. Важным условием для выполнения практических шагов является наличие активного аккаунта разработчика OpenAI и сгенерированного API-ключа.
Начальный этап включает создание изолированного виртуального окружения и установку ключевых библиотек. В терминале выполняются следующие команды:
source vnv/activate
pip install python-dotenv
pip install openai
pip install chromadb
Проект под кодовым названием rag intro состоит из файла конфигурации .env, где прописывается токен OPENAI_API_KEY, и основного скрипта app.py. Для создания векторных представлений (эмбеддингов) инициализируется легковесная модель text-embedding-3-small от OpenAI. В качестве хранилища векторов используется база данных Chroma DB, которая разворачивается локально в режиме persistent-клиента для сохранения данных на диске.
📐 Нативная архитектура Naive RAG шаг за шагом 7:14
Классический, или так называемый «наивный» RAG (Naive RAG) работает в рамках линейного конвейера, состоящего из трех последовательных стадий: индексирование, поиск и генерация. Каждая стадия критически важна для итогового результата.
Процесс обработки кастомных данных выглядит следующим образом:
- Парсинг и предобработка документов (Chunking): исходные текстовые файлы разбиваются на небольшие фрагменты (чанки). В демонстрационном коде размер чанка установлен на уровне 1000 символов с перекрытием (overlap) в 20 символов. Перекрытие необходимо для сохранения сквозного контекста между соседними кусками текста.
- Векторизация и индексация: текстовые чанки отправляются в модель эмбеддингов, которая трансформирует слова в многомерные массивы чисел (векторы). Эти векторы записываются в таблицу базы данных Chroma DB.
- Поиск по сходству (Similarity Search): когда пользователь вводит поисковый запрос, этот запрос точно так же векторизуется через ту же модель эмбеддингов. База данных сопоставляет вектор запроса с векторами чанков и возвращает наиболее близкие по значению документы.
- Аугментация и генерация: оригинальный вопрос пользователя объединяется со специальным системным промптом и найденными текстовыми чанками. Этот дополненный пакет информации передается в модель
gpt-3.5-turbo, которая генерирует финальный осмысленный ответ.
В рамках практического теста Пауло загружает в систему 21 текстовую статью из папки news_articles. Система успешно справляется со специфическими запросами. На вопрос о забастовке сценаристов в США и угрозе применения ИИ (tell me about AI replacing TV writers in strike) скрипт безошибочно находит нужные чанки и выдает точную сводку требований Гильдии сценаристов Америки (WGA). Аналогично система отрабатывает запрос о покупке компании Okera гигантом Databricks.
⚠️ Подводные камни наивного подхода (Naive RAG Pitfalls) 39:06
Несмотря на простоту реализации, базовая архитектура сталкивается с серьезными технологическими барьерами. По словам Пауло, все проблемы наивного RAG можно условно разделить на два крупных лагеря: вызовы этапа извлечения (retrieval challenges) и вызовы этапа генерации (generative challenges).
Автор выделяет пять ключевых уязвимостей Naive RAG:
- Ограниченное понимание контекста: система опирается на простое семантическое сходство векторов. Если пользователь спрашивает о влиянии глобального потепления на полярных медведей, наивный поисковик может вытащить отдельно документы про медведей и отдельно про климат, но упустить критически важные статьи, описывающие взаимосвязь этих явлений.
- Нестабильное качество документов: механизмы ранжирования в Chroma DB по умолчанию могут выводить наверх устаревшие или нерелевантные источники, засоряя контекстное окно языковой модели. При запросе о последних исследованиях в этике ИИ система рискует выдать неактуальные данные.
- Плохая интеграция между компонентами: поисковый движок и LLM работают изолированно. В условиях отсутствия синергии генеративная модель может попросту проигнорировать важные факты из подложенных документов и выдать банальный, обобщенный ответ.
- Проблемы масштабирования: на огромных массивах корпоративных данных примитивные индексы начинают сильно тормозить процесс поиска, а также пропускать важные пласты информации из-за неэффективных стратегий сканирования.
- Хрупкость перед сложными запросами: если пользователь формулирует размытый, многоаспектный или двусмысленный запрос (например, обобщенный вопрос про индексные фонды и личные финансы), система извлекает разрозненные куски данных, неспособные сформировать комплексную картину.
🚀 Продвинутые техники: расширение запросов через гипотетические ответы 48:47
Чтобы преодолеть ограничения линейного конвейера, разработчики применяют продвинутые подходы (Advanced RAG), которые делятся на пре-ретривал (оптимизация до поиска) и пост-ретривал (оптимизация после поиска). Одной из мощных пре-ретривал техник является расширение поискового запроса с использованием гипотетических ответов (Query Expansion with Generated Answers).
Суть метода заключается в том, что оригинальный, зачастую сухой запрос пользователя сначала пропускается через LLM. Нейросеть просят «погаллюцинировать» и составить гипотетический, примерный ответ на этот вопрос, основываясь на ее общих знаниях. Затем этот сгенерированный гипотетический текст склеивается с оригинальным вопросом, и уже эта расширенная текстовая масса отправляется в векторную базу данных.
Логика подхода проста: семантически вектор гипотетического ответа гораздо ближе к реальным целевым документам в базе данных, чем вектор короткого и абстрактного вопроса. Данная техника находит активное применение в поисковых движках интернет-магазинов, корпоративных базах знаний и системах анализа научных публикаций.
💻 Практика расширения запросов на примере отчета Microsoft 54:28
Для демонстрации продвинутых техник автор меняет тестовый датасет на массивный годовой финансовый отчет корпорации Microsoft за 2023 год, содержащий более 110 страниц сложного технического текста.
Для реализации этого этапа требуется расширенный набор библиотек:
pip install pypdf
pip install langchain
pip install sentence-transformers
pip install umap-learn
pip install matplotlib
Текст из PDF-файла извлекается с помощью PyPDF. Затем применяется двухэтапное разбиение: сначала инструмент RecursiveCharacterTextSplitter делит текст на блоки по 1000 символов (получается 410 чанков), а затем SentenceTransformersTokenTextSplitter форматирует их в жесткие рамки по 256 токенов для соответствия ограничениям моделей (на выходе получается 419 токенов). Эмбеддинги генерируются через локальную функцию SentenceTransformerEmbeddingFunction.
В коде создается функция augment_query_generated, которая заставляет gpt-3.5-turbo притворяться экспертом-аналитиком и генерировать гипотетические финансовые ответы. При подаче сложного вопроса о чистой прибыли компании и ее сравнении с прошлым годом система генерирует реалистичный фейковый текст о прибыли в 10 миллиардов и успешном сокращении издержек.
Чтобы наглядно доказать эффективность метода, Пауло использует библиотеку umap-learn для снижения размерности векторов и проецирования многомерного векторного пространства на плоский 2D-график средствами matplotlib. Результаты визуализации однозначны:
- Красный маркер (X): исходный поисковый запрос пользователя находится на значительном удалении от кластера целевых данных.
- Оранжевый маркер (X): расширенный запрос (вопрос + гипотетический ответ) перемещается в самый центр плотного облака данных.
- Зеленые точки: документы, извлеченные базой данных по расширенному запросу, идеально окружают оранжевый маркер, подтверждая максимальную семантическую точность.
🔄 Расширение через множественные подзапросы (Multi-Query Expansion) 1:17:44
Еще одна фундаментальная техника, рассмотренная в рамках мини-курса — мультизапросное расширение (Multi-Query Expansion). Вместо попытки угадать один гипотетический ответ, система использует LLM для генерации пяти абсолютно разных по формулировке, но идентичных по смыслу подзапросов к одной и той же теме.
Например, для оригинального вопроса о факторах роста выручки (What details can you provide about the factors that led to revenue growth) модель генерирует 5 альтернативных векторов исследования:
- Влияние ценовых стратегий на рост доходов.
- Роль запусков новых продуктов.
- Вклад маркетинговых и рекламных кампаний.
- Изменения в клиентской демографии.
- Влияние стратегических партнерств и коллабораций.
Каждый из этих пяти вопросов отправляется в Chroma DB как независимый поисковый запрос. База данных возвращает массивы документов для каждого случая. Далее весь этот объем данных объединяется, программно очищается от дубликатов с помощью функций санитазации списков и передается в финальный промпт для LLM.
По оценке Пауло, такой подход незаменим при анализе запутанных финансовых или медицинских документов, так как он позволяет подсветить проблему с разных углов и минимизировать риск упустить важный факт. Однако у мультизапросного расширения есть и обратная сторона: лавинообразный рост извлекаемых документов может привносить избыточный семантический шум в контекст. Чтобы эффективно бороться с этим шумом, на следующих этапах построения зрелых RAG-систем разработчикам приходится внедрять дополнительные алгоритмы переранжирования (Reranking) результатов.