Проблема «слепой» отправки контекста
Стандартный подход к построению RAG-систем (Retrieval-Augmented Generation) предполагает отправку всех K найденных фрагментов (chunk'ов) в LLM за один вызов. Это работает, но создает скрытые издержки. Если пользователь задает простой фактологический вопрос, например, «Какова дата вступления в силу этой политики?», и ответ содержится в первом по релевантности фрагменте, модель все равно обрабатывает остальные K-1 фрагменты. Эти дополнительные токены не несут информационной ценности, но оплачиваются.
На корпусе из 50 000 документов такие «пустые» вызовы превращаются в значительные ежемесячные расходы. Автор статьи предлагает альтернативный режим — Loop Engineering (или последовательную генерацию), где кандидаты подаются по одному, начиная с top-1.
Механика последовательной проверки
В новом подходе система использует типизированный контракт ответа AnswerWithEvidence, который содержит два ключевых булевых поля:
- answer_found: присутствует ли ответ в текущем фрагменте?
- complete_answer_found: является ли ответ полным, а не фрагментарным?
Алгоритм работает так: LLM получает вопрос и первый фрагмент. Если оба флага истинны, цикл прерывается. Если нет — загружается следующий фрагмент. Это позволяет сократить затраты токенов на 80% для вопросов, где ответ находится в top-1 (что составляет около 80% типичного трафика в корпоративных базах знаний).
Когда нужен Batch-режим (отправка всех K)
Последовательный подход не универсален. Для сложных запросов, требующих анализа нескольких источников одновременно, он не подходит. Автор выделяет три сценария, где обязательна отправка всех K фрагментов за один вызов:
| Тип вопроса | Пример | Почему Batch необходим |
|---|---|---|
| Список (Listing) | «Перечислите все исключения в контракте» | Ответ требует сбора данных из всех совпадающих фрагментов. Последовательный режим остановился бы на первом найденном исключении. |
| Сравнение (Comparison) | «Выше ли премия в этом году, чем в прошлом?» | Модели нужно видеть оба значения (текущий и прошлый год) в одном контекстном окне для корректного сравнения. Последовательная обработка разорвет эту связь. |
| Тесный скор (Tight-score) | Релевантность фрагментов различается менее чем на 5% | Ретривер не может надежно определить лучший источник. LLM должен видеть все кандидаты, чтобы самостоятельно выбрать наиболее точный. |
Диспетчеризация на основе парсинга вопроса
Ключевое архитектурное решение — не выбирать между Batch и Sequential глобально для всего пайплайна, а принимать решение для каждого конкретного вопроса. Это достигается на этапе парсинга вопроса (Brick 2), где определяется форма ответа (answer_shape) и структура декомпозиции (decomposition).
Диспетчер (Dispatcher) читает эти метаданные и маршрутизирует запрос:
- Если ожидается простой тип (Amount, Date, Boolean) — используется Sequential (top-1 first).
- Если ожидается список или сравнение — используется Batch (all K at once).
Эта логика универсальна для различных доменов: страхования, юриспруденции, медицины и финансов. Она позволяет оптимизировать стоимость и задержку (latency), не жертвуя качеством ответов на сложных запросах.
Источник: Towards Data Science ↗
