Перейти к содержанию
Новое AiManual теперь в MAX Подписаться
Публикация AiManual

Многошаговый семантический поиск в Amazon Bedrock: как AgenticRetrieveStream решает проблему сложных запросов к неструктурированным данным

Разбираем AgenticRetrieveStream для Amazon Bedrock Managed Knowledge Bases: как LLM-планировщик разбивает сложные запросы на подзадачи, итеративно уточняет поис

Коротко

Что будет в материале

  1. 01

    Почему классический Retrieve API не справляется со сложными вопросами

  2. 02

    AgenticRetrieveStream: архитектура с планировщиком на основе фундаментальной модели

  3. 03

    Метрики: как AgenticRetrieveStream повышает recall на сложных датасетах

  4. 04

    Когда использовать AgenticRetrieveStream, а когда - обычный Retrieve: практическое руководство

Почему классический Retrieve API не справляется со сложными вопросами

Классический семантический поиск через Retrieve API в Amazon Bedrock Managed Knowledge Bases работает по простому принципу: получает запрос, векторизует его и возвращает наиболее релевантные чанки из базы знаний. Этот подход отлично показывает себя на фактологических вопросах вроде «какая максимальная длина контекста у Claude 4?» или «как настроить S3-коннектор?». Проблемы начинаются, когда запрос требует сопоставления фактов из разных документов, последовательного рассуждения или агрегации.

Разработчики RAG-систем сталкиваются с этой ситуацией регулярно. Пользователь задаёт вопрос, который подразумевает несколько шагов логического вывода, а поисковая подсистема возвращает набор чанков, релевантных лишь отдельным частям запроса. Модель получает фрагментированную информацию и либо даёт неполный ответ, либо игнорирует часть условий, либо начинает галлюцинировать, пытаясь заполнить пробелы. AgenticRetrieveStream API меняет эту механику, добавляя слой динамического планирования на основе LLM, который разбивает сложный запрос на подзадачи, итеративно ищет по каждой и синтезирует целостный ответ.

Примеры запросов, которые ломают одношаговый поиск

Рассмотрим три типичных сценария, где Retrieve API даёт сбой.

Многошаговый запрос. «Найди в логах продакшена причину ошибки OutOfMemoryError за последние сутки, определи, связана ли она с известным багом в версии 2.4.1, и предложи способ обхода». Одношаговый поиск вернёт чанки, содержащие упоминания OutOfMemoryError, отдельно - чанки про баг 2.4.1, отдельно - документацию по обходным путям. Но он не свяжет их в цепочку: ошибка → конкретный баг → решение. Модель, получившая этот набор, должна самостоятельно выстроить логическую связь, не имея гарантий, что все три факта присутствуют в выбранных чанках.

Сравнительный запрос. «Сравни точность и скорость инференса Kimi K3 и GPT-5.6 Sol на задачах суммаризации длинных документов с учётом стоимости». Retrieve API найдёт чанки про Kimi K3, чанки про GPT-5.6 Sol, возможно - чанки про бенчмарки суммаризации. Но он не гарантирует, что метрики будут сопоставимы: одна модель тестировалась на одном датасете, вторая - на другом. Планировщик AgenticRetrieveStream способен сначала найти релевантные бенчмарки для обеих моделей, затем отдельно запросить данные по стоимости, и только потом синтезировать сравнение.

Запрос с агрегацией. «Какие категории товаров чаще всего возвращают клиенты в сегменте электроники, и какие причины возврата преобладают в каждой?» Обычный поиск выдаст разрозненные чанки с отдельными возвратами, но не агрегирует статистику по категориям. Планировщик может сначала запросить все записи о возвратах электроники, затем сгруппировать их по категориям, затем по причинам - последовательно уточняя поиск на основе промежуточных результатов.

