← The Practical AI Product Engineering Playbook
03 / 10 · 90 min

RAG and vector search: answering from your own documents

When retrieval beats fine-tuning, how to chunk documents, why hybrid search and reranking matter, and why citations matter more than a pretty answer.

Lesson content is currently available in Russian.

What you will learn

  • →Обоснованно выбирать между RAG, fine-tuning и длинным контекстом.
  • →Строить retrieval pipeline: chunking, гибридный поиск, reranking, context packing.
  • →Измерять качество retrieval отдельно от качества генерации и показывать источники.

Когда RAG нужен, а когда мешает

RAG (retrieval-augmented generation) решает одну задачу: дать модели релевантные факты в момент запроса, вместо того чтобы надеяться на её веса. Сравним три подхода честно:

  • RAG выигрывает, когда данные меняются (документация, база знаний, тикеты), когда нужны цитаты и проверяемость, и когда у разных пользователей разные права доступа — фильтровать можно на этапе поиска. Обновление знаний = обновление индекса, минуты, а не недели.
  • Fine-tuning учит форму, а не факты: стиль, формат, следование специфичному протоколу. Заучивать fine-tuning-ом свежие факты — дорого, медленно и без возможности процитировать источник. Классическая ошибка — тюнить модель на базе знаний и удивляться галлюцинациям.
  • Длинный контекст («просто положим все документы в промпт») работает до определённого объёма, но платите вы за каждый токен в каждом запросе, а качество использования середины длинного контекста заметно проседает. Для корпуса из тысяч документов это не вариант ни по деньгам, ни по качеству.

Когда RAG мешает: если знания стабильны и умещаются в компактный системный промпт (правила сервиса на две страницы) — retrieval добавит латентность, инфраструктуру и новые точки отказа без выигрыша. RAG — это поисковая система плюс генерация, и обе части нужно строить и мерить. Не начинайте с векторной базы; начинайте с вопроса «какие запросы и по каким документам мы должны отвечать и как проверим, что отвечаем правильно».

Chunking и метаданные

Документы режутся на чанки, потому что искать и класть в контекст нужно фрагменты, а не тома. Гранулярность — главный рычаг качества: слишком крупные чанки (2000+ токенов) размывают вектор — в один embedding попадает несколько тем, и поиск теряет точность; слишком мелкие (меньше ~100 токенов) теряют контекст — найденное предложение без окружения бесполезно и модели, и человеку.

Рабочие ориентиры, от которых можно отталкиваться:

  • Размер чанка 200–800 токенов, overlap 10–20%, чтобы мысль, разрезанная границей, целиком попала хотя бы в один чанк.
  • Structure-aware splitting: резать по заголовкам, спискам и абзацам, а не по числу символов. Таблицу не резать никогда — она теряет смысл; таблицы и код лучше индексировать отдельными чанками с текстовым описанием.
  • К каждому чанку — заголовок его раздела и документа («Тарифы > Возвраты > Сроки»): это дёшево и заметно улучшает и поиск, и понимание модели.

Метаданные — вторая половина chunking, которую чаще всего забывают: id и версия документа, дата обновления, раздел, язык и — критично — права доступа. ACL-фильтрация обязана происходить на этапе поиска (фильтр по метаданным в запросе к индексу), а не после генерации: если чанк с чужими данными попал в контекст, утечка уже произошла, что бы вы ни вырезали из ответа. Дата обновления нужна для freshness: при конфликте версий документа выигрывать должен свежий, а устаревшие чанки должны уходить из индекса вместе с обновлением источника.

Retrieval pipeline: hybrid, rerank, packing

Продовый пайплайн поиска почти никогда не состоит из одного векторного запроса. Стандартная цепочка выглядит так:

  1. Гибридный поиск: dense (embeddings) ловит смысловые перефразировки, лексический BM25 ловит точные термины, артикулы и редкие слова, на которых embeddings слепнут. Результаты сливаются, обычно через Reciprocal Rank Fusion (RRF) — простой и устойчивый способ без подбора весов.
  2. Широкая выборка, узкая выдача: из индекса берут top 30–50 кандидатов, затем reranker (cross-encoder) пересортировывает их, читая пару «запрос + чанк» целиком. Bi-encoder на этапе индексации кодирует запрос и документ независимо — это быстро, но грубо; cross-encoder видит их взаимодействие и намного точнее, но дорог — поэтому его применяют только к кандидатам. В контекст уходит top 5–8 после rerank.
  3. Context packing: каждый чанк кладётся в промпт с идентификатором и источником, а инструкция требует ссылаться на id при каждом утверждении:
