RAG: как подключить свои документы к языковой модели
Как работает Retrieval-Augmented Generation: векторные базы, эмбеддинги, чанкинг. Практическое руководство по 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. Генерация ответа
При запросе пользователя система:
- Превращает вопрос в эмбеддинг той же моделью
- Ищет N ближайших чанков в векторной базе (обычно 3–10)
- Формирует промпт: системная инструкция + найденные фрагменты + вопрос
- Отправляет промпт в 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 RAG | Chunk → Embed → Retrieve → Generate | Прототип, небольшие базы знаний | Низкая |
| Advanced RAG | Query rewriting + HyDE + reranking | Production с умеренными требованиями | Средняя |
| 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 как судью.
Читайте также
- Векторные базы данных: поиск по смыслу
- LangChain vs LlamaIndex: фреймворки для RAG
- Как встроить ИИ-поиск с эмбеддингами
Подробнее: Полный гайд по LLM для разработчиков