Реализация Multi-Query RAG для повышения качества извлечения

Когда RAG-система теряет релевантные документы из-за формулировки запроса, мы внедряем Multi-Query RAG: автоматически перефразируем запрос, запускаем параллельный поиск и объединяем результаты. Наша команда реализует это под ключ — от настройки промптов до дедупликации, обеспечивая стабильную работу и последующую поддержку.
Часто задаваемые вопросы

Реализация Multi-Query RAG для повышения качества извлечения

Представьте: ваша RAG-система на 20% запросов выдает нерелевантные ответы только из-за неудачной формулировки. Мы, как инженеры с глубоким опытом в 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 варианта), 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 оказался проще в реализации и дал на 18% лучший 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: пошагово

  1. Аудит текущей RAG-системы и датасета. Анализируем структуру запросов и документов.
  2. Выбор модели для генерации вариантов (GPT-4o-mini, Claude Haiku, LLaMA 3). Определяем число вариантов (обычно 3-5).
  3. Кастомизация промпта под предметную область. Тестируем на репрезентативной выборке.
  4. Интеграция параллельного поиска и дедупликации. Оптимизируем latency.
  5. A/B-тестирование на ваших запросах. Сравниваем с текущей системой.
  6. Документация и обучение команды. Передаём код и инструкции.

Весь цикл занимает 1 неделю. Стоимость рассчитывается индивидуально и окупается за 2-3 месяца за счёт экономии времени пользователей. По оценкам клиентов, экономия времени на поиск информации достигает существенных сумм для крупной компании.

Когда стоит внедрять Multi-Query, а когда нет?

Multi-Query оптимален, если:

  • запросы пользователей вариативны и содержат синонимы;
  • база знаний насчитывает более 5000 документов;
  • latency до 1 секунды допустима.

Он не нужен, когда:

  • требования по задержке менее 200 мс;
  • пользователи жестко следуют единой терминологии;
  • датасет мал (single query уже дает высокий recall).

Что входит в нашу работу по внедрению

Мы реализуем Multi-Query RAG под ключ:

  • Аудит текущей RAG-системы и датасета;
  • Подбор модели для генерации вариантов (GPT-4o-mini, Claude Haiku, LLaMA 3);
  • Кастомизация промпта под предметную область;
  • Интеграция параллельного поиска и дедупликации;
  • A/B-тестирование на ваших запросах;
  • Документация и обучение команды.
Пример промпта для генерации вариантов
Ты — AI-ассистент по поиску документов.
Сгенерируй 5 различных вариантов следующего вопроса для улучшения поиска в векторной базе.
Правила:
- Используй синонимы и альтернативные формулировки
- Один вариант — более конкретный, один — более общий
- Сохраняй смысл оригинального вопроса
- Каждый вопрос с новой строки, без нумерации

Оригинальный вопрос: {question}

Варианты:

Сроки и стоимость

Ориентировочные сроки:

  • Реализация Multi-Query Retriever: 2–3 дня;
  • Подбор промпта и числа вариантов: 2–3 дня;
  • Тестирование на датасете: 2–3 дня;
  • Итого: 1 неделя.

Стоимость рассчитывается индивидуально, но благодаря ускорению поиска информации система окупается за 2–3 месяца. Для предварительной оценки вашего сценария свяжитесь с нами — мы проанализируем ваш датасет и порекомендуем оптимальную конфигурацию. Закажите внедрение Multi-Query RAG и получите прирост recall до 38% уже через неделю. Получите консультацию инженера по внедрению.

Направления AI-разработки

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139