const context = chunks
  .map((c, i) => '[' + (i + 1) + '] (' + c.source + ', ' + c.updatedAt + ')\n' + c.text)
  .join('\n\n');
// Инструкция: 'Каждое утверждение подкрепляй ссылкой [n]. Нет опоры — так и скажи.'

Цитаты — это не украшение UI, а механизм проверяемости: они позволяют пользователю (и вашим evals) проверить каждое утверждение, а вам — отладить, какой чанк привёл к какому выводу. Ответ без цитат в RAG-системе должен считаться подозрительным по умолчанию.

Failure modes и метрики retrieval

Главная опасность RAG — ошибки выглядят убедительно. Модель, получившая нерелевантные чанки, не скажет «поиск не сработал» — она сгенерирует гладкий ответ из того, что есть, плюс собственные веса. Поэтому качество retrieval и качество генерации измеряются раздельно:

  • Retrieval-метрики считаются на размеченном наборе пар «вопрос → релевантные чанки»: recall@k (какая доля нужных чанков попала в top-k), MRR (как высоко стоит первый релевантный). Если recall@10 низкий — никакой промпт генерацию не спасёт: чинить надо chunking, гибрид, reranker.
  • Faithfulness генерации: доля утверждений ответа, реально подкреплённых переданными чанками. Проверяется LLM-судьёй по паре «ответ + контекст» и выборочной ручной разметкой.

Типовые режимы отказа, которые нужно ловить отдельными счётчиками:

  • Пустой retrieval: релевантного нет, но модель всё равно отвечает — из весов. Лечится порогом релевантности и явным путём «данных недостаточно» как first-class ответом, который показывается пользователю честно, а не маскируется.
  • Устаревший чанк: документ обновили, старая версия осталась в индексе и выигрывает по близости. Лечится дисциплиной переиндексации и фильтром по версии.
  • «Почти правильный» ответ: чанк про смежную тему, ответ правдоподобен, но неверен. Самый опасный режим — ловится только evals и цитатами, по которым видно, что источник не о том.

Практический индикатор здоровья системы: доля ответов без единой цитаты и доля ответов «данных недостаточно». Резкое движение любой из них — повод смотреть traces, не дожидаясь жалоб.

Practice

Knowledge assistant

Соберите мини-ассистента по 20 документам: structure-aware chunking с метаданными, гибридный поиск (BM25 + embeddings, слияние через RRF), reranking, ответ с цитатами [n] и кнопка «показать найденные фрагменты». Разметьте 15 вопросов с ожидаемыми чанками и посчитайте recall@5 до и после включения reranker.

Deliverable

Работающий поиск с цитатами, список чанков, попавших в ответ, и табличка recall@5: гибрид без rerank против гибрида с rerank.

Checkpoint

Как понять, что retrieval провалился, даже если ответ звучит убедительно?

  • ✓ Есть explainability через источники и цитаты, по которым можно проверить каждое утверждение.
  • ✓ Retrieval-качество измеряется отдельно (recall@k / MRR на размеченных парах), а не только «нравится ли ответ».
  • ✓ Путь «данных недостаточно» существует, показывается пользователю честно и отслеживается метрикой.

Check yourself

База знаний компании обновляется каждую неделю. Какой подход выбрать для вопросов-ответов по ней?

01База знаний компании обновляется каждую неделю. Какой подход выбрать для вопросов-ответов по ней?

Зачем в пайплайне reranker, если векторный поиск уже вернул кандидатов по близости?

02Зачем в пайплайне reranker, если векторный поиск уже вернул кандидатов по близости?

Где в RAG-системе применять права доступа пользователя к документам?

03Где в RAG-системе применять права доступа пользователя к документам?

Recall@10 на размеченном наборе — 35%, но ответы «звучат хорошо». Что это означает?

04Recall@10 на размеченном наборе — 35%, но ответы «звучат хорошо». Что это означает?

Каким должно быть поведение системы, когда по запросу не нашлось релевантных чанков выше порога?

05Каким должно быть поведение системы, когда по запросу не нашлось релевантных чанков выше порога?

Sources

RAG and vector search: answering from your own documents · The Practical AI Product Engineering Playbook · VORCL