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

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

TL;DR: RAG-пайплайн для корпоративных документов — это система, которая находит релевантную информацию в базе знаний и генерирует ответы на её основе. Ключевые компоненты: препроцессинг документов, векторизация, поиск по сходству и генерация ответов через LLM.

Архитектура RAG-системы для корпоративных документов

RAG (Retrieval-Augmented Generation) решает главную проблему корпоративных LLM — отсутствие актуальной внутренней информации в обучающих данных. Вместо дообучения модели мы подаём ей контекст из собственных документов.

Типовая архитектура состоит из четырёх блоков:

Препроцессинг и индексация документов

  • Парсинг: извлечение текста из PDF, DOCX, HTML, внутренних систем
  • Чанкинг: разбивка на логические блоки (обычно 200-1000 токенов)
  • Векторизация: преобразование текста в эмбеддинги
  • Индексирование: сохранение в векторную БД

Поисковый модуль (Retriever)

  • Векторный поиск по семантическому сходству
  • Гибридный поиск (векторный + BM25)
  • Ре-ранжирование результатов

Генеративный модуль (Generator)

  • Формирование промпта с найденным контекстом
  • Генерация ответа через LLM
  • Постобработка и валидация

Система мониторинга

  • Логирование запросов и ответов
  • Метрики качества поиска
  • A/B тестирование промптов

Выбор технологического стека

Векторные базы данных

Основные варианты для корпоративного использования:

БДПлюсыМинусыКогда использовать
PineconeManaged, быстрыйДорого, vendor lock-inMVP, быстрый старт
WeaviateOpen source, GraphQLСложнее в настройкеГибкость, on-premise
QdrantRust, производительностьМолодой проектВысокие нагрузки
pgvectorPostgreSQL extensionОграниченная функциональностьЕсть PostgreSQL в стеке

Модели для эмбеддингов

  • OpenAI text-embedding-ada-002: универсальная, хорошее качество
  • Sentence-BERT: open source, можно дообучить
  • E5-large: отличное качество для русского языка
  • multilingual-e5: для многоязычных документов
# Пример создания эмбеддингов с OpenAI
import openai
from typing import List

def create_embeddings(texts: List[str]) -> List[List[float]]:
    response = openai.Embedding.create(
        model="text-embedding-ada-002",
        input=texts
    )
    return [item['embedding'] for item in response['data']]

Препроцессинг корпоративных документов

Стратегии чанкинга

Разбивка документов — критически важный этап. Плохой чанкинг убивает качество поиска.

Фиксированный размер (простой, но не оптимальный):

def fixed_chunk(text: str, chunk_size: int = 512, overlap: int = 50) -> List[str]:
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size
        chunk = text[start:end]
        chunks.append(chunk)
        start = end - overlap
    return chunks

Семантический чанкинг (лучше для качества):

  • По структуре документа (заголовки, параграфы)
  • По семантическим границам через sentence transformers
  • Гибридный подход с учётом размера

Обработка метаданных

Сохраняйте структурированную информацию:

  • Источник документа
  • Дата создания/обновления
  • Тип документа
  • Департамент/автор
  • Теги и категории

Это позволит фильтровать поиск и улучшить ранжирование.

Оптимизация качества поиска

Гибридный поиск

Комбинируйте векторный поиск с классическими методами:

def hybrid_search(query: str, vector_weight: float = 0.7):
    # Векторный поиск
    vector_results = vector_db.search(query, top_k=20)
    
    # BM25 поиск
    bm25_results = bm25_index.search(query, top_k=20)
    
    # Комбинирование скоров
    combined_results = combine_scores(
        vector_results, 
        bm25_results, 
        vector_weight
    )
    
    return combined_results[:10]

Ре-ранжирование

После первичного поиска применяйте модели ре-ранжирования для улучшения порядка результатов:

  • Cross-encoder модели (BERT-based)
  • Учёт метаданных и бизнес-логики
  • Персонализация по пользователю/роли

