Реалізація Multi-Query RAG для підвищення повноти пошуку
Уявіть: ваша RAG-система на 20% запитів видає нерелевантні відповіді лише через невдале формулювання. Ми, як інженери з понад 5 років досвіду в AI/ML, стикалися з цією проблемою десятки разів. Наприклад, запит «як звільнити співробітника» і «процедура розірвання трудового договору» — одне й те саме, але система бачить різні вектори і втрачає половину релевантних документів. RAG (Retrieval-Augmented Generation) — техніка покращення retrieval, при якій вихідний запит автоматично перефразовується декількома способами, кожен варіант запускається в пошуку, а результати об'єднуються. Це знижує залежність якості відповіді від конкретного формулювання запиту і підвищує повноту вилучення. У нашій практиці це дало приріст recall на 38% при помірному зростанні latency.
Як Multi-Query RAG підвищує повноту вилучення?
Одна й та сама інформація може бути описана різними термінами. Наприклад, у корпоративній базі знань запит «як оформити відпустку» знайде заяви, «процедура отримання щорічної відпустки» — регламент, а «правила надання відпускних днів» — політику HR. Multi-Query об'єднує всі три і отримує більш повний контекст, що критично важливо для бізнес-процесів. Згідно з дослідженням RAG на практиці, приріст повноти вилучення досягає 38%.
Реалізація з LangChain
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Qdrant
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Qdrant.from_existing_collection(
embeddings=embeddings,
collection_name="knowledge_base",
url="http://localhost:6333",
)
retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(search_kwargs={"k": 5}),
llm=llm,
include_original=True,
)
# Використання
docs = retriever.invoke("який порядок погодження великої угоди")
# Всередині LangChain генерує 3 перефразування + оригінал,
# шукає по кожному і дедуплікує результати
Це базовий варіант — ми використовуємо його для швидких прототипів. У продакшені часто потрібен кастомний промпт, адаптований під специфіку клієнта.
Кастомний Multi-Query з контролем промпту
Стандартний промпт LangChain можна замінити спеціалізованим:
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import BaseOutputParser
class LineListOutputParser(BaseOutputParser):
"""Парсить список питань з відповіді LLM"""
def parse(self, text: str) -> list[str]:
lines = text.strip().split("\n")
return [line.strip().lstrip("123456789.-) ") for line in lines if line.strip()]
MULTI_QUERY_PROMPT = PromptTemplate(
input_variables=["question"],
template="""Ти — AI-асистент з пошуку документів. Твоє завдання — згенерувати
5 різних варіантів наступного питання для покращення пошуку у векторній базі.
Правила:
- Використовуй синоніми та альтернативні формулювання
- Один варіант — більш конкретний, один — більш загальний
- Зберігай сенс оригінального питання
- Кожне питання з нового рядка, без нумерації
Оригінальне питання: {question}
Варіанти:"""
)
custom_retriever = MultiQueryRetriever(
retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
llm_chain=MULTI_QUERY_PROMPT | llm | LineListOutputParser(),
include_original=True,
)
Наш досвід показує, що кастомний промпт дає на 5–10% кращий recall, оскільки адаптований під предметну область клієнта.
Parallel Multi-Query з дедуплікацією
Для зменшення latency запускаємо пошук по всіх варіантах паралельно:
import asyncio
from openai import AsyncOpenAI
async def multi_query_search(
original_query: str,
vectorstore,
n_variants: int = 4,
top_k_per_query: int = 5,
) -> list[str]:
"""Паралельний multi-query retrieval"""
async_client = AsyncOpenAI()
# Генеруємо варіанти запиту
response = await async_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": f"Згенеруй {n_variants} перефразування питання:\n{original_query}\nОдне питання на рядок."
}],
temperature=0.5,
)
variants = response.choices[0].message.content.strip().split("\n")
all_queries = [original_query] + variants[:n_variants]
# Паралельний пошук
search_tasks = [
asyncio.to_thread(vectorstore.similarity_search, q, k=top_k_per_query)
for q in all_queries
]
results_per_query = await asyncio.gather(*search_tasks)
# Дедуплікація по content
seen_texts = set()
unique_docs = []
for docs in results_per_query:
for doc in docs:
text_hash = hash(doc.page_content[:100])
if text_hash not in seen_texts:
seen_texts.add(text_hash)
unique_docs.append(doc)
return unique_docs
Цей підхід дозволяє вкластися в 700–800 мс навіть при 5 варіантах запиту.
З нашої практики: кейс юридичної компанії
Нещодавно ми впровадили Multi-Query RAG для клієнта з юридичної сфери. Датасет: корпоративна база знань (3200 документів). Тестовий набір — 200 запитів з розміченими релевантними документами.
| Конфігурація | Recall@10 | Precision@5 | Latency (avg) |
|---|---|---|---|
| Single query, k=5 | 0.61 | 0.71 | 280мс |
| Single query, k=15 | 0.72 | 0.58 | 310мс |
| Multi-query (4 variants), k=5 | 0.84 | 0.69 | 680мс |
| Multi-query + Reranker | 0.84 | 0.81 | 920мс |
Multi-query піднімає recall з 0.61 до 0.84 (+38%) при помірному зростанні latency (×2.4). Після reranker precision також відновлюється до 0.81.
Порівняння з альтернативами: HyDE (Hypothetical Document Embeddings) у нашому тесті показав recall@10 = 0.71, але вимагав додаткового кроку генерації гіпотетичного документа. Multi-Query виявився простішим у реалізації і дав майже в 1.2 рази кращий recall.
| Метод | Recall@10 | Latency (avg) | Складність реалізації |
|---|---|---|---|
| Single query | 0.61 | 280 мс | Низька |
| HyDE | 0.71 | 450 мс | Середня |
| Multi-Query | 0.84 | 680 мс | Середня |
З таблиці видно, що Multi-Query забезпечує найкращий recall при прийнятному зростанні latency.
Чому Multi-Query ефективніший за HyDE?
HyDE генерує один гіпотетичний документ і шукає по ньому, що дає виграш, але менший, ніж Multi-Query. Причина: кілька варіантів запиту покривають більше семантичних варіацій, ніж один документ. До того ж, Multi-Query простіший у реалізації — не потрібен додатковий крок генерації документа.
Як ми впроваджуємо Multi-Query RAG: покроково
- Аудит поточної RAG-системи та датасету. Аналізуємо структуру запитів і документів.
- Вибір моделі для генерації варіантів (GPT-4o-mini, Claude Haiku, LLaMA 3). Визначаємо кількість варіантів (зазвичай 3-5).
- Кастомізація промпту під предметну область. Тестуємо на репрезентативній вибірці.
- Інтеграція паралельного пошуку та дедуплікації. Оптимізуємо latency.
- A/B-тестування на ваших запитах. Порівнюємо з поточною системою.
- Документація та навчання команди. Передаємо код та інструкції.
Весь цикл займає 1 тиждень. Вартість впровадження — від $2000 до $5000 залежно від складності. Система окупається за 2-3 місяці за рахунок економії часу користувачів: наприклад, для компанії з 500 співробітників економія може становити до $10,000 на рік. За оцінками клієнтів, економія часу на пошук інформації досягає суттєвих сум для великої компанії.
Коли варто впроваджувати Multi-Query, а коли ні?
Multi-Query оптимальний, якщо:
- запити користувачів варіативні та містять синоніми;
- база знань налічує понад 5000 документів;
- latency до 1 секунди допустима.
Він не потрібен, коли:
- вимоги до затримки менше 200 мс;
- користувачі жорстко дотримуються єдиної термінології;
- датасет малий (single query вже дає високий recall).
Що входить у нашу роботу з впровадження
Ми реалізуємо Multi-Query RAG під ключ. Наші інженери мають сертифікати AWS та OpenAI, а ми гарантуємо підвищення recall на 38% або повертаємо кошти. У нашому портфоліо — понад 30 успішних впроваджень RAG для різних галузей.
- Аудит поточної RAG-системи та датасету;
- Підбір моделі для генерації варіантів (GPT-4o-mini, Claude Haiku, LLaMA 3);
- Кастомізація промпту під предметну область;
- Інтеграція паралельного пошуку та дедуплікації;
- A/B-тестування на ваших запитах;
- Документація та навчання команди.
Приклад промпту для генерації варіантів
Ти — AI-асистент з пошуку документів. Згенеруй 5 різних варіантів наступного питання для покращення пошуку у векторній базі.
Правила:
- Використовуй синоніми та альтернативні формулювання
- Один варіант — більш конкретний, один — більш загальний
- Зберігай сенс оригінального питання
- Кожне питання з нового рядка, без нумерації
Оригінальне питання: {question}
Варіанти:
Часті запитання
Що таке Multi-Query RAG? Multi-Query RAG — техніка покращення retrieval, при якій вихідний запит автоматично перефразується декількома способами. Кожен варіант запускається у пошуку, а результати об'єднуються та дедуплікуються. Це знижує залежність якості відповіді від конкретного формулювання запиту та підвищує повноту вилучення.
Коли потрібно використовувати Multi-Query? Multi-Query ефективний, коли запити користувачів варіативні, а база знань містить документи з різною термінологією. Особливо корисний у корпоративних системах (HR, юридичні, технічні бази). Не рекомендується при жорстких обмеженнях по latency (<200 мс) або дуже малому датасеті (<5000 документів).
Який промпт краще для генерації варіантів? Стандартний промпт LangChain дає 3-5 варіантів. Ми рекомендуємо кастомний промпт, адаптований під предметну область: додаємо синоніми, загальні та конкретні формулювання, зберігаючи вихідний зміст. Це дає приріст recall до 10% без збільшення кількості варіантів.
Який приріст recall дає Multi-Query? У нашій практиці Multi-Query з 4 варіантами запиту та k=5 підвищує Recall@10 з 0.61 до 0.84, тобто на 38%. Після додавання reranker precision відновлюється до 0.81. Latency при цьому зростає в 2-3 рази (до 700-900 мс), що прийнятно для більшості бізнес-сценаріїв.
Скільки часу займає впровадження Multi-Query RAG? Базова реалізація з LangChain займає 2-3 дні, підбір промпта та тестування — ще 2-3 дні. Повний цикл (включно з інтеграцією з існуючою системою та A/B-тестуванням) — до 1 тижня. Вартість впровадження — від $2000 до $5000, але в середньому окупається за рахунок зниження часу користувачів на пошук інформації.
Строки та вартість
Орієнтовні строки:
- Реалізація Multi-Query Retriever: 2–3 дні;
- Підбір промпту та кількості варіантів: 2–3 дні;
- Тестування на датасеті: 2–3 дні;
- Разом: 1 тиждень.
Вартість впровадження — від $2000 до $5000. Завдяки прискоренню пошуку інформації система окупається за 2–3 місяці. Для попередньої оцінки вашого сценарію зв'яжіться з нами — ми безкоштовно проаналізуємо ваш датасет і порекомендуємо оптимальну конфігурацію. Замовте впровадження Multi-Query RAG і отримайте приріст recall до 38% вже через тиждень. Отримайте консультацію інженера з впровадження.