Проблема особенно остра для неструктурированных данных: логов, внутренних отчётов, технической документации, статей. В таких источниках факты распределены по разным документам без явных перекрёстных ссылок, и одношаговый поиск принципиально не способен восстановить связи между ними. AgenticRetrieveStream решает эту задачу архитектурно, а не через усложнение промптов или постобработку.

AgenticRetrieveStream: архитектура с планировщиком на основе фундаментальной модели

Ключевое отличие AgenticRetrieveStream от Retrieve API - появление промежуточного слоя между запросом пользователя и поисковым движком. Этот слой реализован как LLM-планировщик, работающий внутри управляемого сервиса Amazon Bedrock. Планировщик получает исходный запрос, анализирует его и формирует план: последовательность подзадач, каждая из которых отправляется в Knowledge Base как отдельный поисковый запрос. Результаты предыдущих шагов влияют на формулировку последующих.

Архитектура состоит из трёх компонентов. Первый - планировщик на базе фундаментальной модели, который декомпозирует запрос. Второй - итеративный цикл поиска, где каждая подзадача выполняется через тот же Retrieve API к Managed Knowledge Base, но с контекстом, накопленным на предыдущих шагах. Третий - синтезатор, который собирает все найденные чанки и генерирует финальный ответ со ссылками на источники. В отличие от ручного вызова Retrieve в цикле, планировщик динамически адаптирует стратегию: он может изменить направление поиска, если промежуточные результаты указывают на пробел в данных, или добавить уточняющий шаг, если информация противоречива.

Для работы AgenticRetrieveStream требуется настроенная Managed Knowledge Base - сервис выступает источником данных и поисковым движком. Если вы ещё не работали с этим инструментом, в статье «Полное руководство по Amazon Bedrock Managed Knowledge Base» разобрана пошаговая настройка с примерами кода на Python и сравнение прямого и агентного поиска по метрикам.

Как планировщик разбивает запрос на подзадачи

Возьмём запрос: «Какие методы оптимизации инференса лучше всего подходят для LLM на GPU с ограниченной памятью?». Планировщик анализирует его и выделяет три семантических компонента: методы оптимизации инференса, ограничение по GPU-памяти, критерий сравнения «лучше всего». Затем он формирует план из нескольких шагов.

Шаг 1: найти все известные методы оптимизации инференса для LLM. Шаг 2: для каждого метода определить требования к GPU-памяти и поведение в условиях её дефицита. Шаг 3: сравнить методы по применимости в условиях ограниченной памяти. Каждый шаг может использовать разные параметры поиска: на первом шаге - широкий запрос с высоким topK, на втором - более узкий, сфокусированный на конкретных техниках, найденных на первом шаге. Планировщик также может определить, что для третьего шага нужны числовые метрики (потребление VRAM, пропускная способность), и сформулирует запрос с акцентом на бенчмарки.

Этот процесс не жёстко задан заранее. Если на втором шаге выясняется, что метод квантования имеет несколько вариантов (GPTQ, AWQ, GGUF), планировщик может добавить четвёртый шаг для сравнения этих вариантов между собой. Динамическая адаптация плана - ключевое преимущество перед статическим многошаговым Retrieval, где последовательность запросов фиксирована в коде.

Итеративное уточнение и синтез ответа

После выполнения каждого поискового шага планировщик оценивает полученные чанки. Если результаты неполны или противоречивы, он инициирует уточняющий запрос. Например, первый поиск по методам оптимизации может вернуть общие описания без привязки к GPU-памяти. Планировщик фиксирует этот пробел и формулирует следующий запрос более конкретно: «требования к VRAM для квантования, pruning и distillation при инференсе LLM».

Когда все шаги выполнены, накопленные чанки передаются в LLM для синтеза финального ответа. Модель получает не разрозненный набор документов, а структурированную подборку, где каждый фрагмент соответствует определённому аспекту исходного вопроса. Ответ формируется с цитированием источников - каждый факт можно проследить до конкретного чанка в Knowledge Base. Это снижает вероятность галлюцинаций: модели не нужно «додумывать» связи между фактами, они уже установлены на этапе планирования.