Query expansion

Расширяйте пользовательские запросы:

  • Синонимы и связанные термины
  • Переформулирование через LLM
  • Исправление опечаток

Промпт-инжиниринг для генерации ответов

Структура эффективного промпта:

SYSTEM_PROMPT = """
Ты — корпоративный ассистент. Отвечай только на основе предоставленного контекста.
Если информации недостаточно, честно скажи об этом.
Всегда указывай источники информации.
"""

def build_prompt(query: str, context_chunks: List[str]) -> str:
    context = "\n\n".join([
        f"Источник {i+1}: {chunk}" 
        for i, chunk in enumerate(context_chunks)
    ])
    
    return f"""
{SYSTEM_PROMPT}

Контекст:
{context}

Вопрос: {query}

Ответ:
"""

Техники улучшения промптов

  • Chain-of-thought: попросите модель рассуждать пошагово
  • Few-shot examples: добавьте примеры хороших ответов
  • Constraint prompting: явно укажите ограничения и формат ответа
  • Self-consistency: генерируйте несколько ответов и выбирайте лучший

Мониторинг и улучшение системы

Ключевые метрики

  • Recall@k: доля релевантных документов в топ-k результатах
  • Precision@k: доля релевантных среди возвращённых
  • MRR (Mean Reciprocal Rank): средний обратный ранг первого релевантного результата
  • NDCG: нормализованный дисконтированный кумулятивный выигрыш

Сбор обратной связи

Встройте механизмы оценки качества:

  • Thumbs up/down для ответов
  • Детальная оценка по критериям
  • Логирование пользовательского поведения
  • A/B тестирование разных подходов
# Пример логирования для анализа
import json
from datetime import datetime

def log_interaction(query: str, retrieved_docs: List, response: str, 
                   user_feedback: Optional[int] = None):
    log_entry = {
        "timestamp": datetime.utcnow().isoformat(),
        "query": query,
        "retrieved_count": len(retrieved_docs),
        "response_length": len(response),
        "user_feedback": user_feedback,
        "retrieval_scores": [doc.score for doc in retrieved_docs]
    }
    
    with open("rag_logs.jsonl", "a") as f:
        f.write(json.dumps(log_entry) + "\n")

Масштабирование и производительность

Оптимизация скорости

  • Кэширование: популярные запросы и эмбеддинги
  • Батчинг: группировка запросов для эмбеддингов
  • Асинхронность: параллельный поиск и генерация
  • Индексы: правильная настройка векторной БД

Управление затратами

  • Используйте более дешёвые модели для эмбеддингов
  • Кэшируйте результаты LLM
  • Оптимизируйте длину промптов
  • Рассмотрите self-hosted решения для высоких нагрузок

FAQ

В: Какой размер чанка оптимальный для корпоративных документов? О: Зависит от типа документов. For технической документации — 200-400 токенов, для аналитических отчётов — 500-800. Тестируйте на своих данных и измеряйте качество поиска.

В: Как обрабатывать обновления документов? О: Стройте инкрементальную индексацию: отслеживайте изменения через хеши или timestamps, удаляйте старые чанки и добавляйте новые. Для критичных обновлений — полная переиндексация.

В: Стоит ли дообучать embedding модель на корпоративных данных? О: Если у вас специфичная терминология и достаточно данных (10K+ документов) — да. Иначе начните с готовых моделей и оптимизируйте другие компоненты пайплайна.

В: Как обеспечить безопасность корпоративных данных в RAG? О: Используйте role-based фильтрацию в метаданных, изолированные векторные БД по департаментам, аудит доступа. Для особо чувствительных данных — on-premise развёртывание всего стека.

В: Какую LLM выбрать для генерации ответов? О: GPT-4 для максимального качества, GPT-3.5-turbo для баланса цена/качество, Llama 2 или Claude для on-premise. Тестируйте на ваших данных — качество сильно зависит от домена.

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

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

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

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