Как построить RAG-пайплайн для корпоративных документов: от идеи до продакшна

AI и LLM
Как построить RAG-пайплайн для корпоративных документов: от идеи до продакшна

TL;DR: RAG (Retrieval Augmented Generation) — это мощный подход для использования LLM с вашей корпоративной информацией. Он позволяет моделям отвечать на вопросы, основываясь на актуальных и релевантных данных, которые не были частью их изначального обучения. По сути, мы учим модель искать нужную информацию в вашей базе знаний и затем генерировать ответ, опираясь на найденное.

Зачем вообще RAG для корпоративных документов?

Смотри, LLM-ки, конечно, крутые, но у них есть две большие проблемы, когда дело доходит до корпоративного использования:

  1. Галлюцинации: Они могут выдумывать факты, если не знают ответа или не уверены в нём. В бизнесе это недопустимо.
  2. Устаревшая информация: Модели обучаются на данных до определённого момента. Всё, что произошло после, им неведомо. А корпоративные документы постоянно меняются.

Вот тут RAG и приходит на помощь. Мы не переобучаем модель (это дорого и долго), а даём ей возможность «подсмотреть» в наши актуальные документы перед тем, как ответить. Это как дать студенту доступ к учебнику во время экзамена — шансы на правильный ответ сильно возрастают.

Основные компоненты RAG-пайплайна

Давай разберём, из чего состоит типичный RAG-пайплайн. Это не rocket science, но каждый шаг важен.

Источники данных и ингест (Data Ingestion)

Первый шаг — собрать все ваши корпоративные документы. Это могут быть:

  • PDF-файлы (договоры, отчёты)
  • Документы Word, Excel, PowerPoint
  • Страницы Confluence или SharePoint
  • Базы данных (SQL, NoSQL)
  • Электронные письма
  • Корпоративные wiki

Задача ингеста — извлечь текст из этих разнообразных форматов. Здесь могут понадобиться специальные библиотеки для парсинга PDF (например, PyPDF2, fitz из PyMuPDF), конвертации DOCX, или коннекторы к API ваших систем.

Разбиение на чанки (Chunking)

После извлечения текста у нас есть большой объём данных. LLM-ки имеют ограничение на размер входного контекста (context window). Мы не можем подать им весь многостраничный документ целиком. Поэтому мы разбиваем текст на более мелкие, осмысленные части — чанки.

Ключевые моменты при чанкинге:

  • Размер чанка: Обычно от 200 до 1000 токенов (или 500-2000 символов). Слишком маленькие чанки могут потерять контекст, слишком большие — не поместиться в контекст LLM.
  • Перекрытие (overlap): Чтобы не потерять контекст между чанками, полезно делать небольшое перекрытие (например, 10-20% от размера чанка). Это гарантирует, что важная информация, находящаяся на границе чанков, не будет разорвана.
  • Сохранение структуры: По возможности, чанки должны быть логически завершенными (предложения, абзацы, разделы).

Примерный подход к чанкингу текста:

from langchain.text_splitter import RecursiveCharacterTextSplitter

def split_document_into_chunks(text: str, chunk_size: int = 1000, chunk_overlap: int = 200):
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=chunk_size,
        chunk_overlap=chunk_overlap,
        length_function=len,
        add_start_index=True,
    )
    chunks = text_splitter.create_documents([text])
    return chunks

Создание эмбеддингов (Embeddings Generation)

Каждый чанк нужно преобразовать в числовой вектор — эмбеддинг. Эмбеддинги — это многомерные векторы, которые отражают семантическое значение текста. Чанки с похожим смыслом будут иметь “близкие” векторы в векторном пространстве.

Для этого используются специальные модели эмбеддингов (например, OpenAI Embeddings, Sentence Transformers, GTE). Выбор модели зависит от бюджета, требований к производительности и качеству.

from langchain_openai import OpenAIEmbeddings

def generate_embeddings(chunks):
    # Используем OpenAIEmbeddings как пример. Можно заменить на другие модели.
    embedding_model = OpenAIEmbeddings(model="text-embedding-ada-002")
    # chunks - это список объектов Document, как возвращает RecursiveCharacterTextSplitter
    # Для каждого чанка нужно получить его content
    chunk_texts = [chunk.page_content for chunk in chunks]
    embeddings = embedding_model.embed_documents(chunk_texts)
    return embeddings

Векторная база данных (Vector Database)

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

Популярные векторные базы:

  • Pinecone
  • Weaviate
  • Qdrant
  • Chroma
  • Milvus
  • FAISS (локальная библиотека для поиска, не полноценная DB)

Векторная БД будет нашим основным хранилищем знаний.

Поиск релевантной информации (Retrieval)

Когда пользователь задаёт вопрос, происходит следующее:

  1. Вопрос пользователя также преобразуется в эмбеддинг с помощью той же модели, что использовалась для чанков.
  2. Этот вектор запроса используется для поиска ближайших (наиболее семантически похожих) векторов в векторной базе данных. Это и есть retrieval — извлечение релевантных чанков.
  3. Обычно извлекается N самых релевантных чанков (например, N=3-5).

Генерация ответа (Generation)

Полученные релевантные чанки вместе с исходным вопросом пользователя подаются на вход большой языковой модели (LLM).

Промпт для LLM будет выглядеть примерно так:

Используй предоставленный ниже контекст, чтобы ответить на вопрос.
Если ты не можешь найти ответ в контексте, скажи, что не знаешь.
Не придумывай информацию.

Контекст:
---
[Здесь вставляются извлеченные чанки]
---
Вопрос: [Вопрос пользователя]

Ответ:

LLM, опираясь на этот расширенный контекст, генерирует ответ.

