Урок курса

Гибридный поиск в RAG: BM25, векторы и reranking

Vector DB & RAG Developer

Векторный поиск хорошо находит смысловые переформулировки, но может пропускать точные артикулы, имена и редкие термины. BM25 опирается на совпадение токенов и частоты: он силён для идентификаторов и ключевых слов, но слабее понимает синонимы. Гибридный retrieval запускает оба метода и объединяет кандидатов.

Один и тот же документ хранит текст, метаданные и dense embedding; для лексического пути используется inverted index или sparse vector. По запросу система получает два ranking list, после чего выполняет fusion. Так exact match не исчезает из-за семантики, а естественная формулировка не требует точного слова из документа.

Фильтры по tenant, доступу, языку и времени применяются до выдачи контекста модели. Гибридный score не заменяет авторизацию.

Fusion и RRF

Сырые score разных retriever живут в разных шкалах: cosine similarity ограничена, BM25 зависит от корпуса и запроса. Складывать их без нормализации ненадёжно. Reciprocal Rank Fusion использует позиции документов и повышает элементы, которые стоят высоко в нескольких списках.

RRF — хороший baseline, когда нет калиброванных score. Некоторые движки также поддерживают нормализованное смешивание с весом между lexical и vector частями. Вес настраивают по eval-набору, а не по одному красивому запросу.

Увеличение числа кандидатов повышает recall, но увеличивает latency и стоимость следующего этапа. Сначала измерьте Recall@k каждого пути и объединения, затем выберите разумный candidate pool.

Зачем reranking

Первичный retrieval должен быстро собрать несколько десятков кандидатов. Более дорогая cross-encoder или late-interaction модель затем оценивает пару «запрос — документ» точнее и переставляет top результатов. Reranker не найдёт документ, которого не было в candidate pool, поэтому retrieval и reranking измеряют отдельно.

Финальный pipeline часто выглядит так: фильтры доступа → dense и sparse retrieval → fusion → дедупликация → reranking → порог «не знаю» → контекст LLM. Каждый этап логирует идентификаторы и score, чтобы ошибку ответа можно было разложить на поиск и генерацию.

Гибридный поиск оправдан, если eval показывает улучшение на реальных вопросах. На маленькой чистой базе один BM25 или vector retriever может быть быстрее и не хуже.

Объединим два списка через RRF

Лексический поиск вернул документы A, B, C, а векторный — B, D, A. Для RRF каждому документу добавляют 1/(k+rank) из каждого списка, где позиция начинается с единицы. Сырые score двух поисков здесь не складываются. Параметр k=60 — выбранная настройка учебного примера, а не размер выдачи.

def rrf(rankings, k=60):
    scores = {}
    for ranking in rankings:
        for rank, doc_id in enumerate(ranking, start=1):
            scores[doc_id] = scores.get(doc_id, 0) + 1/(k+rank)
    return sorted(scores, key=lambda doc_id: (-scores[doc_id], doc_id))
result = rrf([["A", "B", "C"], ["B", "D", "A"]])
print(result)
assert result[:2] == ["B", "A"]

B поднимается благодаря сильным позициям в обоих списках. C и D присутствуют только в одном. Если нужного документа не было ни в одном списке кандидатов, fusion его не создаст. Проверьте полноту объединения до дорогого reranker и сравните задержку при разных размерах candidate pool.

Продолжите разбор: Метрики качества RAG: Recall, MRR и Faithfulness.

Задача 1

Почему нельзя бездумно складывать сырой cosine score и BM25 score?

Выберите один вариант
Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку