Любая компания рано или поздно сталкивается с одной и той же проблемой: знания разбросаны по сотням файлов, регламентов, вики-страниц и переписок, а найти нужный ответ быстро почти невозможно. Обычный ChatGPT тут не поможет - он не знает ваших внутренних документов и в лучшем случае честно скажет "не знаю", а в худшем - выдумает правдоподобный, но неверный ответ. Решение этой проблемы называется RAG (Retrieval-Augmented Generation) - подход, который позволяет нейросети отвечать, опираясь на реальные данные компании. В этой статье разберём, как устроен RAG и как собрать такую систему самостоятельно, шаг за шагом.
Что такое RAG и почему это не просто "чат с документами"
RAG - это архитектура, которая объединяет два процесса: поиск релевантной информации (Retrieval) и генерацию ответа на её основе (Generation). Вместо того чтобы обучать модель заново на ваших данных (что дорого и долго), вы даёте ей возможность "заглянуть" в базу знаний перед тем, как отвечать.
Схема работает так:
- Пользователь задаёт вопрос.
- Система ищет в базе документов фрагменты, наиболее релевантные вопросу.
- Найденные фрагменты вместе с вопросом передаются в языковую модель.
- Модель формирует ответ, опираясь именно на эти фрагменты, а не на общие знания из интернета.
Ключевое отличие от простого "чата с документами" в том, что RAG - это не разовый трюк, а полноценная инфраструктура: база знаний, поисковый механизм, логика ранжирования и слой генерации ответа. Именно поэтому такие системы масштабируются на тысячи и миллионы документов, а не ломаются после первых десяти файлов.
Почему бизнесу это выгодно:
- Не нужно дообучать модель - это дорого и требует постоянного обновления при изменении данных.
- Ответы можно проверить: система показывает, из какого документа взята информация.
- Данные остаются под контролем компании, а не "растворяются" в весах модели.
- Систему легко обновлять - просто добавляете новый документ в базу.
Из чего состоит RAG-система
Прежде чем переходить к практике, разберёмся с компонентами. Их всего пять, и каждый выполняет свою роль.
1. Источники данных. Это PDF, Word, Confluence, базы знаний, таблицы, письма поддержки - всё, что содержит полезную информацию.
2. Чанкер (chunker). Документы делятся на небольшие фрагменты - чанки. Модель не может "проглотить" весь документ целиком, поэтому текст режется на куски по 300-1000 токенов с небольшим перекрытием.
3. Модель эмбеддингов. Каждый чанк превращается в вектор - числовое представление смысла текста. Похожие по смыслу фрагменты оказываются близко друг к другу в векторном пространстве.
4. Векторная база данных. Хранилище для этих векторов с возможностью быстрого поиска похожих (Pinecone, Weaviate, Qdrant, Chroma, Milvus).
5. Языковая модель (LLM). Получает вопрос пользователя и найденные фрагменты, формирует связный ответ на человеческом языке.
Все эти части соединяются в единый пайплайн - именно его мы и будем собирать.
Шаг 1: подготовка документов
Начните с малого - соберите 20-50 документов, на которых будете тестировать систему. Это может быть база FAQ поддержки, регламенты, документация продукта.
Практические советы по подготовке:
- Уберите из документов "мусор": колонтитулы, повторяющиеся дисклеймеры, служебную разметку.
- Если документы в PDF со сканами - прогоните через OCR (Tesseract, Google Vision API).
- Структурируйте текст: заголовки, списки и таблицы помогают модели лучше понимать контекст при разбиении на чанки.
- Добавьте метаданные к каждому документу: дата, источник, отдел, версия. Это пригодится для фильтрации при поиске.
Шаг 2: разбиение на чанки
Разбиение текста на фрагменты - недооценённый, но критически важный этап. Слишком крупные чанки размывают релевантность поиска, слишком мелкие - теряют контекст.
Рекомендации по чанкованию:
- Начните с размера 500-800 токенов и перекрытия (overlap) в 10-15%.
- Используйте разбиение по смысловым границам - абзацам, разделам, а не просто "по количеству символов".
- Для таблиц и списков делайте отдельную логику - их разрывать особенно вредно.
- Сохраняйте в метаданные чанка ссылку на исходный документ и раздел - это нужно, чтобы потом показывать пользователю источник ответа.
Пример на Python с использованием LangChain:
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=700,
chunk_overlap=100,
separators=["\n\n", "\n", ". ", " "]
)
chunks = splitter.split_text(document_text)Шаг 3: создание эмбеддингов и загрузка в векторную базу
Теперь каждый чанк нужно превратить в вектор. Для этого используется модель эмбеддингов - например, text-embedding-3-small от OpenAI или открытые аналоги вроде e5 и bge, если данные не должны покидать инфраструктуру компании.
Пример кода для генерации эмбеддингов и загрузки в Chroma:
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_texts(
texts=chunks,
embedding=embeddings,
metadatas=metadata_list,
persist_directory="./db"
)
vectorstore.persist()На этом этапе важно решить, где хранить базу: в облаке (Pinecone, Weaviate Cloud) или локально (Chroma, Qdrant на своём сервере). Для чувствительных данных бизнеса второй вариант часто предпочтительнее.
Шаг 4: поиск и генерация ответа
Когда база готова, можно собирать логику ответа на вопрос. Процесс такой:
- Вопрос пользователя превращается в эмбеддинг той же моделью.
- Векторная база возвращает top-k наиболее похожих чанков (обычно 3-5).
- Чанки и вопрос собираются в промпт для LLM.
- Модель формирует ответ строго на основе переданного контекста.
Пример простого промпта для генерации:
Ты - ассистент службы поддержки компании.
Отвечай на вопрос пользователя, используя ТОЛЬКО информацию из контекста ниже.
Если ответа в контексте нет, скажи, что не нашёл информации, не придумывай.
Контекст:
{retrieved_chunks}
Вопрос: {user_question}
Ответ:Пример реализации на LangChain:
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever,
return_source_documents=True
)
result = qa_chain({"query": "Как оформить возврат товара?"})
print(result["result"])
print(result["source_documents"])Важная деталь: temperature=0 снижает "творческую самодеятельность" модели - для деловых ответов это критично.
Шаг 5: улучшение качества ответов
Базовый пайплайн заработает уже после четырёх шагов, но качество ответов на первых порах редко бывает идеальным. Вот что реально помогает его поднять:
- Гибридный поиск. Комбинируйте векторный поиск с классическим keyword-поиском (BM25). Это спасает, когда вопрос содержит редкие термины или коды продуктов, которые плохо ловятся эмбеддингами.
- Re-ranking. После первичного поиска пропустите топ-20 кандидатов через более точную модель ранжирования (например, Cohere Rerank), чтобы оставить самые релевантные 3-5 чанков.
- Проверка на галлюцинации. Добавьте отдельный шаг, где модель или скрипт проверяет, действительно ли ответ подтверждается контекстом.
- Фильтрация по метаданным. Если у вас несколько отделов или продуктов, дайте пользователю возможность сузить поиск (например, только по документам HR или только по актуальной версии продукта).
- Логирование и обратная связь. Собирайте оценки пользователей ("ответ помог / не помог") - это лучший источник данных для дальнейшей donастройки системы.
Практика: собираем мини-RAG для поддержки клиентов
Разберём сквозной пример на конкретной задаче - бот для ответов по базе знаний службы поддержки интернет-магазина.
Шаг 1. Собираем 40 статей из внутренней вики: доставка, возврат, оплата, гарантия. Экспортируем в текстовый формат.
Шаг 2. Прогоняем через чанкер с размером 600 токенов и перекрытием 80.
Шаг 3. Генерируем эмбеддинги моделью text-embedding-3-small, загружаем в Qdrant локально - данные о заказах не должны уходить во внешние сервисы без необходимости.
Шаг 4. Настраиваем retriever с k=4 и добавляем re-ranking через Cohere, чтобы отсекать нерелевантные совпадения (например, статьи про доставку в другой стране).
Шаг 5. Собираем промпт с инструкцией отвечать только по контексту и обязательно указывать номер статьи-источника в конце ответа.
Шаг 6. Тестируем на 30 реальных вопросах из истории обращений в поддержку, фиксируем, на каких вопросах система ошибается или не находит ответ.
Шаг 7. По результатам тестов дополняем базу знаний недостающими статьями и донастраиваем размер чанков там, где терялся контекст.
Такой цикл "тест - правка - повторный тест" обычно занимает одну-две недели и выводит систему на приемлемое для продакшена качество.
Частые ошибки при внедрении RAG
- Слишком большая база сразу. Начинать нужно с малого набора документов и постепенно расширять, иначе сложно отследить, где именно теряется качество.
- Игнорирование метаданных. Без ссылки на источник пользователи не доверяют ответам и не могут проверить их достоверность.
- Один универсальный чанк-размер для всех типов документов. Таблицы, код и обычный текст требуют разной логики разбиения.
- Отсутствие мониторинга. Без логов и оценок сложно понять, деградирует ли качество ответов со временем при росте базы.
- Ставка только на генерацию без проверки. Даже с RAG модель может галлюцинировать, если контекст неполный или противоречивый - нужен слой контроля.
Вывод
RAG-система - это не разовая интеграция чат-бота, а полноценная инфраструктура, которая позволяет нейросети отвечать на основе реальных знаний компании, а не догадок. Ключевые шаги - подготовка документов, грамотное чанкование, качественные эмбеддинги, продуманный поиск и контроль над генерацией ответа. Начните с небольшого пилота на 20-50 документах, пройдите цикл тестирования и постепенно масштабируйте систему на всю базу знаний компании. Именно такой поэтапный подход даёт устойчивый результат - в отличие от попытки сразу построить "идеальный" ответ на все вопросы бизнеса.
Читайте также: Контекст-инжиниринг: почему дело не в промпте, а в папке, Что такое Claude Code и Codex, что такое ИИ-агент.
