Как вы решаете проблему “я знаю, что ответ есть в документах, но retrieval не находит”?

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

Проблема «знаю, что ответ есть, но retrieval не находит» — одна из самых частых в RAG-системах. Её корень — несоответствие между тем, как пользователь формулирует запрос, и тем, как документы закодированы в векторном пространстве. Решение — системный подход: сначала улучшаем запрос (query rewriting, expansion), затем улучшаем индексацию (чанкинг, метаданные), и только потом переходим к сложным multi-step стратегиям (HyDE, step-back). Query rewriting — самое простое и эффективное первое действие.


1. Термин: Retrieval (поиск) и его ограничения

Retrieval — этап RAG, где система ищет в векторной БД чанки, семантически близкие к запросу пользователя. Проблема возникает, когда семантическая близость не равна релевантности.

Почему это происходит

  • Плохой запрос пользователь использует общие слова, синонимы, или формулирует вопрос иначе, чем написано в документах.
  • Шум в чанках чанк содержит много нерелевантного текста, разбавляющего полезную информацию.
  • Неудачный чанкинг разрыв логической единицы (например, ответ на вопрос разорван между двумя чанками).
  • Несовпадение эмбеддингов модель эмбеддингов не улавливает тонкие связи (например, «как исправить ошибку 404» vs «настройка .htaccess для перенаправления»).

Термин «Семантический разрыв» (semantic gap) — разница между смыслом запроса и смыслом документа в векторном пространстве.


2. Первый шаг: Улучшение запроса (Query-side)

2.1 Query Rewriting (переписывание запроса)

Что это: LLM переписывает исходный запрос пользователя в более чёткую, поисковую форму.

Пример:

  • Исходный запрос: «Почему у меня не работает?»
  • Переписанный: «Причины неработоспособности функции X в версии Y и способы их устранения».

Код (псевдо):

def rewrite_query(user_query: str) -> str:
    prompt = f"""Перепиши запрос пользователя для поиска в базе знаний.
    Сделай его конкретным, добавь ключевые термины.
    Запрос: {user_query}
    Переписанный запрос:"""
    return llm.generate(prompt)

Почему это эффективно LLM понимает контекст и может сформулировать запрос так, как он мог бы быть написан в документации.

2.2 Query Expansion (расширение запроса)

Что это: Добавление к запросу синонимов, связанных терминов, переводов.

