Если вы выкатили простую RAG-систему, вы знаете паттерн: нарезать документы на чанки, получить их эмбеддинги, положить в векторную БД, по запросу достать top-k, вставить в промпт. Для демо работает. В продакшене часто разочаровывает.
Разрыв между демо-RAG и продакшен-RAG огромен. Реальные документы грязные. Реальные запросы неоднозначные. Качество дико варьируется по типам запросов. Стоимость и задержка — реальные ограничения. Обновления и версионирование имеют значение.
Эта статья — о том, как выглядит RAG-конвейер промышленного уровня: шесть стадий, паттерны на каждой и дисциплина оценки, которая отличает работающие системы от разочаровывающих.
Конвейер
У продакшен-RAG-системы шесть логических стадий:
[Documents]
↓
1. Ingestion (парсинг, очистка, извлечение метаданных)
↓
2. Chunking (разбиение на единицы извлечения)
↓
3. Embedding (векторы + хранение)
↓
[Query]
↓
4. Retrieval (семантика + лексика + фильтры)
↓
5. Reranking (top-k → top-N)
↓
6. Generation (LLM + контекст)
↓
[Response]
У каждой стадии — свои проблемы качества. Улучшение любой одной улучшает всю систему.
Пройдём по каждой.
Стадия 1: приём данных (ingestion)
Мусор на входе — мусор на выходе. Качество приёма данных определяет потолок всего, что идёт ниже.
Типы источников, с которыми вы столкнётесь:
- PDF (в основном худший вариант).
- Word-документы.
- HTML-страницы.
- Markdown.
- Таблицы.
- Слайды (PowerPoint, Google Slides).
- Письма.
- Код.
- Структурированные данные (CSV, JSON).
У каждого свои сложности парсинга.
Парсинг PDF. PDF — формат презентации, а не данных. Они печально известны сложностью парсинга. Стратегии:
- Текстовые PDF:
pdfplumber,pymupdf,unstructured. Работают для чистого текста. - Сканированные PDF: OCR с Tesseract, Google Cloud Vision или AWS Textract.
- С учётом макета:
LayoutLM, Mathpix или парсинг через LLM (GPT-4 vision) для сложных макетов (таблицы, несколько колонок).
Современный подход для сложных PDF: использовать LLM с поддержкой зрения для OCR и структурирования контента. Стоит дороже, но качество драматически лучше традиционного OCR.
Обработка таблиц. Таблицы в неструктурированном тексте — боль. Варианты:
- Конвертировать в markdown-таблицы (сохраняет структуру).
- Линеаризовать в прозу («Row 1: customer A had 50 orders…»).
- Считать отдельными извлекаемыми единицами со структурированной схемой.
Правильный выбор зависит от того, какие запросы вы будете получать.
Извлечение метаданных. У каждого документа есть метаданные, которые важны:
- Заголовок, автор, дата, версия.
- Тема, категория, теги.
- URL источника или его местоположение.
- Права / видимость.
Захватывайте это на этапе приёма данных. Это станет параметрами фильтрации при извлечении.
Очистка. Срезайте шаблонный мусор:
- Колонтитулы, повторяющиеся на каждой странице.
- Навигация, реклама, баннеры о cookie.
- Страницы оглавления.
- Пустые или дублированные параграфы.
По чистому корпусу поиск работает лучше. Шаблонный мусор приводит к ложным срабатываниям.
Проверки качества.
- Извлёк ли парсер реально текст? (Некоторые PDF возвращают пустые строки.)
- Есть ли проблемы с кодировкой?
- Сохранены ли таблицы?
- Подписаны ли картинки или пропущены?
Встройте базовые проверки в конвейер приёма данных. Ловите битые результаты парсинга до того, как они загрязнят индекс.
Стадия 2: нарезка на чанки (chunking)
У вас есть чистые документы. Теперь делите их на единицы извлечения (чанки).
Фундаментальный компромисс:
- Мелкие чанки: точное извлечение (сфокусированное на вопросе), но без контекста.
- Крупные чанки: больше контекста, но менее точно (нужная часть закопана).
Обе крайности теряют качество. Золотая середина варьируется по типу контента.
Распространённые стратегии:
Фиксированный размер с перекрытием. Резать на чанки по N токенов (300–800 токенов) с перекрытием 50–100 токенов. Просто, работает как базовый вариант.
С учётом границ предложений. Резать по границам предложений (используя nltk, spaCy или аналог). Избегает разрывов в середине предложения.
По параграфам. Каждый параграф — чанк. Работает для документов с хорошо структурированными параграфами.
Иерархический (мелкий + крупный). Два индекса:
- Мелкие чанки (300 токенов) для точного извлечения.
- Крупные чанки (1500 токенов) или целые секции для контекста. При извлечении достаём мелкие; в LLM подаём родительский крупный.
Учёт структуры документа. Используйте структуру документа (заголовки, секции) для формирования чанков. Каждая секция — чанк, иерархия сохраняется.
Семантическая нарезка. Используйте эмбеддинги, чтобы найти естественные точки разрыва (где меняется тема). Дороже, но даёт лучшие чанки для некоторого контента.
Нарезка через суммаризацию LLM. Длинные документы суммируются в иерархические чанки на нескольких уровнях (резюме параграфа, резюме секции, резюме документа). LLM генерирует это один раз на этапе приёма данных.
Правильная стратегия зависит от контента. Статьи и вики: параграфы или иерархия. Код: уровень функций. Разговоры: по репликам. Технические доки: учёт структуры.
Метаданные чанков. Каждый чанк должен нести:
- ID и URL исходного документа.
- Путь секции (chapter > section > subsection).
- Номер страницы (для цитирования).
- Заголовки выше этого чанка (для контекста).
- Метаданные уровня документа (дата, автор, тип).
Эти метаданные позволяют фильтровать и цитировать в финальном ответе.
Стадия 3: эмбеддинг
Превращаем чанки в векторы.
Выбор модели эмбеддинга.
В 2026:
- OpenAI text-embedding-3-large: сильный универсал, дорогой.
- Voyage Voyage-3: конкурентоспособен, часто лучше на техническом контенте.
- Cohere embed-v4: сильный мультиязычный.
- BAAI bge-large: сильный, с открытым исходным кодом.
- Nomic embed-text: хороший, с открытым кодом, бесплатный при размещении у себя.
- Доменно-специализированные модели: для кода (Voyage Code, OpenAI text-embedding-3-large тоже работает для кода), юридический, медицинский и т. д.
Выбор модели: тестируйте на своём домене. Не считайте, что лидер таблицы рейтингов — лучший для ваших данных.
Размерность эмбеддинга. Модели предлагают 256–3072 измерений. Выше размерность = выше качество, выше стоимость/хранение. Для большинства случаев оптимум — 768–1536.
Версионирование. Модели эмбеддинга обновляются; вы можете захотеть переключиться. Планируйте это:
- Отслеживайте, какая версия модели произвела каждый вектор.
- Заново эмбеддите всё при миграции (или используйте переход через двойной индекс).
- Не смешивайте векторы разных моделей в одном поиске.
Стоимость. Эмбеддинг миллионов чанков стоит денег. €0.10–€0.50 за миллион токенов (зависит от провайдера). Для больших корпусов считайте заранее.
Хранение. Векторы большие. 1M чанков × 1536 измерений × 4 байта = 6GB. Планируйте хранилище соответственно.
Стадия 4: извлечение (retrieval)
Приходит запрос. Нужно найти релевантные чанки.
Векторный поиск (плотное извлечение). Эмбеддим запрос, ищем ближайших соседей. Ловит семантическое сходство. Стандарт.
Поиск по ключевым словам (BM25 / лексический). Традиционный текстовый поиск. Ловит точные совпадения, редкие термины, конкретные имена. Часто дополняет векторный.
Гибридный поиск. Запускаем оба, сливаем результаты. Reciprocal Rank Fusion (RRF) — стандартный подход к слиянию.
def reciprocal_rank_fusion(rankings, k=60):
scores = {}
for ranking in rankings:
for rank, doc_id in enumerate(ranking):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)
return sorted(scores.items(), key=lambda x: -x[1])
На практике гибрид обыгрывает чисто векторный или чисто по ключевым словам на большинстве бенчмарков. Используйте по умолчанию.
Фильтрация по метаданным. Фильтруйте извлечение по метаданным до скоринга. «Только документы с 2025+». «Только документы из доступного пользователю набора». «Только документы типа policy».
Критично для мультиарендных систем: каждый запрос ограничен документами, доступными арендатору.
Понимание запроса. Предобработка запроса:
- Коррекция опечаток. «engineerin» → «engineering».
- Раскрытие аббревиатур. «MFA» → «Multi-Factor Authentication MFA».
- Синонимы / расширение запроса. Генерируем альтернативные формулировки; ищем по каждой.
- Декомпозиция. Многосоставные вопросы разбиваются на подзапросы, каждый извлекается отдельно.
Эти шаги предобработки значительно улучшают извлечение на реальных запросах.
HyDE (Hypothetical Document Embeddings). Сгенерировать с помощью LLM фиктивный «идеальный ответ». Получить его эмбеддинг. Использовать результат как запрос для извлечения. Часто работает лучше, чем эмбеддинг вопроса напрямую, потому что фиктивный ответ ближе к реальным документам-ответам.
def hyde_retrieve(query, k=20):
hypothetical = llm("Write a passage answering: " + query)
embedding = embed(hypothetical)
return vector_search(embedding, k=k)
Компромисс: дополнительный вызов LLM на запрос (задержка, стоимость). Стоит того для сложных запросов; перебор для простых.
Мультивекторное извлечение. Вместо одного вектора на чанк — несколько (например, один для чанка, один для резюме, один для гипотетических вопросов). Добавляет хранение и сложность, но улучшает извлечение для некоторого контента.
Стадия 5: переранжирование (reranking)
После начального извлечения (top-k, k=20–50) используйте переранжировщик, чтобы более аккуратно оценить кандидатов.
Зачем переранжировать?
Начальное извлечение быстрое, но неточное. Векторная близость — грубая аппроксимация релевантности. Переранжировщик (обычно модель-кросс-энкодер) читает запрос и каждого кандидата вместе, выдавая более точную оценку.
Варианты переранжировщиков:
- Cohere Rerank. Индустриальный стандарт. Хорошее качество, хостируемое.
- Voyage Rerank. Сильный конкурент.
- BGE Rerank-large. Открытый код, бесплатный при размещении у себя.
- Кросс-энкодеры MiniLM. Меньше, быстрее, ниже качество.
- Переранжирование на базе LLM. Используем маленькую LLM для оценки пар «запрос-кандидат». Самое высокое качество, самая высокая стоимость.
Эффект.
Добавление переранжирования, как правило, улучшает качество конечной задачи в большинстве RAG-систем; часто цитируемый диапазон 10–20% воспринимайте как плановую оценку, которую нужно проверить на собственных оценках. Почти всегда стоит того по задержке и стоимости.
Типичная конфигурация:
- Достать 30–50 кандидатов гибридным поиском.
- Переранжировать до top 5–10.
- Передать топ-результаты в LLM.
Адаптивное переранжирование.
Для запросов, где топ-1 результат имеет высокое векторное сходство (явное совпадение), переранжирование пропускайте. Для запросов с близкими оценками (несколько кандидатов вровень) — переранжируйте агрессивно.
Стадия 6: генерация
LLM производит ответ, используя извлечённый контекст.
Структура промпта:
Вы — ассистент, отвечающий на вопросы на основе предоставленного контекста.
Context:
[Document 1 - title, URL]
[chunk 1 content]
[Document 2 - title, URL]
[chunk 2 content]
...
User question: {query}
Instructions:
- Отвечайте только на основе предоставленного контекста.
- Если в контексте нет ответа, так и скажите. Не выдумывайте информацию.
- Цитируйте источники в нотации [Source N].
- Будьте лаконичны, но полны.
Паттерны промпта, которые имеют значение:
- Маркировка источников. Каждый чанк контекста маркируется источником для цитирования.
- Инструкции по опоре на контекст. Явно говорим модели использовать только контекст.
- Требование цитирования. Принуждаем к цитированию. Ловит галлюцинации.
- Запасная инструкция. «If the context doesn’t have the answer, say so.» Предотвращает домысливание.
Обработка цитирования.
Распространённый паттерн: включить ссылки на источники в ответ. Интерфейс отображает их как кликабельные ссылки.
«Политика удалённой работы компании допускает до 4 дней в неделю из дома [1].
[1]: https://wiki.company.com/policies/remote-work»
Это делает ответ проверяемым. Пользователи больше доверяют ответам, опирающимся на источники.
Управление размером контекста.
Длинные контексты деградируют. Большинство моделей лучше работают со сфокусированными контекстами (5–10 высокорелевантных чанков), а не со свалкой всего. Качество падает по мере разбухания контекста.
Если приходится включать много контекста, суммируйте менее релевантные элементы, а не включайте их целиком.
Оценка на каждой стадии
Нельзя оптимизировать то, что не измеряешь. Каждой стадии нужны свои оценки.
Оценка приёма данных. Корректно ли распарсились документы? Возьмите выборку документов; проверьте, что ключевой контент сохранён.
Оценка нарезки. Правильного ли размера чанки? Сохраняют ли контекст? Рвутся ли по разумным границам?
Оценка эмбеддинга. Похоже ли эмбеддятся похожие концепции? На тестовом наборе заведомо похожих и заведомо разных пар — соответствует ли косинусная близость ожиданиям?
Оценка извлечения. Для данного запроса — есть ли релевантные чанки в top-K? Типичная метрика: recall@K (какой % запросов имеет хотя бы один релевантный чанк в top K).
Оценка переранжирования. Среди извлечённых кандидатов — ставит ли переранжировщик самый релевантный первым? Метрика: NDCG (normalized discounted cumulative gain) или MRR (mean reciprocal rank).
Оценка генерации. При данном контексте и запросе — выдаёт ли LLM корректный ответ? Метрики: верность контексту (faithfulness — использует ли ответ контекст?), корректность (correctness — верен ли ответ?), полезность (helpfulness — отвечает ли он на намерение пользователя?).
Сквозная оценка (end-to-end). При реальном запросе — выдаёт ли система правильный ответ? Самое важное; зависит от всех стадий.
Вам нужны тестовые наборы для каждой стадии. Типичный стартовый набор:
- Собрать 50–100 запросов с известно-хорошими ответами.
- Для каждого запроса определить, какой документ(ы) содержит ответ.
- Использовать это для оценки извлечения (достали ли мы нужные документы?) и генерации (верен ли ответ?).
Инструменты: Ragas, TruLens, свои наборы. Конкретный инструмент менее важен, чем сам факт запуска оценок.
Операционные вопросы
Несколько продакшен-реалий:
Конвейеры индексации. Приходят новые документы. Переэмбеддить. Обновить индексы. Обработать удаления и обновления. Этот конвейер работает постоянно, не только на настройке. Стройте его как систему, а не как одноразовый скрипт.
Задержка.
Типичная разбивка:
- Эмбеддинг (запрос): 50–200 мс.
- Векторный поиск: 50–200 мс.
- Переранжирование: 200–500 мс (зависит от K).
- Генерация: 1–5 с (зависит от контекста и модели).
- Итого: 1.5–6 с.
Оптимизация:
- Кэшировать эмбеддинги частых запросов.
- Кэшировать переранжирование для повторяющихся пар «запрос-кандидат».
- Передавать генерацию потоком.
- Распараллеливать, где возможно.
Для задержки < 2 с обычно нужны быстрая модель эмбеддинга, быстрая векторная БД и либо быстрый переранжировщик, либо пропуск переранжирования для закэшированных/простых запросов.
Стоимость.
Стоимость на запрос:
- Эмбеддинг: ~€0.0001.
- Векторный поиск: ~€0.0001 (зависит от инфраструктуры).
- Переранжирование: €0.001–0.01 (зависит от модели).
- Генерация: €0.005–0.05 (зависит от модели и контекста).
- Итого: ~€0.01–0.05 на запрос.
На масштабе это складывается. Миллион запросов = €10K–50K.
Оптимизация стоимости:
- Кэшировать.
- Использовать более дешёвые модели там, где качество позволяет.
- Сжимать контекст (резюме вместо полных чанков).
Обновления. Документы меняются. Паттерны:
- Версионирование: у каждого документа есть версия; старые версии хранятся или удаляются по политике.
- Инкрементально: новые версии заново нарезаются и заново эмбеддятся; старые чанки удаляются.
- С учётом различий: переобрабатываются только изменённые секции.
Для сценариев с большим объёмом обновлений это существенно.
Права. RAG над приватными данными: у документов есть средства контроля доступа; извлечение должно их уважать.
- Фильтрация по метаданным (у каждого чанка есть метаданные о том, кому он доступен).
- Индексы, изолированные по арендаторам, для жёсткой изоляции.
- Журналирование доступа: кто к чему обращался.
Не доверяйте LLM обеспечивать соблюдение прав. Обеспечивайте его на этапе извлечения.
Типичные режимы провала
Несколько паттернов, которые мы видим в провальных RAG-системах:
Провал 1: плохая нарезка. Чанки рвутся посреди мысли, таблица разбита между чанками, заголовки отделены от своего содержания. Исправление: лучшая стратегия нарезки.
Провал 2: извлечение промахивается мимо ответа. Релевантный чанк существует, но не находится. Часто — несоответствие запроса и документа. Исправление: HyDE, расширение запроса, лучшие эмбеддинги.
Провал 3: правильные чанки, неверный порядок. Релевантный чанк извлечён, но ранжирован низко. LLM использует более высокоранжированные нерелевантные чанки. Исправление: переранжирование.
Провал 4: правильные чанки, галлюцинация. Чанки правильные, но LLM придумывает дополнительную информацию. Исправление: более строгий промпт с опорой на источники, требования цитирования, более низкая температура.
Провал 5: правильные чанки, неверный ответ. Чанки содержат ответ, но LLM извлекает неверную часть. Исправление: лучший промпт генерации, возможно — модель побольше.
Провал 6: устаревшие данные. Индекс не обновлялся. Исправление: непрерывный конвейер приёма данных.
Провал 7: утечки прав. Пользователи видят чанки, которые им не положены. Исправление: применять фильтрацию на этапе извлечения; аудит.
Провал 8: неконтролируемый рост затрат. Задержка и стоимость выросли с ростом корпуса и трафика. Исправление: кэширование, маршрутизация моделей, возможно — архитектурные изменения.
Разобранный пример: RAG для корпоративной базы знаний
Чтобы было конкретно: типичная RAG-система над корпоративной базой знаний.
Корпус: ~50 000 документов (страницы вики, политики, руководства по эксплуатации, заметки встреч, треды в Slack).
Конвейер:
-
Приём данных:
- Notion: экспорт через API.
- Slack: экспорт архива, отфильтрованный до релевантных каналов.
- Google Drive: API-экспорт согласованных папок.
- Очистка: убрать сообщения только из эмодзи, шаблонные подписи.
-
Нарезка:
- Иерархическая: мелкие чанки уровня параграфа, родительские чанки уровня секции.
- ~250K общих чанков на мелком уровне.
- Метаданные: источник, путь секции, last_updated, accessible_to.
-
Эмбеддинг:
- Эмбеддинги Voyage-3, 1024 измерения.
- Хранение в Pinecone (управляемый сервис).
- Еженедельный повторный эмбеддинг для изменённых документов.
-
Извлечение:
- Гибридное: векторный поиск + BM25 (через гибрид Pinecone).
- HyDE для запроса.
- Фильтр по метаданным для доступности.
- Извлекается top 30.
-
Переранжирование:
- Cohere Rerank.
- Top 30 → top 8.
-
Генерация:
- Claude Sonnet 5.
- Top 8 родительских чанков (не мелких) подаются как контекст.
- Цитирование требуется в ответе.
Оценка:
- 100 вручную составленных пар «запрос/ответ».
- recall@30 для извлечения: ~92%.
- Корректность финального ответа: ~85%.
- Верность контексту (faithfulness, без галлюцинаций): ~95%.
Операции:
- Ежедневный инкрементальный приём данных.
- Еженедельный полный повторный эмбеддинг для изменённых документов.
- Наблюдаемость по каждому запросу.
- Ежемесячный повторный прогон оценок; мониторинг трендов.
- Ежеквартальный обзор журнала запросов для поиска новых паттернов провалов.
Стоимость:
- Эмбеддинг: ~€500/месяц (в установившемся режиме).
- Хостинг векторной БД: ~€800/месяц (Pinecone).
- Извлечение + генерация на запрос: ~€0.02.
- Итого: ~€2 500/месяц + €0.02 × объём запросов.
Для большинства компаний это полностью оправдано приростом продуктивности.
План 90-дневной сборки RAG
Если стартуете с нуля:
Дни 1–30: MVP.
- Определить корпус и основной сценарий использования.
- Базовый приём данных (один источник).
- Базовая нарезка (фиксированный размер с перекрытием).
- Стандартная модель эмбеддинга.
- Только векторный поиск (без переранжирования).
- Простой промпт генерации.
Дни 31–60: качество.
- Вручную собрать набор для оценки (50–100 запросов).
- Определить режимы провалов.
- Добавить переранжирование.
- Добавить гибридный поиск.
- Улучшить нарезку.
Дни 61–90: операции.
- Непрерывный конвейер приёма данных.
- Наблюдаемость.
- Автоматизация оценки.
- Права / аутентификация.
- Мониторинг стоимости.
Через 90 дней у вас система, которую можно не просто демонстрировать, а реально использовать. Реальные пользователи могут на неё опереться.
Качество живёт на каждой стадии
Продакшен-RAG — это шестистадийный конвейер с вопросами качества на каждой стадии. Паттерны, которые отличают работающие системы от разочаровывающих:
- Приём данных: тщательный парсинг, сохранение структуры, захват метаданных.
- Нарезка: подходящая стратегия для типа контента, часто иерархическая.
- Эмбеддинг: качественная модель, версионирование, план миграции.
- Извлечение: гибрид по умолчанию, понимание запроса, фильтрация по метаданным.
- Переранжирование: почти всегда того стоит.
- Генерация: опора на источники, цитирование, запасной ответ для неизвестного.
- Оценка: на каждой стадии, постоянно.
Ничто из этого не опционально. Разница между RAG, который попадает в 60% качества ответа, и RAG, который попадает в 90%, живёт именно в этих деталях.
Вложения реальные — продакшен-сборка RAG занимает месяцы, а не недели. Награда — система, которой ваши пользователи могут реально доверять. Это и есть значимый порог.