В контексте RAG-систем проблема галлюцинаций часто возникает не на этапе генерации, а раньше - при парсинге, обработке запроса и поиске. Статья «Четыре кита Context Engineering: почему RAG галлюцинирует, даже если промпт идеален» детально разбирает эти этапы и предлагает воспроизводимые решения для каждого из них.

Метрики: как AgenticRetrieveStream повышает recall на сложных датасетах

Эффективность AgenticRetrieveStream измерялась на датасете MuSiQue (Multi-hop Sequential Question Answering), который содержит вопросы, требующие последовательного соединения фактов из разных документов. Каждый вопрос в MuSiQue предполагает от двух до четырёх шагов логического вывода, что делает его эталонным бенчмарком для оценки многошагового поиска.

Результаты показывают значимый прирост recall по сравнению с одношаговым Retrieve API. Для 2-шаговых вопросов улучшение составило порядка +15%, для 3-шаговых - около +25%, а для 4-шаговых вопросов recall вырос до +37%. Это означает, что на самых сложных запросах, требующих соединения четырёх фактов из разных источников, AgenticRetrieveStream находит релевантные чанки более чем на треть чаще, чем классический подход.

Прирост достигается за счёт того, что каждый последующий поисковый шаг использует контекст, полученный на предыдущих. Одношаговый Retrieve вынужден угадывать, какие чанки понадобятся для полного ответа, по одному векторному представлению сложного запроса. Планировщик AgenticRetrieveStream распределяет эту задачу по шагам: сначала находит базовые факты, затем уточняет их, затем ищет связи. Каждый шаг проще для поискового движка, потому что запросы становятся более конкретными.

Сравнение recall на разных типах запросов

Прирост recall неравномерен по типам запросов. На простых фактологических вопросах («когда вышла модель X?») разница между Retrieve и AgenticRetrieveStream минимальна - в пределах 2-3%. Планировщик в таких случаях выполняет один шаг, и overhead на планирование не даёт заметного выигрыша. На запросах средней сложности, требующих двух логических переходов, прирост составляет 10-18%. Максимальный эффект - на многошаговых сравнительных и аналитических запросах, где требуется агрегация данных из трёх и более документов.

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

Платой за улучшение метрик становится увеличенная latency. Каждый дополнительный шаг добавляет время на вызов LLM для планирования и на поисковый запрос. Для 4-шагового вопроса общее время ответа может быть в 3-5 раз выше, чем у одношагового Retrieve. Это компромисс, который нужно учитывать при проектировании системы.

Когда использовать AgenticRetrieveStream, а когда - обычный Retrieve: практическое руководство

Выбор между двумя API сводится к трём критериям: сложность запросов, требования к latency и бюджет. Обычный Retrieve API остаётся оптимальным выбором для сценариев, где запросы фактологические и самодостаточные: поиск по документации, ответы на конкретные вопросы о параметрах или настройках, извлечение определений. Он быстрее и дешевле, потому что не тратит токены на планирование.

AgenticRetrieveStream нужен, когда запросы пользователей систематически требуют сопоставления информации из разных источников. Признаки таких запросов: сравнительные формулировки («чем отличается X от Y?»), вопросы с условиями («какой метод лучше всего подходит для сценария Z?»), аналитические задачи («почему произошла ошибка и как её исправить?»), запросы с агрегацией («какие тренды видны в данных за последний квартал?»).

Практическая рекомендация: начните с Retrieve API для всего спектра запросов и соберите метрики. Если пользователи жалуются на неполные ответы или вы видите, что модель часто переспрашивает и уточняет - это сигнал к внедрению AgenticRetrieveStream. Внедряйте не глобально, а для конкретных категорий запросов, где проблема подтверждена метриками. Такой подход описан в кейсе «Строим AI-агента с нуля: архитектура, метрики и код на Python», где разбирается чек-лист для выбора между своей разработкой и готовым решением на основе цифр latency, cost и reliability.