Пример:

  • Исходный запрос: «Как настроить SSL?»
  • Расширенный: «Как настроить SSL? (SSL, TLS, сертификат, https, шифрование, Let's Encrypt)»

Методы

МетодОписаниеПлюсыМинусы
LLM-генерацияLLM генерирует синонимыГибко, контекстноДорого, latency
Тезаурус/WordNetСтатический словарьБыстро, дёшевоНе учитывает контекст
Back-translationПеревод на другой язык и обратноДобавляет вариативностьМожет исказить смысл

Важно Query expansion может увеличить шум, если синонимы выбраны неудачно. Нужно тестировать.


3. Второй шаг: Улучшение индексации (Index-side)

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

3.1 Smaller / Smarter Chunking (умный чанкинг)

Проблема Слишком большие чанки разбавляют релевантную информацию; слишком маленькие — теряют контекст.

Решения

  • Semantic chunking разбивать по смысловым границам (абзацы, предложения), а не по фиксированной длине.
  • Overlapping chunks перекрытие чанков (например, 10-20% overlap) — если ответ разорван, он попадёт в соседний чанк.
  • Hierarchical chunking хранить чанки разного размера (small для точного поиска, large для контекста).

3.2 Добавление метаданных (Metadata)

Что это: Добавление к каждому чанку тегов: источник, дата, тип документа, заголовок, ключевые слова.

Как помогает Можно фильтровать поиск по метаданным (например, «только документация по версии 2.0»), что резко сужает пространство поиска.

Пример структуры метаданных

{
  "chunk_id": "123",
  "source": "docs/api_v2.pdf",
  "title": "Настройка аутентификации",
  "tags": ["auth", "security", "v2.0"],
  "date": "2024-01-15"
}

Фильтрация в векторной БД (Pinecone, Qdrant):

results = index.query(
    vector=query_embedding,
    filter={"tags": {"$contains": "auth"}},
    top_k=5
)

4. Третий шаг: Multi-step retrieval (многошаговый поиск)

Если простые методы не работают, используем более сложные стратегии.

4.1 HyDE (Hypothetical Document Embeddings)

Что это: LLM генерирует гипотетический документ, который мог бы быть ответом на запрос. Затем этот документ используется для поиска похожих реальных документов.

Процесс

  1. Запрос → LLM → Гипотетический ответ (документ)
  2. Гипотетический ответ → Эмбеддинг → Поиск в векторной БД
  3. Результаты поиска → LLM → Финальный ответ

Почему работает Гипотетический ответ семантически ближе к реальным документам, чем исходный запрос.

Код (псевдо):

def hyde_retrieval(query: str) -> list[str]:
    hypothetical_doc = llm.generate(f"Напиши гипотетический документ, отвечающий на запрос: {query}")
    embedding = embedder.embed(hypothetical_doc)
    results = vector_db.search(embedding, top_k=5)
    return results

4.2 Step-back Prompting (шаг назад)

Что это: Сначала генерируется более общий запрос (step-back), затем по нему ищутся документы, и только потом — уточняющий поиск.

Пример:

  • Исходный запрос: «Как исправить ошибку E123 в модуле X?»
  • Step-back запрос: «Общие принципы работы модуля X и типичные ошибки»
  • Поиск по step-back запросу → контекст → уточняющий поиск по исходному запросу

Плюсы Находит документы, которые объясняют причину, а не только симптом.


5. Четвёртый шаг: Human-in-the-loop (человек в контуре)

Когда автоматические методы исчерпаны, добавляем возможность ручного вмешательства.

Варианты

  • Пользователь может указать документ вручную кнопка «Прикрепить файл» или выбор из списка.
  • Администратор может добавить синонимы/правила например, «если запрос содержит "ошибка 404", искать по тегу "перенаправление"».
  • Feedback loop если пользователь оценил ответ как нерелевантный, система запоминает запрос и предлагает администратору добавить правило.

Почему это важно В production всегда будут крайние случаи, которые не покрываются автоматикой. Human-in-the-loop — страховка.


6. Диагностика: как понять, что именно не так?

Прежде чем лечить, нужно поставить диагноз. Используйте оффлайн-метрики (см. вопрос 5).

МетрикаЧто показываетЕсли плохо → проблема в
Hit Rate@kЕсть ли хоть один релевантный документ в top-kИндексация, эмбеддинги
MRRНа каком месте первый релевантный документРанжирование, запрос
Recall@kСколько всех релевантных документов нашлосьЧанкинг, coverage

Пример диагностики

  • HR@5 = 0.9, MRR = 0.3 → релевантный документ есть, но он глубоко в выдаче → проблема в запросе или ранжировании.
  • HR@5 = 0.4 → релевантного документа часто нет вообще → проблема в индексации или чанкинге.

7. Сравнение методов: что выбрать первым?

МетодСложностьЭффективностьLatencyКогда использовать
Query RewritingНизкаяВысокаяНизкаяВсегда, как первая линия
Query ExpansionНизкаяСредняяНизкаяЕсли запрос слишком короткий
Smarter ChunkingСредняяВысокаяНулевая (однократно)Если HR низкий
Metadata FilteringСредняяВысокаяНизкаяЕсли есть структурированные данные
HyDEВысокаяВысокаяВысокаяЕсли простые методы не работают
Step-backВысокаяСредняяВысокаяДля сложных, многосоставных вопросов
Human-in-the-loopОчень высокаяМаксимальнаяНулевая (для системы)Как крайняя мера

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

Задача Создать RAG-систему для технической документации (например, документация Flask или FastAPI), где 20% запросов не находят ответа, хотя он есть.

Инструменты Python, LangChain, FAISS (векторная БД), OpenAI API (эмбеддинги + LLM), Streamlit (UI).

Шаги:

  1. Загрузка данных Скачать документацию Flask (HTML/PDF), разбить на чанки (semantic chunking с overlap 15%).
  2. Индексация Создать эмбеддинги (text-embedding-3-small), сохранить в FAISS с метаданными (заголовок, раздел).
  3. Базовый retrieval Простой поиск по косинусной близости.
  4. Добавление query rewriting LLM (GPT-4o-mini) переписывает запрос перед поиском.
  5. Добавление query expansion LLM генерирует 3 синонима к запросу.
  6. Тестирование Собрать 50 запросов, где базовый retrieval не находит ответ. Проверить, сколько из них исправляет rewriting + expansion.
  7. Добавление HyDE Для оставшихся запросов применить HyDE.
  8. Human-in-the-loop Добавить кнопку «Указать документ вручную» в UI.
  9. Оценка Посчитать HR@5, MRR до и после каждого улучшения.

Ожидаемый результат Вы увидите, как каждый метод повышает метрики. Например:


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

ВопросТема
5Оценка качества retrieval (метрики для диагностики)
3Стратегии chunking (как улучшить индексацию)
7Уменьшение latency (как не замедлить систему при multi-step)
10Self-RAG (альтернативный подход к улучшению retrieval)
15Обработка запросов без ответа (смежная проблема)
20Метаданные и фильтрация (как улучшить индексацию)

Навигация