中文翻译暂不可用,显示俄语原文。

Как вы делаете query rewriting и query expansion в RAG?

Краткий тезис

Query rewriting и query expansion — техники предобработки пользовательского запроса перед этапом retrieval в RAG. Rewriting переформулирует запрос для устранения неоднозначности и приведения к стилю документов, expansion добавляет синонимы, связанные термины или варианты запроса. Обе техники повышают recall (полноту поиска) и качество retrieval, особенно для коротких, разговорных или нечётких запросов. В современных RAG-системах эти операции часто выполняются с помощью LLM или специализированных моделей.


1. Термины: Query Rewriting и Query Expansion

Query rewriting — изменение формулировки запроса без изменения его смысла. Цель — сделать запрос более подходящим для поиска в векторной БД: убрать местоимения, добавить контекст, исправить грамматику, перевести на формальный язык.

Query expansion — добавление к исходному запросу дополнительных терминов (синонимов, гипонимов, связанных понятий). Цель — увеличить вероятность совпадения с релевантными документами, даже если в них используются другие слова.

ХарактеристикаQuery RewritingQuery Expansion
СутьПереформулировкаДополнение
Длина запросаМожет уменьшиться или остаться той жеУвеличивается
Влияние на precisionМожет повысить (точнее соответствует документам)Может снизить (шум от лишних терминов)
Влияние на recallПовышает (лучше покрывает смысл)Повышает (больше совпадений)
Типичный инструментLLM (zero-shot/few-shot)LLM, тезаурус, PRF

2. Зачем нужны эти техники в RAG?

Пользовательские запросы в реальных системах часто:

  • Короткие («погода» — что именно? где? когда?)
  • Неоднозначные («яблоко» — фрукт или компания?)
  • Разговорные («а что там с тем проектом?» — без контекста)
  • Содержат опечатки («нейронка» вместо «нейронная сеть»)
  • Не совпадают по лексике с документами (пользователь говорит «автомобиль», а в документах «машина»)

Без обработки запроса retrieval может пропустить релевантные чанки, что приведёт к плохому ответу LLM. Rewriting и expansion — дешёвый способ улучшить recall без изменения индекса или эмбеддингов.


3. Query Rewriting: подходы

3.1 LLM-based rewriting (наиболее распространённый)

Используется LLM (часто та же, что и для генерации ответа, или более лёгкая) для переформулировки запроса. Пример промпта:

Перепиши запрос пользователя так, чтобы он был более конкретным и подходил для поиска по технической документации. Если запрос неоднозначен, уточни его, используя контекст диалога.

Пользователь: {query}
Переписанный запрос:

Zero-shot — без примеров. Few-shot — с 2-3 примерами в промпте.

3.2 Rule-based rewriting

Простые правила: удаление стоп-слов, исправление опечаток (через словарь или Levenshtein), замена местоимений на полные формы (если есть история диалога). Менее гибко, но быстро и без затрат на LLM.

3.3 Multi-step rewriting (HyDE, Rewrite-Retrieve-Read)

  • HyDE (Hypothetical Document Embeddings): LLM генерирует гипотетический документ-ответ на запрос, затем этот документ используется как запрос для поиска. Фактически rewriting в виде целого документа.
  • Rewrite-Retrieve-Read: сначала переписать запрос, потом найти документы, потом прочитать и ответить. Популярная архитектура из статьи «Rewrite-Retrieve-Read» (2023).

4. Query Expansion: методы

4.1 Synonym expansion (синонимическое расширение)

Использование тезаурусов (WordNet, ConceptNet) или списков синонимов для добавления эквивалентных терминов. Пример: запрос «нейронная сеть» → «нейронная сеть, искусственная нейронная сеть, deep learning, neural network».

4.2 Embedding-based expansion

Поиск в векторном пространстве терминов, близких к эмбеддингу запроса. Можно использовать предобученные word embeddings (Word2Vec, FastText) или эмбеддинги из той же модели, что и для документов. Добавляются top-k ближайших слов.

4.3 LLM-generated expansion

LLM генерирует варианты запроса или дополнительные ключевые слова. Промпт:

Сгенерируй 5 вариантов запроса, которые передают тот же смысл, но используют другие слова. Исходный запрос: {query}

Полученные варианты объединяются с исходным запросом (например, через OR в булевом поиске или как отдельные запросы с агрегацией результатов).

4.4 Pseudo-relevance feedback (PRF)

Классический метод информационного поиска:

  1. Выполнить поиск по исходному запросу.
  2. Взять top-k документов (предположительно релевантных).
  3. Извлечь из них наиболее значимые термины (TF-IDF, BM25).
  4. Добавить эти термины к запросу.

В RAG PRF может быть реализован с помощью LLM: после первого раунда retrieval LLM выделяет ключевые понятия из найденных чанков и добавляет их в запрос для второго раунда.


5. Сравнение Rewriting vs Expansion

КритерийRewritingExpansion
ЦельУточнить смыслРасширить покрытие
РискПотеря исходного намеренияЗашумление запроса
Сложность реализацииСредняя (промптинг)Низкая-средняя
Влияние на latency+1 LLM вызов+0..+1 LLM вызов
Типичное улучшение recall+5-15%+10-25%
Типичное влияние на precision+5-10%-5-10% (возможно снижение)

