Почему в RAG недостаточно одного вида поиска
В корпоративной базе знаний встречаются два разных типа вопросов. Первый требует точного совпадения: номер договора, артикул, фамилия, код ошибки, пункт регламента или редкая аббревиатура. Второй выражает смысл другими словами: сотрудник спрашивает «как вернуть оплату», а документ называется «порядок оформления возврата денежных средств».
Лексический поиск BM25 хорошо замечает конкретные слова и редкие токены. Векторный поиск сравнивает смысловые представления и находит перефразированные формулировки. Ни один из методов не гарантирует лидерство на всех данных. В исследовании BEIR, охватившем разнородные задачи информационного поиска, BM25 остался сильной базовой линией, а более сложные методы заметно различались между доменами. Практический вывод для бизнеса: выбирать поисковик по общей таблице лидеров опасно; проверять нужно на собственных вопросах.
Гибридный поиск запускает обе стратегии, объединяет списки кандидатов, при необходимости переупорядочивает их более точной моделью и только затем передаёт несколько фрагментов генеративной модели. Его задача не «сделать RAG умнее» вообще, а уменьшить две конкретные ошибки:
- релевантный документ не попал в выборку;
- нужный фрагмент найден, но оказался ниже шума и не вошёл в контекст.
Где ломается векторный поиск
Эмбеддинги особенно полезны для синонимов, разговорных запросов и документов с разной терминологией. Но они могут пропускать то, что для бизнеса является критичным точным признаком.
Например, запрос по артикулу `AB-1047` может оказаться близок к описаниям всей товарной группы, а не к единственной карточке. Короткие коды, версии программ, номера заявок, даты и фамилии часто несут мало «семантики», зато требуют буквального совпадения. Сложности добавляют русский и английский в одном документе, OCR-ошибки, внутренний жаргон и новые термины, которых не было в обучающих данных модели.
Векторный поиск чувствителен к размеру фрагментов, составу полей и версии модели. Гибрид не исправит плохую загрузку документов, но даст второй путь к точному фрагменту.
Где ломается поиск по словам
BM25 не понимает смысл как человек. Если в вопросе и документе нет общих важных слов, нужный фрагмент может не попасть в кандидаты. Словари синонимов помогают, но быстро превращаются в отдельный продукт: их нужно поддерживать по отделам, языкам и версиям процессов.
Морфология русского языка, опечатки и длинные естественные вопросы требуют анализаторов и настройки полей. Лексический поиск — не устаревший запасной путь, а специализированный сигнал для объединения с семантическим.
Рабочий конвейер из четырёх этапов
Минимальная архитектура выглядит так.
1. **Подготовка запроса.** Шлюз определяет пользователя, допустимые коллекции, язык и структурные фильтры. Права, организация, подразделение, статус документа и срок действия применяются до поиска, а не после генерации ответа.
2. **Два независимых поиска.** BM25 и векторный индекс получают один нормализованный запрос и возвращают, например, по 30 кандидатов. Важные идентификаторы не нужно удалять при нормализации. Для векторной ветки можно отдельно добавить понятное человеку описание запроса, сохранив оригинал для лексической.
3. **Слияние списков.** Reciprocal Rank Fusion, или RRF, начисляет документу баллы по его позиции в каждом списке. Документ, который высоко стоит в обеих выдачах, поднимается; сильный результат только одной ветки тоже сохраняет шанс. Затем остаётся, например, 20–40 уникальных кандидатов.
4. **Reranker и сбор контекста.** Более точная модель оценивает пары «вопрос — фрагмент» и переставляет ограниченный набор. После дедупликации и контроля токенов в LLM уходят пять-восемь фрагментов с источниками.
Числа 30, 20–40 и пять-восемь — стартовые настройки, а не универсальная норма. Их выбирают по полноте поиска, задержке и размеру документов.
Почему RRF удобен для первого пилота
Оценки BM25 и косинусная близость измеряют разные величины. Значение 12,4 в одном поиске нельзя напрямую сравнить с 0,87 в другом. RRF обходит проблему: использует порядковые места, а не исходные оценки. Документация OpenSearch рекомендует такой подход как разумную отправную точку, когда команда ещё не знает, как сопоставлять шкалы и веса.
У RRF есть ограничения. Он не учитывает, насколько первый результат сильнее второго: важны только позиции. Его итоговый балл зависит от числа веток и параметра rank constant, поэтому не стоит применять один `min_score` ко всем запросам или сравнивать RRF-баллы разных вопросов как абсолютную уверенность.
Если разница исходных оценок несёт полезный смысл и есть размеченная выборка, можно перейти к нормализации score и настроенным весам. OpenSearch предлагает min-max, L2 и z-score нормализацию с разными способами объединения. Но такая гибкость увеличивает число параметров, поэтому её следует оплачивать реальным улучшением на контрольном наборе, а не красотой конфигурации.
Зачем нужен reranker
Слияние расширяет охват, но не всегда правильно расставляет похожие документы. Reranker получает вопрос и текст кандидата вместе, поэтому может учитывать точные отношения между ними. Cross-encoder обычно точнее отдельного сравнения эмбеддингов, но дороже: модель должна обработать каждую пару.
Поэтому reranker ставят вторым этапом, а не запускают по всему индексу. Если объединённый список содержит 40 фрагментов, на один пользовательский запрос возникает 40 пар. При тысяче запросов в день это уже 40 тысяч оценок. Размер модели, длина фрагмента, пакетная обработка и оборудование напрямую влияют на p95 задержки.
Для русскоязычного корпуса нужна отдельная проверка. Карточка BAAI `bge-reranker-v2-m3`, например, описывает модель как мультиязычную и Apache-2.0, но это не доказывает качество на ваших договорах, артикулах или инструкциях. Нужен локальный тест, а модель и её лицензию следует фиксировать как часть версии поискового конвейера.
Как собрать контрольный набор
Без разметки гибридный поиск легко превратить в бесконечную настройку весов. Для пилота достаточно 100–200 реальных вопросов из журналов поддержки, интервью с сотрудниками и типовых операций. Секреты и персональные данные нужно удалить до передачи разметчикам.
Набор должен включать разные классы:
- точные идентификаторы, даты, версии и фамилии;
- естественные перефразировки;
- вопросы с несколькими допустимыми документами;
- устаревшие и конфликтующие инструкции;
- запросы, на которые база не содержит ответа;
- русско-английские термины, опечатки и сокращения.
Для каждого вопроса эксперт отмечает релевантность фрагментов, например от 0 до 3. OpenSearch Search Relevance Workbench использует те же базовые сущности: query set, search configuration и judgment list. Автоматический судья может помочь расширить разметку, но критичные примеры должны проверить владельцы процесса.
Сравнивать нужно как минимум четыре конфигурации: BM25, векторный поиск, гибрид без reranker и гибрид с reranker. Полезные метрики:
- **Recall@K:** оказался ли хотя бы один нужный фрагмент среди первых K;
- **nDCG@K:** насколько высоко стоят более релевантные документы;
- доля ответов, полностью подтверждённых переданными источниками;
- доля корректных отказов, когда доказательств нет;
- p50 и p95 времени поиска и полного ответа;
- стоимость или загрузка оборудования на принятый ответ.
Средняя метрика не должна скрывать провалы. Отдельно анализируют точные коды, устаревшие документы и вопросы без ответа.
Данные, фильтры и наблюдаемость
Обе ветки должны искать по одной версии корпуса и одинаковым правилам доступа. Иначе RRF может объединить разрешённый векторный результат с запрещённым лексическим. Для каждого фрагмента нужны стабильный идентификатор, версия документа, источник, ACL, дата действия и признак удаления.
В журнале запроса полезно хранить версию конфигурации, время каждой ветки, позиции кандидатов до и после слияния, результат reranker и фрагменты, реально отправленные модели. Текст запроса и документов логируют только по политике данных; для чувствительных систем достаточно идентификаторов и обезличенных классов ошибок.
Если одна ветка недоступна, система должна явно перейти в деградированный режим. Для критичных справок интерфейс может показать, что поиск выполнен частично.
Модельная экономика
Рассмотрим условный корпус из 50 тысяч фрагментов и тысячу запросов в день. Лексическая и векторная ветки дают по 30 кандидатов, после слияния reranker оценивает 40 уникальных пар. Это 40 тысяч пар в сутки. Само объединение рангов почти ничего не стоит; основные расходы приходятся на построение эмбеддингов, память индекса и reranker.
Иллюстративный расчёт внедрения: 80 часов разработки и измерений по 3 000 рублей — 240 000 рублей. Разметка 150 вопросов по три минуты при внутренней ставке 1 200 рублей в час — ещё 9 000 рублей. Четыре часа сопровождения в месяц по 3 000 рублей дают 144 000 рублей в год. Это не прайс поставщика, а модель для решения.
Если BM25 уже даёт требуемый Recall@20 и сотрудники редко перефразируют вопросы, гибрид может не окупиться. Если ошибки поиска ведут к повторным обращениям, ручному просмотру десятков документов или неверным действиям, оценивать следует стоимость устранённых ошибок, а не только миллисекунды сервера.
Пилот за десять рабочих дней
1. Соберите 100–200 реальных вопросов и разметьте контрольную часть.
2. Зафиксируйте текущий BM25 или векторный поиск как baseline.
3. Подключите вторую ветку с теми же ACL и версией корпуса.
4. Начните с RRF без ручных весов; сохраните объяснение вклада каждой ветки.
5. Добавьте reranker только для верхних 20–40 кандидатов и ограничьте длину фрагмента.
6. Сравните четыре конфигурации по качеству, отказам и p95 задержки.
7. Запустите победителя в теневом режиме, затем на небольшой доле пользователей с быстрым откатом.
Руководителю не нужно выбирать между «старым поиском» и «нейросетью». Вопрос другой: какие запросы теряются, какой второй сигнал их возвращает и сколько стоит дополнительный подтверждённый ответ.
