Игорь Градов
Игорь Градов
6 мин
ai

Contextual Retrieval для RAG нейросети: контекст чанков снижает ошибки поиска в разы

Anthropic качество генерации контекста у Haiku и Sonnet отличается минимально для этой задачи.

Contextual Retrieval для RAG нейросети: контекст чанков снижает ошибки поиска в разы

Для русскоязычных корпусов можно использовать тот же промпт, переведённый на русский, или оставить английский — Haiku хорошо работает с обоими вариантами. Но если корпус на русском, русскоязычный промпт даёт чуть более релевантные описания.

Prompt Caching: как не разориться

Главная экономическая проблема Contextual Retrieval — каждый чанк требует вызова LLM с полным документом в контексте. Если документ на 100 страниц разбивается на 200 чанков, модель получает 200 раз один и тот же документ.

Без кеширования это означает: 200 вызовов × ~50K токенов документа = 10M входных токенов на один документ. При стоимости Claude Haiku ~$0.25 за 1M входных токенов это $2.50 за один документ. Для корпуса из 1000 документов — $2500 только на генерацию контекстов.

С Prompt Caching (доступен у Anthropic, OpenAI и Google) документ кешируется после первого вызова, и последующие вызовы для чанков того же документа используют кеш. Стоимость кешированных токенов в ~10 раз ниже. Итого вместо $2500 получается ~$300–400 за тот же корпус.

def generate_contexts_for_document(document: str, chunks: list[str], llm_client) -> list[str]:
    contexts = []
    for i, chunk in enumerate(chunks):
        messages = [
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": f"<document>\n{document}\n</document>",
                        "cache_control": {"type": "ephemeral"}
                    },
                    {
                        "type": "text",
                        "text": f"""Here is the chunk we want to situate within the whole document:
<chunk>
{chunk}
</chunk>

Please give a short succinct context (50-100 tokens) to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else."""
                    }
                ]
            }
        ]

        response = llm_client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=200,
            messages=messages
        )
        contexts.append(response.content[0].text.strip())
    return contexts

Обратите внимание на cache_control: {"type": "ephemeral"} на блоке с документом. Это говорит API кешировать этот блок между вызовами. Все последующие чанки того же документа получат документ из кеша.

Архитектура полного пайплайна

Полный пайплайн Contextual Retrieval выглядит так:

Этап индексации:

  1. Разбить документ на чанки (256–512 токенов, с overlap 50–100 токенов).
  2. Для каждого чанка сгенерировать контекстный префикс через LLM.
  3. Склеить префикс + чанк → обогащённый чанк.
  4. Прогнать обогащённый чанк через embedding-модель → вектор в базу.
  5. Прогнать обогащённый чанк через BM25-токенизатор → в BM25-индекс.

Этап поиска:

  1. Получить запрос пользователя.
  2. Параллельно: embedding-поиск (top-K) + BM25-поиск (top-K).
  3. Объединить результаты (reciprocal rank fusion или другой метод).
  4. Прогнать объединённый список через reranking-модель.
  5. Взять top-N после reranking → финальный контекст для LLM.
Документ → Chunking → [Chunk₁, Chunk₂, ..., Chunkₙ]
                                    ↓
                        LLM генерирует контекст
                                    ↓
                     [Context₁+Chunk₁, Context₂+Chunk₂, ...]
                            ↓                    ↓
                    Embedding Model           BM25 Index
                            ↓                    ↓
                     Vector Store           BM25 Store

Запрос → Embedding → Top-K vectors    → ┐
      → BM25 query → Top-K BM25       → ├→ Fusion → Reranker → Top-N → LLM

Reranking: зачем и какой

Reranking — это второй этап поиска, где специализированная модель пересортировывает уже найденные результаты. В отличие от embedding-поиска, reranker видит запрос и документ одновременно (cross-encoder), что даёт более точное ранжирование, но медленнее.

В контексте Contextual Retrieval reranking работает поверх уже обогащённых чанков. Reranker видит контекстный префикс вместе с содержимым чанка и может использовать оба для ранжирования.

Популярные варианты rerankers:

  • Cohere Rerank — облачный API, хорошо работает с русскоязычными текстами.
  • BGE Reranker — открытая модель, можно запускать локально. Для русского языка есть мультиязычные варианты.
  • LLM-based reranking — использование самой LLM для пересортировки (дорого, но максимально точно).

Добавление reranking поверх Contextual Embeddings + BM25 дало в бенчмарках Anthropic снижение failure rate с 2.9% до 1.9%.

import cohere

co = cohere.ClientV2("your-api-key")