На практике часто комбинируют: сначала rewriting, затем expansion к переписанному запросу.


6. Практическая реализация: пример кода (Python + LangChain)

from langchain_community.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

# Инициализация LLM (можно заменить на локальную модель)
llm = OpenAI(model="gpt-3.5-turbo-instruct", temperature=0)

# 1. Query Rewriting
rewrite_prompt = PromptTemplate(
    input_variables=["query"],
    template="Перепиши запрос для поиска по документации. Сделай его конкретным и формальным.\nЗапрос: {query}\nПереписанный запрос:"
)
rewrite_chain = LLMChain(llm=llm, prompt=rewrite_prompt)

# 2. Query Expansion
expand_prompt = PromptTemplate(
    input_variables=["query"],
    template="Сгенерируй 3 дополнительных варианта этого запроса, используя синонимы и близкие термины.\nИсходный запрос: {query}\nВарианты (каждый с новой строки):"
)
expand_chain = LLMChain(llm=llm, prompt=expand_prompt)

def process_query(user_query: str) -> str:
    # Шаг 1: переписываем
    rewritten = rewrite_chain.run(user_query).strip()
    # Шаг 2: расширяем
    expansions = expand_chain.run(rewritten).strip().split('\n')
    # Объединяем: исходный переписанный + варианты
    all_queries = [rewritten] + expansions
    # Для векторного поиска можно выполнить каждый запрос отдельно и объединить результаты
    # Или склеить через OR для BM25
    final_query = " OR ".join(all_queries)
    return final_query

# Пример
user_input = "расскажи про нейронки"
processed = process_query(user_input)
print(processed)
# Вывод: "расскажи про нейронные сети OR нейронные сети OR глубокое обучение OR искусственные нейронные сети"

7. Оценка эффективности

Для оценки влияния rewriting/expansion на RAG используют:

Пример результатов (гипотетические):

КонфигурацияRecall@5MRRFaithfulness
Без обработки0.650.720.80
Только rewriting0.720.780.82
Только expansion0.780.750.79
Rewriting + expansion0.820.800.81

Expansion может снизить faithfulness из-за шума, поэтому важно тестировать.


8. Продвинутые техники: Agentic Rewriting

В контексте Agentic RAG (вопросы 371-380) rewriting может быть итеративным:

  • Агент выполняет поиск, получает результаты, анализирует их (например, через LLM).
  • Если результаты нерелевантны, агент переписывает запрос с учётом полученной информации и делает второй поиск.
  • Цикл повторяется до достижения порога уверенности или лимита шагов.

Пример: пользователь спрашивает «последние новости про ИИ». Агент сначала ищет «последние новости про ИИ», получает общие статьи, затем уточняет «новости про ИИ за март 2025» и т.д.


9. Риски и ограничения

  • Over-expansion: слишком много добавленных терминов размывают запрос, precision падает.
  • Увеличение latency: каждый LLM-вызов добавляет 0.5-2 секунды. Для real-time систем критично.
  • Зависимость от качества LLM: если LLM плохо переписывает, можно ухудшить retrieval.
  • Потеря контекста: при rewriting без учёта истории диалога можно потерять важные детали.
  • Стоимость: частые вызовы LLM увеличивают затраты (токены).

10. Когда использовать, а когда нет?

СитуацияРекомендация
Короткие запросы (1-3 слова)Обязательно rewriting + expansion
Длинные, хорошо сформулированные запросыМожно без обработки или только лёгкое expansion
Разговорный стиль (чат-бот)Rewriting обязателен
Высокие требования к latencyИспользовать лёгкие модели (например, DistilBERT) или rule-based
Ограниченный бюджет на LLMИспользовать PRF или synonym expansion без LLM
Тематическая область с узкой терминологиейExpansion через тезаурус домена

Пет-проект для закрепления

Задача: Реализовать модуль query preprocessing для RAG-системы, который поддерживает rewriting через LLM и expansion через WordNet.

Инструменты: Python, NLTK (WordNet), LangChain (или openai), FAISS (для векторного поиска), небольшой датасет документов (например, статьи из Википедии).

Шаги:

  1. Загрузите 100-200 документов по одной теме (например, машинное обучение).
  2. Разбейте на чанки, создайте векторный индекс (FAISS + sentence-transformers).
  3. Напишите функцию rewrite_query(query) с использованием LLM (можно использовать бесплатный API или локальную модель через Ollama).
  4. Напишите функцию expand_query(query) через WordNet: для каждого существительного найдите синонимы и добавьте их.
  5. Объедините: processed_query = expand_query(rewrite_query(query)).
  6. Сравните recall@5 для 10 тестовых запросов с обработкой и без.
  7. Визуализируйте результаты (таблица/график).

Ожидаемый результат: Вы увидите, что recall повышается на 10-30% для коротких запросов, но может незначительно снизиться precision. Пет-проект демонстрирует trade-off и практическую пользу техник.


Связь с другими вопросами

ВопросТема
5Оценка качества retrieval в RAG
7Уменьшение latency RAG-системы
9Обновление документов в RAG
10Self-RAG и его применение
15Стратегии chunking
20HyDE (гипотетические документы)

Навигация