Сравнение по ключевым параметрам:

КритерийRetrieve APIAgenticRetrieveStream
Сложность запросаПростые, фактологическиеСравнительные, многошаговые, аналитические
LatencyНизкая (один поисковый вызов)Выше в 2-5 раз (зависит от числа шагов)
СтоимостьТолько поисковые вызовыПоисковые вызовы + токены планировщика
Recall на сложных запросахБазовыйДо +37% на 4-шаговых вопросах
Требования к настройкеМинимальныеКонфигурация max_steps, бюджета, таймаутов

Настройка, бюджетирование и observability стрима

AgenticRetrieveStream конфигурируется через параметры, управляющие глубиной поиска и затратами. Основные настройки: максимальное количество шагов (max_steps), ограничение на число возвращаемых чанков за шаг, таймаут на всю операцию, модель для планировщика. Выбор модели планировщика напрямую влияет на стоимость и качество плана: Claude Haiku дешевле и быстрее, но может хуже справляться со сложной декомпозицией; Claude Sonnet даёт более точные планы ценой большего потребления токенов.

Для мониторинга используются стандартные инструменты AWS: CloudWatch собирает метрики по длительности вызовов, количеству шагов и объёму возвращённых данных. Логи стрима содержат трассировку каждого шага - какой подзапрос был сформулирован, сколько чанков возвращено, какая часть бюджета израсходована. Это позволяет отлаживать поведение планировщика и выявлять запросы, на которых он принимает неоптимальные решения.

Пример кода: вызов AgenticRetrieveStream и обработка ответа

import boto3
import json

# Создание клиента Bedrock Agent Runtime
client = boto3.client('bedrock-agent-runtime', region_name='us-east-1')

# Идентификатор базы знаний (из консоли Bedrock)
knowledge_base_id = 'YOUR_KB_ID'

# Сложный многошаговый запрос
query = 'Какие методы оптимизации инференса лучше всего подходят для LLM на GPU с ограниченной памятью?'

# Вызов AgenticRetrieveStream
response = client.agentic_retrieve_stream(
    knowledgeBaseId=knowledge_base_id,
    retrievalQuery={
        'text': query
    },
    retrievalConfiguration={
        'retrievalMode': 'AGENTIC',  # Включает режим с планировщиком
        'retrievalStrategy': {
            'type': 'DYNAMIC'  # Динамическое планирование шагов
        },
        'orchestrationConfiguration': {
            'queryDecompositionConfiguration': {
                'maxSteps': 5  # Максимум 5 поисковых шагов
            },
            'inferenceConfig': {
                'textInferenceConfig': {
                    'maxTokens': 4096  # Бюджет токенов на синтез ответа
                }
            }
        }
    }
)

# Обработка стрима событий
final_answer = ''
citations = []

for event in response.get('responseStream', []):
    # Событие с чанком финального ответа
    if 'output' in event:
        final_answer += event['output'].get('text', '')
    
    # Событие с информацией о цитировании
    if 'generatedResponsePart' in event:
        part = event['generatedResponsePart']
        if 'textResponsePart' in part:
            citations.append({
                'text': part['textResponsePart'].get('text', ''),
                'span': part['textResponsePart'].get('span', {}),
                'references': part['textResponsePart'].get('references', [])
            })
    
    # Событие с трассировкой шага планировщика
    if 'trace' in event:
        trace = event['trace']
        if 'orchestrationTrace' in trace:
            orchestration = trace['orchestrationTrace']
            print(f"Шаг планировщика: {orchestration.get('stepType', 'UNKNOWN')}")
            if 'queryDecomposition' in orchestration:
                print(f"  Подзапрос: {orchestration['queryDecomposition'].get('subQuery', 'N/A')}")

print(f"\nФинальный ответ: {final_answer}")
print(f"Найдено цитирований: {len(citations)}")

