RAG: как подключить свои документы к языковой модели

Как работает Retrieval-Augmented Generation: векторные базы, эмбеддинги, чанкинг. Практическое руководство по RAG-системам для работы с внутренними документами.

RAG: как подключить свои документы к языковой модели

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

Проблема, которую решает RAG

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

Файн-тюнинг — обучение модели на своих данных — частично решает первую проблему, но дорог, требует экспертизы и не устраняет галлюцинации. Каждое обновление данных требует повторного обучения.

RAG предлагает другой подход: вместо того чтобы учить модель всему, мы подаём нужную информацию прямо в контекст запроса. Модель получает вопрос вместе с релевантными фрагментами документов и формирует ответ на основе фактов, а не «памяти».

Архитектура RAG-системы

RAG-пайплайн состоит из четырёх ключевых компонентов, каждый из которых влияет на качество итогового ответа.

1. Загрузка и чанкинг документов

Документы нужно разбить на фрагменты (chunks) — куски текста по 200–1000 токенов. Слишком маленькие чанки теряют контекст. Слишком большие — снижают точность поиска и занимают место в контекстном окне модели.

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

  • По фиксированному размеру — простейший подход: текст нарезается на фрагменты по N символов с перекрытием (overlap) в 10–20%. Перекрытие нужно, чтобы не разрывать предложения на границе чанков.
  • По структуре документа — разбиение по заголовкам, параграфам, разделам. Сохраняет семантическую целостность, но работает только со структурированными документами.
  • Рекурсивный — сначала пытается разбить по параграфам, затем по предложениям, затем по символам. Используется в LangChain по умолчанию.

2. Эмбеддинги

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

Модели эмбеддингов, которые стоит рассмотреть:

  • OpenAI text-embedding-3-small — 1536 измерений, хороший баланс качества и стоимости
  • Cohere embed-v3 — мультиязычная модель, хорошо работает с русским
  • BGE-M3 — open-source, мультиязычная, можно запускать локально
  • E5-mistral-7b-instruct — на базе Mistral, высокое качество для длинных текстов

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

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

Эмбеддинги хранятся в специализированных базах данных, оптимизированных для поиска ближайших соседей (nearest neighbor search).

  • Chroma — встраиваемая база, работает как библиотека Python. Идеальна для прототипов и небольших проектов (до 100 000 документов).
  • Pinecone — облачный сервис, управляемая инфраструктура. Масштабируется до миллиардов векторов.
  • Weaviate — open-source, поддерживает гибридный поиск (векторный + полнотекстовый).
  • pgvector — расширение PostgreSQL. Позволяет хранить векторы рядом с обычными данными без отдельной инфраструктуры.
  • Qdrant — open-source, написан на Rust, быстрый и эффективный по памяти.

4. Генерация ответа

При запросе пользователя система:

  1. Превращает вопрос в эмбеддинг той же моделью
  2. Ищет N ближайших чанков в векторной базе (обычно 3–10)
  3. Формирует промпт: системная инструкция + найденные фрагменты + вопрос
  4. Отправляет промпт в LLM и возвращает ответ

Пример: RAG на Python за 30 строк

from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA

# 1. Загрузка документов
loader = DirectoryLoader('./docs/', glob='**/*.md')
documents = loader.load()

# 2. Чанкинг
splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50
)
chunks = splitter.split_documents(documents)

# 3. Создание векторной базы
db = Chroma.from_documents(
    chunks,
    OpenAIEmbeddings(model='text-embedding-3-small')
)

# 4. Цепочка вопрос-ответ
qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model='gpt-4o-mini'),
    retriever=db.as_retriever(search_kwargs={'k': 5})
)

result = qa.invoke('Какие сроки у текущего проекта?')
print(result['result'])

Этот код загружает Markdown-файлы из папки, разбивает на чанки, индексирует в Chroma и позволяет задавать вопросы по содержимому.

Типичные ошибки и как их избежать

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

Неподходящая модель эмбеддингов — англоязычная модель эмбеддингов на русских документах будет работать, но хуже мультиязычной. Разница в качестве поиска — 15–30% по метрикам recall.

Слишком много контекста — если подавать 20 чанков по 1000 токенов, модель может «утонуть» в информации. Исследование Стэнфорда Lost in the Middle показало: модели хуже обрабатывают информацию в середине длинного контекста. Оптимально — 3–7 релевантных чанков.

Отсутствие перерейтинга — векторный поиск не идеален. Добавление этапа re-ranking (переоценки релевантности найденных чанков с помощью cross-encoder модели) повышает качество на 10–25%.

Продвинутые техники

Гибридный поиск — комбинация векторного (семантического) и полнотекстового (BM25) поиска. Семантический поиск находит тексты, близкие по смыслу. BM25 — тексты с точными совпадениями ключевых слов. Вместе они покрывают оба случая.

Hypothetical Document Embeddings (HyDE) — вместо поиска по вопросу пользователя LLM сначала генерирует гипотетический ответ, и поиск идёт по этому ответу. Повышает качество для абстрактных вопросов.

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

RAG против файн-тюнинга

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

Архитектуры RAG: сравнение подходов

Тип RAGОписаниеКогда применятьСложность
Naive RAGChunk → Embed → Retrieve → GenerateПрототип, небольшие базы знанийНизкая
Advanced RAGQuery rewriting + HyDE + rerankingProduction с умеренными требованиямиСредняя
Modular RAGНезависимые модули: поиск, фильтрация, генерацияСложные enterprise-системыВысокая
Graph RAGГраф знаний + векторный поискДокументы со сложными связямиОчень высокая
Agentic RAGАгент решает, когда и как делать поискМногоступенчатые вопросыВысокая

Минимальный рабочий RAG (Python)

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA

# 1. Загрузка документа
loader = PyPDFLoader('document.pdf')
docs = loader.load()

# 2. Разбивка на чанки
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)

# 3. Создание векторного индекса
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(chunks, embeddings)

# 4. Запрос
qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model='gpt-4o-mini'),
    retriever=vectorstore.as_retriever(search_kwargs={'k': 4})
)
print(qa.invoke('Ваш вопрос'))

Ключевые параметры качества RAG

  • Chunk size: 500–1000 токенов для большинства задач; маленькие чанки = высокая точность, большие = больший контекст
  • Chunk overlap: 10–20% от chunk size для сохранения связности
  • k (число извлекаемых чанков): 3–5 для оптимального баланса релевантности и токенов
  • Embedding модель: text-embedding-3-large (OpenAI) > E5-large-v2 > nomic-embed-text (open source)
  • Reranking: добавление cross-encoder reranker (например, BGE-reranker-large) улучшает точность на 15–25%

Оценка качества RAG: метрики

  • Faithfulness: насколько ответ основан на извлечённых документах (RAGAS-метрика)
  • Answer Relevancy: насколько ответ соответствует вопросу
  • Context Recall: все ли нужные документы были найдены
  • Инструменты оценки: RAGAS (pip install ragas), TruLens, DeepEval

RAGAS позволяет автоматически оценивать RAG-систему без ручной разметки — использует LLM как судью.


Читайте также

Подробнее: Полный гайд по LLM для разработчиков