Ваш RAG-пайплайн працює. Відповіді генеруються, retrieval повертає результати.
Але користувач шукає get_user_v2 — і замість документації отримує
статтю про user management. Або питає про "стаття 42 ЗУ про захист персональних
даних" — і vector search повертає три чанки про GDPR, але жоден не містить тексту
потрібної статті.
Спойлер: проблема не в LLM і не в embedding-моделі. Проблема в
тому, що чистий vector search шукає сенс — але іноді потрібен
текст. Hybrid search + reranking закривають цю діру і дають +15–25%
якості retrieval у реальних проєктах без жодної зміни моделі.
⚡ Коротко
- ✅ Vector search vs BM25: сенс vs ключові слова — потрібна комбінація
- ✅ Hybrid search: об’єднання через RRF, а не нормалізацію скорів
- ✅ Reranking: +8–25% якості за рахунок cross-encoder
- 🎯 Ви отримаєте: коли і як застосовувати hybrid + reranking з кодом
- 👇 Нижче — архітектура, формули та приклади
📚 Зміст статті
🎯 Розділ 1. Два типи пошуку: чому кожен сильний по-своєму
BM25 (keyword search) знаходить точні збіги — артикули, ID, назви методів.
Dense vector search знаходить семантично схожі документи — синоніми,
перефразування, cross-lingual запити. Жоден з цих підходів не є достатнім
для production RAG: BM25 не розуміє сенс, а vector search "розмиває"
точні значення.
Якщо vector search — це "знайди щось схоже за змістом", то BM25 — це
"знайди документ, де є саме це слово". Production RAG потребує обох.
BM25 (Keyword Search): чому алгоритм 1994 року досі живий
BM25 (Best Matching 25) — це класичний алгоритм ранжування, який оцінює
релевантність документа за трьома факторами: частота терміну в документі (TF),
зворотна частота по корпусу (IDF) і довжина документа. Алгоритм був
формалізований Robertson та Walker у 1994 році
і досі є стандартом keyword-пошуку в Elasticsearch, OpenSearch і більшості
пошукових систем.
Чому він не помер за 30 років? Тому що для певних типів запитів нічого кращого
немає. Коли користувач шукає SKU-4521, get_user_v2
або "стаття 42" — це exact match задача. Embedding-модель перетворює
SKU-4521 на вектор, який описує загальний "сенс" товарного артикулу,
але різниця між 4521 і 4522 у цьому векторі мінімальна.
BM25 знаходить точний збіг за мілісекунди — без нейронних мереж, без GPU,
без ембедингів.
Де BM25 незамінний: артикули і коди товарів, назви функцій і API-ендпоінтів,
номери документів і статей законів, рідкісні терміни і абревіатури, точні цитати.
Обмеження BM25: "автомобіль" ≠ "машина". Якщо користувач написав
"скасувати підписку", а в документі — "відмовитись від тарифу", BM25
не знайде нічого, бо жодного спільного слова немає.
Dense Vector Search (Semantic): сила контексту
Dense vector search працює інакше. Запит і документи перетворюються на числові
вектори (embeddings), і пошук відбувається за
cosine similarity — кутом між векторами у просторі сенсу.
"Скасувати підписку" і "відмовитись від тарифу" отримають близькі вектори,
бо embedding-модель навчилась, що ці фрази означають одне і те саме.
Де dense vector search незамінний: семантичний пошук по синонімах і
перефразуваннях, cross-lingual запити (запит українською знаходить документ
англійською), запити природною мовою ("як зменшити витрати на інфраструктуру").
Обмеження: embedding "розмиває" точні значення. Два різних артикули отримують
майже однаковий вектор. Короткі запити з одного-двох слів дають нечіткий вектор.
Детально про ці обмеження — у
статті про embeddings
Таблиця: коли що працює
| Тип запиту |
BM25 |
Dense Vector |
Hybrid |
get_user_v2 (точний термін) |
✅ точний збіг |
❌ розмиває |
✅ |
| "як скасувати підписку" (семантичний) |
❌ немає збігів слів |
✅ семантика |
✅ |
| "стаття 42 закону про дані" (змішаний) |
✅ "стаття 42" |
✅ "захист даних" |
✅✅ обидва сигнали |
| "pricing" (1 слово) |
⚠️ занадто широко |
⚠️ розмитий вектор |
⚠️ потрібен query transform |
- ✔️ BM25: незамінний для exact match — ID, артикули, назви функцій
- ✔️ Dense vectors: незамінні для семантичного пошуку — синоніми, перефразування, cross-lingual
- ✔️ Жоден з підходів не є самодостатнім для production RAG
Висновок розділу:
BM25 і dense vector search — це не конкуренти, а комплементарні інструменти.
Перший знаходить слова, другий — сенс. Production RAG потребує обох.
📌 Розділ 2. Hybrid Search: як об'єднати обидва підходи
Hybrid search виконує BM25 і dense vector search паралельно, а потім
об'єднує результати через Reciprocal Rank Fusion (RRF) — алгоритм, який
використовує позиції у рейтингу замість скорів. RRF не потребує нормалізації
і стабільно працює з різнотипними джерелами. На бенчмарках
Weaviate (2025)
hybrid search з RRF перевершує best-performing single-method на 2.6–13.4
пунктів nDCG@10.
Головна проблема об'єднання результатів з BM25 і vector search — їхні скори
живуть на різних шкалах і їх не можна просто скласти. RRF елегантно обходить
цю проблему, працюючи з рангами, а не з числами.
Reciprocal Rank Fusion (RRF): простий і надійний метод злиття
RRF був запропонований
Cormack, Clarke та Buettcher у 2009 році (SIGIR '09) і з тих пір став
стандартом де факто для hybrid search. Формула:
score(d) = Σ 1 / (k + rank(d))
де rank(d) — позиція документа у кожному окремому рейтингу,
а k — константа згладжування (стандартне значення: 60).
Чому k = 60? Як пояснює
документація Elasticsearch, ця константа запобігає надмірному впливу
першої позиції. Без згладжування різниця між рангом 1 (score = 1.0) і
рангом 2 (score = 0.5) — двократна. З k = 60 різниця між
рангом 1 (1/61 ≈ 0.0164) і рангом 2 (1/62 ≈ 0.0161) — мінімальна, що
робить злиття стабільнішим.
Чому RRF кращий за лінійну комбінацію скорів? Три причини.
По-перше, BM25 повертає скори в довільному діапазоні (від 0 до десятків),
а cosine similarity — від -1 до 1. Нормалізація цих шкал до спільного
діапазону — нетривіальна задача, яка залежить від розподілу скорів у
конкретному корпусі. RRF працює виключно з позиціями, ігноруючи абсолютні
скори.
По-друге, RRF нечутливий до outlier'ів: один документ з аномально високим
BM25-скором не "перетягне" на себе весь рейтинг.
По-третє, як зазначає
OpenSearch (2025), RRF природно підсилює документи, які з'являються
у верхніх позиціях кількох рейтингів одночасно — що є сильним сигналом
релевантності.
Приклад з числами
BM25 повертає: [Doc A (rank 1), Doc C (rank 2), Doc B (rank 3)]
Dense повертає: [Doc B (rank 1), Doc A (rank 2), Doc D (rank 3)]
RRF-скори (k=60):
- Doc A: 1/(60+1) + 1/(60+2) = 0.0164 + 0.0161 = 0.0325 ← виграє
- Doc B: 1/(60+3) + 1/(60+1) = 0.0159 + 0.0164 = 0.0323
- Doc C: 1/(60+2) + 0 = 0.0161
- Doc D: 0 + 1/(60+3) = 0.0159
Результат: [A, B, C, D]. Doc A виграє, бо стабільно у верхніх позиціях
обох рейтингів.
Weighted Hybrid: коли потрібен контроль через α (alpha)
RRF дає рівну вагу кожному методу пошуку. Але не завжди це оптимально.
Для технічної документації з великою кількістю точних термінів BM25 має бути
"голосніше". Для customer support з природномовними запитами — dense vectors
важливіші.
Більшість vector DB підтримують параметр α (alpha), де
α = 0.0 — чистий BM25, α = 1.0 — чистий vector search.
Weaviate документація
дозволяє виставити alpha безпосередньо у запиті.
Elasticsearch з версії 8.x підтримує weighted RRF — кожен retriever
отримує свою вагу.
Рекомендації по доменах (орієнтовні — тестуйте на своїх даних):
- Технічна документація, код: α = 0.3–0.4 (більше keyword)
- Загальний контент, customer support: α = 0.6–0.7 (більше семантики)
- Юридичні тексти: α = 0.4–0.5 (баланс: точні статті + семантичний контекст)
- E-commerce каталоги: α = 0.3–0.5 (артикули + описи товарів)
Як підібрати α на практиці: візьміть 20–30 реальних запитів
з відомими правильними відповідями, прогоніть пошук з α від 0.1 до 0.9
з кроком 0.1, порівняйте recall@5. Це займає годину і дає конкретну відповідь
для вашого домену.
Які Vector DB підтримують hybrid нативно
| Vector DB |
Hybrid підтримка |
Метод злиття |
Примітка |
| Qdrant |
✅ нативно |
RRF, DBSF |
Sparse vectors через
BM25 або SPLADE,
prefetch multi-stage
|
| Weaviate |
✅ нативно |
RRF, Relative Score Fusion, Learned Fusion (v1.25+) |
Найпростіший API:
один параметр alpha
|
| Elasticsearch |
✅ нативно |
RRF, Weighted RRF, Linear |
Потужно, але складніший setup.
Weighted RRF з v8.x
|
| pgvector |
⚠️ вручну |
Окремий BM25 (ts_vector) + злиття в коді |
Підходить якщо Postgres вже є, але вимагає ручної роботи |
| ChromaDB |
✅ з v0.6+ |
RRF через Rrf() API
|
Вимагає sparse vector index, не доступно у legacy API |
Детальне порівняння vector DB — у статті
ChromaDB, Qdrant або pgvector: як обрати.
⚠️ Підводні камені
Невірний α вбиває якість замість покращення.
На бенчмарку
WANDS (e-commerce) RRF додав лише +1.7% Mean NDCG над dense-only.
Якщо ваші запити переважно семантичні і без точних термінів — hybrid може не
дати помітного приросту. Вимірюйте, не вірте дефолтам.
Подвійна індексація = подвійні ресурси.
Hybrid search вимагає і інвертованого індексу (для BM25), і векторного.
Це більше RAM і більше часу на індексацію. Для невеликих проєктів
(<10K документів) додатковий overhead може бути невиправданим.
α-рекомендації по доменах — це орієнтири, не абсолютні правила.
Оптимальне значення залежить від вашого корпусу, мови, типу запитів.
Завжди тестуйте на реальних даних.
- ✔️ RRF — стандарт де факто для hybrid search, працює з рангами замість скорів
- ✔️ Weighted hybrid (α) дає контроль — але потребує тестування на реальних запитах
- ✔️ Qdrant, Weaviate, Elasticsearch підтримують hybrid нативно
Висновок розділу:
На мою думку Hybrid search — перший і найпростіший крок для підвищення якості RAG.
Якщо ваші запити містять точні терміни — ефект (ROI) помітний одразу.
📌 Reranking: другий етап, який змінює все
Reranking — це другий етап retrieval, де cross-encoder модель переоцінює
кожну пару (запит, документ) і переупорядковує кандидатів за точнішою оцінкою
релевантності. Типова архітектура: hybrid search повертає топ-50, reranker
обирає фінальні 5–10 для LLM. За даними
Agentset Reranker Leaderboard (2026),
reranking стабільно покращує nDCG@10 і hit rate незалежно від embedding-моделі.
Bi-encoder (embedding model) оцінює запит і документ окремо —
швидко, але грубо. Cross-encoder (reranker) оцінює пару разом —
точно, але повільно. Перший — для відсіювання, другий — для точного
ранжування.
Чому top-k з першого етапу недостатньо
Embedding-модель (bi-encoder) перетворює запит і документ на вектори
незалежно один від одного. Це робить пошук швидким — можна порівнювати
мільйони документів за мілісекунди. Але ця швидкість коштує точності: модель
не "бачить" запит і документ одночасно, тому може не вловити тонкий зв'язок
між ними.
Cross-encoder (reranker) працює інакше. Він приймає пару (запит + документ)
як єдиний вхід і обробляє їх разом через всі шари трансформера. Це дає
значно точнішу оцінку релевантності — але кожна пара вимагає окремого проходу
через модель. На 1 мільйоні документів це зайняло б хвилини замість мілісекунд.
Аналогія: bi-encoder — це сканування 1000 резюме за ключовими словами.
Cross-encoder — це співбесіда з кожним кандидатом. Очевидно, що на першому
етапі потрібно скоротити список, а на другому — ретельно обрати найкращих.
Two-Stage Retrieval: архітектура
Запит → [Stage 1: Hybrid Search → top-50] → [Stage 2: Reranker → top-5] → LLM
Stage 1 (Hybrid Search): швидкий, грубий відбір. BM25 + dense
vectors + RRF повертають ~50 кандидатів за 20–50ms. Мета — максимізувати recall:
переконатись, що правильний документ є десь у списку.
Stage 2 (Reranker): точне переранжування. Cross-encoder оцінює
кожну з 50 пар (запит, документ) і обирає фінальні 5–10. Час: 100–300ms
залежно від моделі і кількості документів. Мета — максимізувати precision:
поставити найрелевантніше на перше місце.
Чому 50, а не 20 або 200? Це trade-off recall vs latency. Менше 20
кандидатів — ризик, що релевантний документ не потрапить у вибірку.
Більше 100 — reranker стає bottleneck за latency.
ZeroEntropy (2026) рекомендує 50 документів для чат-ботів (де важлива
швидкість) і 100–200 для задач comprehensive search.
Lost in the Middle: як reranking вирішує проблему позиційного bias
LLM краще використовують інформацію з початку і кінця контекстного вікна,
ігноруючи середину. Це ефект "lost in the middle", задокументований у
Stanford TACL дослідженні:
падіння точності на 20–50% для інформації, розміщеної в середині довгого
контексту. Детально про цей ефект — у
статті про контекстне вікно LLM, Розділ 3.
Reranker вирішує це побічно, але ефективно. Він не просто фільтрує — він
упорядковує. Якщо найрелевантніший чанк стоїть на позиції 47 з 50,
reranker підніме його на позицію 1. А оскільки у LLM контекст формується
з топ-5 результатів reranker'а, найважливіша інформація автоматично
опиняється на початку контексту — саме там, де LLM працює найефективніше.
Порівняння Rerankers (2026)
За даними
Agentset Reranker Leaderboard (2026)
та
BSWEN порівняння (2026):
| Reranker |
Тип |
Якість |
Latency (50 docs) |
Ціна |
Коли обирати |
| Zerank-2 |
API |
Найвища (ELO лідер) |
~600ms |
~$0.05/1K запитів |
Найкраща якість, production |
| Voyage Rerank 2.5 |
API |
Висока |
~600ms |
Порівнянна з Cohere |
Баланс якість/швидкість |
| Cohere Rerank 3.5 |
API |
Висока |
~600ms |
$2/1K запитів |
Production, reliability, SLA |
| bge-reranker-v2-m3 |
Self-hosted |
Висока |
~80ms (GPU), ~350ms (CPU) |
$0 (потрібен GPU) |
Конфіденційні дані, контроль |
| mxbai-rerank-large-v2 |
Self-hosted |
Висока (BEIR лідер) |
~150ms (GPU) |
$0 (Apache 2.0) |
Open-source production |
| cross-encoder/ms-marco |
Self-hosted |
Середня |
~300ms (GPU) |
$0 |
Прототипування, бюджет |
Важливий нюанс: за даними Agentset,
Cohere v3.5 — найшвидший серед API-рішень, але за якістю (ELO score)
поступається Zerank і Voyage. BGE-v2-m3 на GPU конкурує з API-рішеннями
за latency при нульовій вартості за запит, що робить його оптимальним
вибором для self-hosted production.
Коли reranking НЕ допоможе
❌ Поганий chunking → reranker сортує сміття → сміття
залишається сміттям. Якщо важлива інформація розірвана між чанками — навіть
ідеальний reranker не склеїть її назад. Детально — у
статті про chunking strategies.
❌ Невірна embedding-модель → hybrid search не знаходить
релевантних кандидатів → reranker'у нічого сортувати. Якщо модель погано
працює з вашою мовою або доменом — спочатку замініть її.
❌ Брудні дані (дублікати, застарілий контент) → reranker
підніме "найкращий" дублікат, але проблема залишиться. Garbage in — garbage out.
⚠️ Підводні камені
"+48% якості" — це маркетинг.
Цифри
Pinecone/Superlinked — best-case на ідеальних бенчмарках. У реальних
проєктах цільтесь у +15–25% покращення retrieval. Якщо на вашому корпусі
ефект менше +5% — проблема, імовірно, не в retrieval.
Latency budget.
Reranker додає 100–300ms до кожного запиту. Для чат-ботів з очікуваним
response time < 2s це суттєва частка. Рахуйте повний pipeline:
embedding (20ms) + hybrid search (30ms) + reranker (200ms) + LLM (500–1500ms)
= 750–1750ms.
GPU для self-hosted.
BGE-reranker-v2 на CPU дає ~350ms latency. На GPU — ~80ms. Різниця у 4x
може визначити, чи вписуєтесь ви у latency budget.
BSWEN (2026) описує як автор ледь не відмовився від BGE через
тестування на CPU.
- ✔️ Two-stage retrieval (hybrid → reranker) — стандартна production-архітектура
- ✔️ Reranker вирішує і precision, і lost in the middle
- ✔️ Self-hosted (BGE-v2-m3) конкурує з API-рішеннями на GPU
З мого досвіду:
Reranking — другий за ROI крок після hybrid search. Додає 100–300 ms latency,
але суттєво підвищує precision і усуває позиційний bias.
Головне обмеження: reranker не виправить поганий chunking або брудні дані.
📌 Query Transformation: коли запит занадто "бідний"
Query transformation — це техніки розширення або переформулювання запиту
перед пошуком. Multi-query генерує кілька варіантів запиту для підвищення
recall. HyDE створює "гіпотетичну відповідь" і шукає по її вектору.
Step-back prompting узагальнює запит до ширшого рівня. Кожна техніка
додає 0.5–2 секунди latency через додатковий LLM-виклик.
Hybrid search + reranking вирішують 80% проблем retrieval. Але залишаються
випадки, коли сам запит — недостатньо інформативний для пошуку.
Цей розділ — для тих 20%.
Multi-query
LLM генерує 3–5 варіантів оригінального запиту, кожен шукається окремо,
результати об'єднуються через RRF. Техніка формалізована як
RAG-Fusion (Rackauckas, 2024)
і добре інтегрується з existing hybrid pipeline.
Коли працює: неоднозначні запити ("як це налаштувати" — що саме?), запити
з неявним контекстом.
Коли зайвий: чіткі конкретні запити, де одного формулювання достатньо.
Latency: +500ms–1.5s (один LLM-виклик для генерації варіантів).
HyDE (Hypothetical Document Embeddings)
LLM генерує "гіпотетичну ідеальну відповідь" на запит, embedding цієї
відповіді використовується для пошуку. Оригінальна
стаття Gao et al. (2023).
Коли працює: короткий запит, довга очікувана відповідь. Запит "OAuth" →
LLM генерує абзац про OAuth flow → embedding цього абзацу шукає схожі
документи значно точніше, ніж embedding одного слова "OAuth".
⚠️ Ризик: на вузьких доменах (медицина, юриспруденція) LLM
може згалюцинувати "гіпотетичний документ" з неправильними фактами — і пошук
піде в хибному напрямку. Використовуйте HyDE тільки на загальних доменах,
де LLM має достатні знання.
Latency: +1–2s (один LLM-виклик).
Step-back Prompting
LLM спочатку формулює ширше питання, потім шукає по ньому.
Запит "чому bge-reranker-v2 повільніший на CPU" → step-back:
"як працюють cross-encoder rerankers і які у них вимоги до hardware" →
пошук по ширшому запиту знаходить загальну документацію, яка містить
і відповідь на конкретне питання.
Коли працює: дуже специфічні запити, де прямий пошук не повертає результатів.
Latency: +500ms–1s.
Latency Tax: таблиця
| Техніка |
Додатковий час |
LLM-виклик |
Коли виправдано |
| Multi-query |
+0.5–1.5s |
✅ 1 виклик |
Неоднозначні запити |
| HyDE |
+1–2s |
✅ 1 виклик |
Короткі запити, загальний домен |
| Step-back |
+0.5–1s |
✅ 1 виклик |
Вузькоспеціалізовані запити |
| Без трансформації |
0 |
❌ |
Чіткі конкретні запити |
⚠️ Підводні камені
HyDE на вузьких доменах — ризик.
Якщо LLM не має достатніх знань у вашому домені, "гіпотетичний документ"
буде неправильним, і пошук знайде нерелевантні чанки. Тестуйте на 10–20
запитах перед впровадженням.
Latency складається.
Multi-query + reranking = +2–3.5s до кожного запиту. Для інтерактивних
чат-ботів це може бути неприйнятним. Для batch-processing або аналітичних
задач — цілком виправдано.
Висновок розділу:
Query transformation — це інструмент для специфічних випадків, не для всіх
запитів. Впроваджуйте після hybrid search і reranking, і тільки якщо бачите
конкретні проблеми з recall на певних типах запитів.
📌 Практика: мінімальний код для старту
Hybrid search на Qdrant реалізується через prefetch API з RRF fusion
за ~15 рядків Python-коду. Для додавання reranking — ще ~10 рядків
з Cohere API або sentence-transformers. Нижче — copy-paste ready приклади
для обох варіантів.
Hybrid Search + RRF на Qdrant (Python)
Qdrant підтримує hybrid search нативно через
Universal Query API з prefetch-механізмом. Приклад використовує
вбудований BM25 та dense vectors:
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
def hybrid_search(query: str, limit: int = 10):
"""Hybrid search з RRF: dense + sparse (BM25)."""
return client.query_points(
collection_name="my_documents",
prefetch=[
# Stage 1a: Dense vector search
models.Prefetch(
query=models.Document(
text=query,
model="sentence-transformers/all-MiniLM-L6-v2",
),
using="dense",
limit=50, # top-50 для recall
),
# Stage 1b: Sparse (BM25) search
models.Prefetch(
query=models.Document(
text=query,
model="Qdrant/bm25",
),
using="sparse",
limit=50,
),
],
# Злиття через RRF
query=models.FusionQuery(fusion=models.Fusion.RRF),
limit=limit,
).points
# Використання
results = hybrid_search("стаття 42 закону про захист даних")
for i, point in enumerate(results, 1):
print(f"{i}. {point.payload.get('title')} (Score: {point.score:.4f})")
Код базується на
офіційному туторіалі Qdrant і документації
Query API.
Додаємо Reranking (Cohere API)
import cohere
co = cohere.Client("your-api-key")
def hybrid_search_with_rerank(query: str, top_k: int = 5):
"""Two-stage: hybrid search (top-50) → rerank (top-k)."""
# Stage 1: Hybrid search
candidates = hybrid_search(query, limit=50)
# Формуємо документи для reranker
docs = [point.payload.get("text", "") for point in candidates]
# Stage 2: Reranking
reranked = co.rerank(
model="rerank-v3.5",
query=query,
documents=docs,
top_n=top_k,
)
# Повертаємо переранжовані результати
return [
{
"text": docs[r.index][:200],
"relevance_score": r.relevance_score,
"original_rank": r.index + 1,
}
for r in reranked.results
]
Як виміряти ефект: мінімальний A/B тест
Я раджу: Перед впровадженням на production вам потрібно переконатись,
що hybrid + reranking дійсно покращує якість на ваших даних. Мінімальний тест:
- Зберіть 20–30 реальних запитів з відомими правильними відповідями (golden set)
- Прогоніть кожен запит через: (a) чистий vector search, (b) hybrid search, (c) hybrid + reranking
- Порівняйте recall@5 (чи правильна відповідь є у топ-5) для кожного варіанту
- Якщо recall зріс на <5% — проблема, ймовірно, не в retrieval, а в chunking або якості даних
Детально про метрики retrieval — у
Як виміряти якість RAG: метрики, інструменти .
⚠️ Підводні камені
Версії бібліотек.
Qdrant Query API (prefetch + fusion) доступний з версії 1.10+.
Перевірте вашу версію qdrant-client.
ChromaDB RRF API доступний з v0.6+.
Cohere pricing може змінитись.
Станом на березень 2026 — $2/1K запитів для Rerank 3.5. Перевіряйте
актуальний прайс перед впровадженням.
Self-hosted reranker потребує GPU.
BGE-reranker-v2-m3 на CPU дає ~350ms на 50 документів — може не вписатись
у latency budget. На GPU (навіть T4) — ~80ms.
Висновок розділу:
Впровадження hybrid search + reranking — це години, не тижні. Головне —
виміряти ефект на реальних запитах перед deployment на production.
💼 Діагностична матриця: що впроваджувати першим
Я раджу: Порядок впровадження: (1) hybrid search — мінімальний effort, максимальний
ефект, (2) reranking — +100–300ms, але значне покращення precision,
(3) query transformation — тільки якщо перші два кроки недостатні.
Якщо жодне з трьох не допомагає — проблема в chunking або якості даних,
не в retrieval.
Decision Tree: що впроваджувати першим
Ваш RAG не знаходить потрібне?
│
├─ Не знаходить точні терміни / ID / коди?
│ └─ → Додайте BM25 (Hybrid Search)
│ Latency: +0ms (паралельний пошук)
│ ROI: найшвидший
│
├─ Знаходить правильні документи, але не в топ-3?
│ └─ → Додайте Reranking
│ Latency: +100–300ms
│ ROI: високий для precision-critical задач
│
├─ Запити занадто короткі або неоднозначні?
│ └─ → Спробуйте Multi-query або HyDE
│ Latency: +0.5–2s
│ ROI: залежить від типу запитів
│
├─ Велика база, високий шум у результатах?
│ └─ → Reranking + збільшіть top-k Stage 1 до 100
│
└─ Нічого не допомагає?
└─ → Проблема в chunking або якості даних, не в retrieval
Перевірте: chunking strategies, embedding model, дані
Порядок впровадження
-
Hybrid search — мінімальний effort, максимальний ефект.
Якщо ваша Vector DB підтримує hybrid нативно (Qdrant, Weaviate,
Elasticsearch) — це зміна конфігурації, не переписування пайплайну.
-
Reranking — додає 100–300ms, але значно покращує precision.
Почніть з Cohere API (мінімум інфраструктури), потім мігруйте на self-hosted
BGE-v2-m3 якщо latency або вартість стануть проблемою.
-
Query Transformation — тільки якщо 1 і 2 недостатньо.
Кожна техніка додає LLM-виклик і latency. Впроваджуйте вибірково —
не для всіх запитів, а для тих типів, де бачите проблему з recall.
❓ Часті питання (FAQ)
Чи потрібен hybrid search, якщо я використовую BGE-M3 з native sparse?
Так, але реалізація спрощується. BGE-M3 генерує dense і sparse вектори
в одній моделі — вам не потрібен окремий BM25. Але RRF або інший fusion
метод все одно потрібен для об'єднання результатів. У Qdrant це реалізується
тим самим prefetch API.
Скільки коштує Cohere Rerank на 1000 запитів на день?
Станом на березень 2026: Cohere Rerank 3.5 коштує ~$2 за 1000 запитів
(при reranking 50 документів на запит). 1000 запитів/день = ~$60/місяць.
Для порівняння: self-hosted BGE-v2-m3 на T4 GPU (~$150–300/місяць) стає
вигідніше при > 2500–5000 запитів/день.
Чи можна використовувати reranking без hybrid search?
Так. Reranking працює з будь-яким retriever — чистим vector search, BM25,
або hybrid. Але комбінація hybrid + reranking дає найкращий результат, бо
hybrid забезпечує ширший і різноманітніший набір кандидатів для reranker'а.
Як hybrid search впливає на latency?
Мінімально. BM25 і vector search виконуються паралельно, а RRF fusion
додає лише обчислення рангів — мікросекунди. Основний додатковий час —
reranking (100–300ms), не hybrid search як такий.
Чим RRF відрізняється від weighted sum?
RRF працює з рангами (позиціями), weighted sum — зі скорами (числовими
оцінками). RRF не потребує нормалізації і стабільніший при різних розподілах
скорів. Weighted sum дає більше контролю, але вимагає калібрування шкал —
що не завжди можливо.
✅ Висновки
- 🔹 Vector search сам по собі не достатній: розмиває точні терміни та короткі запити; BM25 закриває ці пробіли.
- 🔹 Hybrid search (BM25 + dense + RRF): перший і простий крок для покращення якості.
- 🔹 Reranking (cross-encoder): другий етап; +100–300ms, але +8–25% precision, вирішує "lost in the middle".
- 🔹 Query transformation: для специфічних запитів, додає latency через LLM-виклик.
- 🔹 Порядок впровадження: hybrid → reranking → query transform; якщо не допомагає — проблема в chunking або даних.
- 🔹 Тестуйте на реальних запитах: 20–30 запитів з golden set, recall@5 до і після — мінімум перед production.
Моя головна думка:
Hybrid search і reranking — це не заміна хорошої embedding-моделі або
правильного chunking. Це наступний шар оптимізації для RAG-системи, яка
вже працює, але потребує вищої точності. Впроваджуйте поступово, вимірюйте
кожен крок, і не вірте маркетинговим цифрам "+48%" — цільтесь у реалістичні
+15–25%.
Якщо хочете глибше зануритись в архітектуру retrieval —
ColBERT, Vector DB Internals (🔴 Advanced, скоро).
Якщо потрібно системно вимірювати якість —
📖 Джерела