Код демонстрирует минимальную рабочую конфигурацию: создание клиента, вызов agentic_retrieve_stream с ограничением в 5 шагов и 4096 токенов на синтез, итеративную обработку событий стрима. В реальной системе стоит добавить обработку ошибок, логирование каждого шага для отладки и механизм повторных попыток при таймаутах.

Контроль затрат: как не выйти за бюджет

Многошаговый поиск потребляет больше ресурсов, чем одношаговый, за счёт двух факторов: каждый дополнительный шаг - это отдельный поисковый вызов к Knowledge Base, а планировщик расходует токены на генерацию подзапросов и оценку промежуточных результатов. Стратегия контроля затрат строится на трёх уровнях.

Первый - ограничение глубины. Параметр max_steps жёстко ограничивает максимальное число поисковых итераций. Для большинства практических задач 3-5 шагов достаточно; значения выше 7 редко дают дополнительный прирост качества, но линейно увеличивают стоимость. Второй - выбор модели планировщика. Используйте Claude Haiku для запросов средней сложности и переключайтесь на Sonnet только для действительно сложных аналитических задач. Разница в стоимости токенов между Haiku и Sonnet может быть пятикратной. Третий - кэширование. Если пользователи задают похожие вопросы, результаты промежуточных шагов можно кэшировать и переиспользовать, но эта логика ложится на сторону приложения - сам AgenticRetrieveStream кэш не предоставляет.

Пример расчёта стоимости для типового 3-шагового запроса: 3 поисковых вызова к Knowledge Base (~$0.001-0.003 за вызов в зависимости от объёма индекса), плюс токены планировщика (~2000 входных и 500 выходных токенов на шаг для Haiku - это порядка $0.002-0.005 за весь запрос). Итого около $0.01-0.02 на один сложный запрос. Для сравнения, одношаговый Retrieve API обошёлся бы в $0.001-0.003. Разница на порядок, но она оправдана, если качество ответа критично для бизнес-задачи.

Ограничения и когда AgenticRetrieveStream может не подойти

AgenticRetrieveStream не универсальное решение. Первое и главное ограничение - latency. Каждый шаг планирования добавляет 200-500 мс на вызов LLM плюс время поискового запроса. Для real-time систем с требованиями ответа до 1-2 секунд (чат-боты, интерактивные ассистенты) многошаговый режим может оказаться неприемлемым. В таких сценариях лучше использовать обычный Retrieve с хорошо проработанной стратегией чанкинга и расширения запроса.

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

Третье - зависимость от качества индексации в Knowledge Base. Если чанки poorly структурированы, содержат неполную информацию или дублируются, даже идеальный план поиска не даст хорошего результата. Проблема не в AgenticRetrieveStream, а в источнике данных, но она обостряется при многошаговом поиске, потому что ошибки на ранних шагах каскадно влияют на последующие.

Четвёртое - стоимость. При большом потоке запросов разница между $0.002 и $0.02 на запрос становится существенной. Перед полным внедрением проведите A/B-тест на репрезентативной выборке: сравните качество ответов и затраты для Retrieve и AgenticRetrieveStream на ваших данных. Методология такого тестирования с конкретными цифрами разбирается в статье «Как Databricks перешёл от Big Data к AI: уроки оценки, открытые веса и выбор обвязки для кодинга», где показано, как правильно сравнивать модели и подходы по метрикам, а не по субъективным ощущениям.

Наконец, AgenticRetrieveStream не решает проблему отсутствия данных. Если в Knowledge Base нет информации, отвечающей на вопрос, никакое количество шагов планирования её не создаст. В таких случаях система должна честно сообщать о невозможности ответа, а не пытаться синтезировать правдоподобный, но ложный вывод. Это особенно важно для regulated-индустрий, где цена ошибки высока - пример такого кейса с анализом причин провала и уроков для внедрения разобран в статье «Побочный продукт ИИ-агента: как инструмент для разработки стал главным помощником аналитиков».

Подписаться на канал