Архитектура RAG-пайплайна: типовой сценарий

Представим типовую архитектуру для корпоративного RAG-бота:

+-------------------+      +-----------------+      +-------------------+
| Корпоративные     |      | Модуль          |      | Модуль            |
| Документы         |----->| Ингеста данных  |----->| Чанкинга и        |
| (PDF, DOCX, Wiki) |      | (Парсинг, OCR)  |      | Эмбеддингов       |
+-------------------+      +-----------------+      +-------------------+
                                   |                       |
                                   V                       V
+-----------------------------------------------------------------------+
|                 Векторная База Данных (Pinecone, Qdrant)              |
|          (Хранит эмбеддинги чанков и метаданные)                      |
+-----------------------------------------------------------------------+
                                   ^
                                   |
                                   | (поиск релевантных чанков)
                                   |
+-------------------+      +-----------------+      +-------------------+
| Пользовательский  |----->| API-шлюз /      |----->| Модуль            |
| Запрос            |      | Backend-сервис  |      | Поиска (Retriever)|
| (Чатбот, UI)      |      |                 |      |                   |
+-------------------+      +-----------------+      +-------------------+
                                   |                       |
                                   | (вопрос + релевантные чанки)
                                   V
+-----------------------------------------------------------------------+
|                 Большая Языковая Модель (LLM)                         |
|                 (GPT-4, Claude, Llama 3)                              |
+-----------------------------------------------------------------------+
                                   |
                                   V
+-------------------+
| Ответ Пользователю|
+-------------------+

Оптимизация и продвинутые техники

RAG — это не просто линейный пайплайн. Есть много способов его улучшить:

Оптимизация чанкинга

  • Семантический чанкинг: Разбиение на чанки не по фиксированному размеру, а по смысловым границам (например, с использованием NLP-моделей для определения границ тем).
  • Родитель-дочерний чанкинг: Храним как маленькие, детализированные чанки, так и большие, контекстные. При поиске сначала ищем в маленьких, а затем извлекаем родительский чанк для более широкого контекста.

Улучшение ретривера

  • Гибридный поиск (Hybrid Search): Комбинация векторного поиска (семантика) с полнотекстовым поиском по ключевым словам (BM25, TF-IDF). Это помогает найти документы, где ключевые слова важны, но семантика может быть немного другой.
  • Переранжирование (Re-ranking): После извлечения N чанков, можно использовать отдельную, более лёгкую модель (re-ranker) для их повторной оценки релевантности и выбора лучших K чанков. Это позволяет отфильтровать шум.
  • Мультимодальный RAG: Если документы содержат изображения, таблицы, графики, можно создавать эмбеддинги не только текста, но и других модальностей.

Работа с LLM

  • Промпт-инжиниринг: Тонкая настройка системного промпта для LLM, чтобы она лучше понимала задачу и генерировала более качественные ответы.
  • Использование нескольких LLM: Для разных задач (например, одна LLM для извлечения сущностей из запроса, другая для генерации ответа).

Ключевые метрики для оценки RAG-пайплайна

Как понять, что наш RAG работает хорошо? Нужны метрики:

  • Релевантность (Relevance): Насколько извлеченные чанки действительно относятся к вопросу.
  • Полнота (Recall): Насколько полно извлеченные чанки покрывают информацию, необходимую для ответа.
  • Точность ответа (Answer Faithfulness): Насколько ответ LLM соответствует информации, содержащейся в извлеченных чанках (отсутствие галлюцинаций).
  • Полезность ответа (Answer Relevance): Насколько ответ LLM полезен и адекватен запросу пользователя.

Эти метрики часто оцениваются как автоматически (с помощью других LLM или синтетических данных), так и вручную экспертами.

FAQ

Q1: Какую векторную базу данных выбрать?

A1: Выбор зависит от масштаба проекта, бюджета, требований к производительности и простоты развертывания. Для небольших проектов Chroma или FAISS могут быть достаточны. Для продакшн-систем с большим объёмом данных и высокими требованиями к надёжности и масштабированию часто выбирают Pinecone, Weaviate или Qdrant.

Q2: Какие модели эмбеддингов лучше использовать?

A2: Для коммерческих проектов OpenAI Embeddings (text-embedding-ada-002, text-embedding-3-small, text-embedding-3-large) показывают очень хорошие результаты. Если нужен open-source вариант, то хорошо себя зарекомендовали модели из семейства Sentence Transformers (например, all-MiniLM-L6-v2, BAAI/bge-large-en-v1.5). Выбор зависит от языка документов, требований к качеству и доступных ресурсов.

Q3: Сколько чанков подавать в LLM?

A3: Обычно подают от 3 до 7 наиболее релевантных чанков. Слишком мало может привести к неполным ответам, слишком много — к “засорению” контекста LLM, увеличению стоимости и времени генерации, а также к “потере в середине” (LLM может хуже обрабатывать информацию, находящуюся в середине длинного контекста).

Q4: Можно ли использовать RAG без векторной базы данных?

A4: Теоретически можно использовать полнотекстовый поиск (например, Elasticsearch) для извлечения документов, а затем передавать их в LLM. Однако векторный поиск обеспечивает гораздо лучшую семантическую релевантность, находя документы по смыслу, а не только по ключевым словам. Для большинства RAG-приложений векторная база данных является ключевым компонентом.

Q5: Насколько сложно поддерживать RAG-пайплайн?

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

Нужна помощь с построением RAG-пайплайна для ваших корпоративных документов? Напишите мне — обсудим ваш проект.

Обсудить проект

Есть идея или задача? Давайте обсудим, как можно её реализовать с помощью современных AI-технологий.

Написать мне
Вернуться к блогу