def rerank_results(query: str, documents: list[str], top_n: int = 5) -> list:
    response = co.rerank(
        model="rerank-v3.5",
        query=query,
        documents=documents,
        top_n=top_n
    )
    return response.results

Где Contextual Retrieval ломается

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

Очень короткие документы. Если документ целиком помещается в один чанк, контекст не нужен — он уже весь там. На корпусах из FAQ, однострочных записей, коротких заметок эффект нулевой.

Очень однородные документы. Если документы настолько похожи, что даже с контекстом чанки неразличимы (например, ежедневные отчёты с одинаковой структурой, отличающиеся только числами), контекст не решает проблему. Здесь нужны metadata filters: фильтрация по дате, автору, версии до поиска.

Документы без чёткой структуры. Если документ — поток сознания без разделов, тем и логических блоков, LLM генерирует бесполезные контексты вроде «этот чанк из середины документа» или «продолжение предыдущей мысли». В таких случаях нужна предварительная сегментация на тематические блоки.

Ошибки LLM при генерации контекста. LLM может галлюцинировать в контексте: приписать чанку неправильную тему, перепутать раздел, добавить несуществующие детали. Это особенно опасно, потому что ошибочный контекст будет систематически уводить поиск не туда. Для критических систем нужна выборочная верификация генерируемых контекстов.

Мультимодальные документы. Таблицы, графики, формулы — контексты для них генерируются хуже, потому что LLM не всегда правильно интерпретирует структурированные данные в текстовом виде. Для таблиц лучше работает предварительное преобразование в текстовое описание.

Стоимость и latency

Contextual Retrieval добавляет стоимость только на этапе индексации, не на этапе поиска. На этапе поиска всё работает так же, как обычный RAG — embedding-поиск, BM25, reranking.

Стоимость индексации зависит от размера корпуса и выбранной модели:

  • Claude Haiku с кешированием: ~$0.30–0.50 за документ на 100 страниц (200 чанков).
  • GPT-4o-mini: сопоставимая стоимость.
  • Локальная модель (Llama 3, Phi-3): только стоимость GPU-времени, но качество контекстов может быть ниже.

Latency на этапе индексации: ~0.5–1 секунда на чанк при использовании облачных API. 200 чанков = 100–200 секунд на документ. Параллелизация и батчинг могут ускорить в 5–10 раз.

На этапе поиска latency не меняется: embedding-поиск + BM25 + reranking работают с той же скоростью, обогащённые чанки чуть длиннее оригинальных (на 50–100 токенов), но это не влияет на время поиска существенно.

Итого

Contextual Retrieval — это одна из немногих техник в RAG, которая одновременно проста в реализации, не ломает существующий пайплайн и даёт измеримый прирост качества. Суть — добавить LLM-generated контекст к каждому чанку перед индексацией, чтобы embedding и BM25 работали с полной информацией, а не с вырванным из контекста фрагментом.

Антрпопик показала снижение failure rate до 67%, и это воспроизводится на практике. На русскоязычных корпоративных корпусах (финансовые отчёты, юридические документы, техническая документация) эффект как минимум сопоставимый, а в некоторых случаях даже выше из-за бо́льшей однородности корпусов.

Техника стала стандартом не потому, что она модная, а потому, что она решает реальную проблему, которую другие методы (overlap, metadata, semantic chunking) решали лишь частично.

Source name: Habr Source URL: https://habr.com/ru/articles/920834/

Поделиться:TelegramVK
Игорь Градов
Игорь Градов

Основатель dzen.guru. Эксперт по монетизации и продвижению на Дзен. Автор курса «Старт на Дзен 2026».

Комментарии

Читайте также

Генеалогия с ИИ: как построить родословную без зарубежных сервисов и риска потери данных
ai

Генеалогия с ИИ: как построить родословную без зарубежных сервисов и риска потери данных

Нейросети умеют не только генерировать картинки и тексты, но и помогать в кропотливой работе с семейными архивами: генеалогия ИИ превращает из хобби одиночек в…

7 мин
Activation steering без выбросов: PCA вместо среднего делает вектор устойчивым
ai

Activation steering без выбросов: PCA вместо среднего делает вектор устойчивым

Компания X приговорила модель к толерантности, а модель отказалась — знакомая ситуация для всех, кто пытался рулить поведением нейросети через промпт.…

7 мин
AI разработка платформы за 2,5 месяца: двое ускорили открытие магазинов сети в 4 раза
ai

AI разработка платформы за 2,5 месяца: двое ускорили открытие магазинов сети в 4 раза

Почему это важно Два человека за 2,5 месяца собрали платформу, на которую раньше ушли бы годы, и ускорили открытие магазинов торговой сети с 5 до 20 в год,…

5 мин