В Дне 23 ты построил базовый RAG и увидел: top-N по эмбеддингам — не значит «лучшие». Сегодня — про второй этап, где из найденного выбирается реально релевантное. И почему хорошая RAG-система — это не «поиск», а «воронка».
Эмбеддинговый поиск даёт «примерно подходящее» — быстро и дёшево, но не точно. Чтобы из 50 подходящих выбрать 5 действительно нужных, нужен второй проход — реранкинг. Это специализированная модель, которая читает каждый найденный фрагмент вместе с запросом и оценивает их совпадение. Плюс — фильтры по метаданным (дата, автор, тип документа), которые сужают пространство поиска до того, как начался семантический. Серьёзный RAG — это всегда воронка с двумя-тремя этапами.
Базовый RAG из Дня 23 устроен просто: текст запроса → вектор → ищем top-5 ближайших векторов в БД → суём в контекст. И ты увидел, что результат часто разочаровывает: в топ попадают «похожие, но не те», действительно нужное оказывается на 8-м месте.
Это не баг — это фундаментальное свойство эмбеддинг-поиска. Чтобы понять почему, надо вспомнить, как он работает.
Эмбеддинг — это вектор фиксированной длины (768, 1536, 3072 чисел), который пытается сжать весь смысл текста в одну точку. Это очень мощное сжатие. Но и очень лоссовое: что-то всегда теряется.
Конкретно, эмбеддинги хорошо ловят общий смысл и тему, но плохо различают:
Поэтому даже когда top-50 «правильные по теме», внутри этих 50 нужный документ редко стоит первым. Хорошие документы перемешаны с «похоже выглядящими» неправильными.
Эмбеддинги — это инструмент recall (полнота): «среди всех документов найди те, что про эту тему». Но они плохо справляются с precision (точность): «из похожих по теме выбери именно правильный».
Это и есть формальная причина, почему RAG нужно две модели: одна для recall (эмбеддинги), вторая для precision (реранкер).
Серьёзный RAG-pipeline устроен как воронка. Каждый этап делает свою работу:
Каждая ступень делает то, что плохо делает следующая:
«Найди мне всё, что про это»
Берёт твою базу из 1M чанков и быстро (за миллисекунды) находит top-50, которые «похожи по теме» на запрос. Не точные, не отранжированные — просто множество кандидатов, среди которых наверняка есть правильные.
Цель этого этапа — не упустить. Лучше взять 50 кандидатов, из которых 80% мусор, чем 5, из которых нужное не попало.
«Из этих 50 выбери 5 действительно правильных»
Берёт top-50 от первой ступени и пропускает каждый через специальную модель-реранкер. Реранкер читает (запрос + один документ) вместе и выдаёт число — насколько они совпадают. Сортирует по этому числу, отбирает top-5.
Ключевое отличие от эмбеддингов: реранкер видит конкретные слова и связи запроса с документом. Он замечает, что «Acme» в запросе и «Beta» в документе — это разные сущности. Видит отрицания. Видит числа.
На рынке есть готовые модели-реранкеры, которые ты подключаешь как сервис:
Технически реранкер устроен как cross-encoder: он подаёт пару (запрос, документ) через одну модель и выдаёт скор. Эмбеддинг-модель — это bi-encoder: запрос и документ кодируются отдельно, потом меряется расстояние. Это разница объясняет, почему реранкер точнее, но медленнее.
Эмбеддинги и реранкеры — это семантический поиск. Он отлично ловит смысл, но плохо ограничивает по фактам: «только за последний месяц», «только этого автора», «только в этом проекте». Для таких ограничений нужны фильтры по метаданным.
Когда ты индексировал документы (День 22), помимо самого текста и эмбеддинга у каждого чанка можно (и нужно) хранить метаданные — структурированные поля:
doc_type: статья / тикет / письмо / спецификацияauthor: кто создал документcreated_at: дата созданияtags: ручная разметка («billing», «onboarding», «api»)project_id: к какому проекту относитсяlanguage: язык документаaccess_level: кто имеет право видеть
Современные векторные БД (Pinecone, Weaviate, Qdrant, pgvector + jsonb) умеют делать гибридный запрос: «найди ближайшие векторы среди тех, у кого tags содержит «billing» и created_at > 2024-01-01».
Фильтр — это первая ступень воронки. До эмбеддинг-поиска. До реранкера. Это сильно меняет экономику системы:
Из 1M чанков → 100K по фильтрам → эмбеддингам нужно сравнивать в 10 раз меньше. Реранкер обрабатывает 50 «хороших по теме», а не «50 случайных».
В результатах не появятся документы из «не того» проекта или старее чем нужно. Реранкеру не приходится их отсеивать — их просто нет.
Фильтр по access_level = роль пользователя. Чужие документы физически не попадут в результаты, даже семантически релевантные.
Главный практический вопрос: пользователь не пишет «покажи мне статьи 2024 года в проекте Acme». Он пишет «что у нас с Acme?». Откуда система знает, что нужно фильтровать?
Три типичных подхода:
У тебя уже есть данные про пользователя из его сессии: в каком проекте он находится, его роль, текущая страница. Эти фильтры применяются автоматически, без вмешательства модели.
Например: пользователь зашёл в проект Acme → все RAG-запросы в этой сессии автоматически фильтруются по project_id = "acme". Это самый частый и надёжный подход.
Преимущество: работает 100% времени, без ошибок LLM, без зависимости от формулировки запроса.
Перед RAG-поиском запускаешь отдельный маленький LLM-вызов: «извлеки из этого запроса фильтры». Запрос «что у нас по Acme за последний квартал?» → {project: "acme", date_from: "2024-Q4"}.
Этот промпт идёт быстро, на дешёвой модели, с structured output (День 2). Результат — JSON с фильтрами, которые применяются на этапе поиска.
Когда использовать: когда пользователь часто пишет запросы с явными фильтрами в тексте («за прошлую неделю», «от Ивана», «только баги»).
Самый простой и часто недооценённый: дать пользователю явные фильтры в интерфейсе. Дропдауны «проект», «дата», «автор», «тип документа». Перед запросом он их выставляет, фильтры идут в RAG-pipeline.
Это паттерн «как в продвинутом поиске почты». Не очень модный для AI-чатов, но работает идеально — нет ошибок LLM, нет догадок.
Когда использовать: когда запросы пользователя нечёткие, но контекст важен. В корпоративных продуктах с экспертными пользователями это часто лучший вариант.
Два числа определяют твою воронку: N — сколько берём после эмбеддинг-поиска, K — сколько отдаём модели после реранкера.
Практическое правило: N=30-50, K=3-7. Подстраивается под задачу: для сложных вопросов с фактами — K=5-7, для простых — K=2-3.
Реранкер — это дополнительная стоимость и latency. Когда он действительно нужен:
Когда без реранкера обойтись: маленькая база (<5K чанков), узкая предметная область, требования к скорости больше требований к точности.
«Сначала запустим простой RAG, потом оптимизируем реранкером». На практике без реранкера качество настолько отличается, что «простой RAG» иногда невозможно пустить даже в бету. Лучше с первого дня закладывать двухступенчатую архитектуру.
Реранкер — это не финальная оптимизация, это часть фундаментальной архитектуры. Особенно если у тебя продакшен с реальными пользователями.
«Возьмём дорогую эмбеддинг-модель, она различит проекты сама». Не различит. Эмбеддинги принципиально плохо работают с точными сущностями. Фильтры по метаданным — это не «костыль», это правильный способ ограничивать пространство поиска.
Правило: всё, что можно точно зафильтровать (даты, проекты, теги) — фильтруй. Семантический поиск оставляй на то, что без него никак.
«Сначала проиндексирую тексты, метаданные потом добавлю». На практике добавлять метаданные потом — это переиндексировать всё заново: тысячи чанков, десятки минут. Дорого и больно.
Привычка: при индексации записывать все метаданные сразу, даже если не уверен, что они понадобятся. Лишние поля в индексе ничего не стоят, отсутствие нужного поля стоит переиндексации.
«Везде использую N=30 K=5». В реальности разные запросы требуют разных воронок. «Покажи последний инцидент» — нужен 1 чанк, фильтр по дате. «Что мы знаем про Acme?» — нужно 10 чанков, разные стороны.
Продвинутый паттерн: классификация запроса перед поиском (маленьким LLM-вызовом), и на основе типа — выбор стратегии поиска. Это уже близко к agentic RAG.
Открой Perplexity, ChatGPT с web search, или похожий продукт. Задай вопрос на тему, в которой ты — эксперт. Внимательно посмотри на список найденных источников: какие из них действительно по делу, какие — «вообще про эту тему, но не отвечают на вопрос»? Часто 2 из 8 источников — правильные, 6 — рядом-стоящий шум. Это и есть «recall без хорошего реранкинга». Чувство этой проблемы — половина понимания темы.
Возьми реальный набор документов из своей работы (база знаний компании, твои заметки в Obsidian, корпоративная wiki). Распиши: какие метаданные у каждого документа есть или должны быть? Что бы помогало фильтровать перед семантическим поиском? Минимум 5 полей. Это и есть фундамент твоей будущей RAG-архитектуры.
Cohere предоставляет демо-страницу с реранкером (cohere.com / dashboard). Загрузи 10-15 коротких текстовых фрагментов и запрос. Посмотри, как они ранжируются. Затем — поменяй порядок текстов и снова запусти: ранжировка такая же. Это даёт ощущение, что реранкер работает стабильно и независимо от исходного порядка. Хорошее интуитивное понимание того, как он отличается от эмбеддинг-поиска.