Enterprise RAG Challenge 3: уроки публичных решений

Автоматический перевод

Эта статья была автоматически переведена с оригинальной английской версии.

В Enterprise RAG Challenge 3 (ERC3) агенты выполняли бизнес-задачи через API симулированной компании. Замороженный призовой лидерборд необычно полезен: многие участники опубликовали не только результат, но и архитектуру, набор моделей, стоимость и заметки об ошибках.

Я изучил эти публичные описания, чтобы ответить на более узкий вопрос: какие проектные решения повторялись в сильных работах и какие из них пригодятся за пределами этого бенчмарка?

Статья для инженеров, которые строят агентов, вызывающих корпоративные APIs. Вы увидите пять архитектур из публичных разборов, проблемы, которые каждая решала (права доступа, пагинация, пропущенные ссылки, размер контекста), и порядок, в котором их стоит пробовать в своём агенте.

Что такое Enterprise RAG Challenge?

Enterprise RAG Challenge 3 — это масштабный краудсорсинговый исследовательский проект, который проверяет, как автономные ИИ-агенты справляются со сложными бизнес-задачами. В отличие от статичных бенчмарков, ERC3 работает на Agentic Enterprise Simulation (AGES) — дискретно-событийной симуляции, которая предоставляет реалистичный корпоративный API.

Что проверяет бенчмарк

Через AGES агенты работают внутри вымышленной компании, в которой есть:

  • Профили сотрудников с конкретными навыками и отделами
  • Проекты с назначенными командами и отношениями с клиентами
  • Корпоративная вики с бизнес-правилами и иерархиями прав доступа
  • Учёт времени и финансовые операции

Каждая задача запускает изолированную симуляцию. Вики общая, а операционные записи отличаются от задачи к задаче, поэтому агент не может пройти весь набор, запомнив состояние одной компании.

Читайте оценки как снимок

Сейчас ERC3 показывает и замороженный лидерборд соревнования, и публичный бенчмарк, который продолжал принимать запуски после окончания события. Эти страницы отвечают на разные вопросы. Цифры ниже описывают призовой лидерборд на момент закрытия соревнования, а не более поздние лучшие сессии:

МетрикаСнимок соревнования
Призовые решения38
Набор задач103 бизнес-задачи
Максимальный призовой балл0.718
Закрытие призового зачёта9 декабря 2025, 13:40 CET

На странице живого бенчмарка могут быть более высокие оценки, потому что она включает поздние запуски. Поэтому для утверждений о том, что победило в соревновании, правильный источник — замороженный лидерборд. Ultimate-лидерборд берёт лучший запуск каждого аккаунта без отсечки соревнования, поэтому его оценки несопоставимы с призовыми.

Типы задач

Задачи охватывают несколько областей навыков:

  • Многошаговый ризонинг, например сопоставление навыков сотрудников с назначениями на проекты.
  • Проверка прав доступа, например блокировка несанкционированного изменения зарплаты или доступа к данным.
  • Неоднозначные запросы, включая многоязычные и перефразированные.
  • Строгое соответствие формату ответа, включая обязательные ссылки на сущности в ответах.

Что говорят решения

Публичные разборы не подтверждают однозначный вывод вроде «multi-agent подход лучше одиночного агента». Решение, занявшее четвёртое призовое место, MMzXeM, — это один агент с инструментами, сопоставленными 1:1 с эндпоинтами API, инструментом ask_wiki и системным промптом на 320 токенов. Зато разборы подтверждают четыре более узких наблюдения:

  1. Команды выделяли отдельный компонент, когда он отвечал за одно требование, которое агенты постоянно проваливали: проверку прав, валидацию шагов, выполнение кода или ссылки на сущности. Они не делили систему на произвольные «роли агентов».
  2. Валидация сместилась ближе к необратимым действиям. Несколько систем проверяли права до выполнения, проверяли отдельные шаги или защищали финальный ответ.
  3. Изменениями управляли неудачные трейсы. Победитель превращал неудачные запуски в правки промпта через автоматический цикл; другие команды документировали столь же конкретные исправления инструментов и промптов.
  4. Политика контекста была архитектурным выбором. Команды пробовали дистилляцию, предзагрузку, retrieval и сжатие истории. Их собственные отчёты расходятся в том, помогло ли сжатие, так что универсального рецепта нет.

Пять показательных подходов

Это не пять лучших по рангу. Я выбрал их, потому что их публичные описания показывают пять разных способов построить систему: автоматическая правка промпта, стадии со специалистами, валидация каждого шага, гарды на ответе и изоляция plan-execute.

КомандаКонтекст лидербордаОпубликованный балл
VZS9FLПризовой, 1-е0.718
LcnxuyПризовой, 8-е0.505
NLN7DwПризовой, 2-е0.621
J8GvbiПризовой, 16-е0.437
5qsp7i (key_concept_parallel)Ultimate, 3-е0.670

1. Эволюционный промпт-инжиниринг (команда VZS9FL / @aostrikov)

Самый результативный подход автоматизировал промпт-инжиниринг через цикл самоулучшения.

Версии промпта от v1 до v80 и один оборот цикла: главный агент логирует задачи с ошибками, анализатор предлагает причины, агент версий оставляет часть из них и пишет следующую версиюВерсии промпта от v1 до v80 и один оборот цикла: главный агент логирует задачи с ошибками, анализатор предлагает причины, агент версий оставляет часть из них и пишет следующую версию

Вместо ручной настройки промпта для прода команда построила цикл из трёх агентов, который превращал неудачные трейсы в кандидаты на новую версию.

Пайплайн из трёх агентов:

АгентРоль
Main AgentЗапускает бенчмарк, логирует все действия и ошибки
Analyzer AgentРазбирает задачи с ошибками, формулирует гипотезы о первопричинах
Versioner AgentГенерирует новую версию промпта с учётом выводов

Промпт в проде был 80-й автоматически сгенерированной версией. Команда описывает цикл так: он анализирует задачи с ошибками, предлагает причины и решает, какие предложения учесть. Лидерборд устанавливает итоговый балл и число итераций. Он не показывает, какая часть прироста пришлась на автоматизацию, а какая — на модели, инструменты и накопленную обратную связь от бенчмарка.

Стек: claude-opus-4.5 с Anthropic Python SDK и нативный tool use.


2. Multi-agent последовательный пайплайн (команда Lcnxuy / @andrey_aiweapps)

Это решение построило последовательный воркфлоу, в котором специализированные компоненты отвечали за проверки безопасности, извлечение контекста, выполнение и оформление ссылок на сущности.

Четыре стадии от security gate до инструмента ответа, пять фаз выполнения и два ответа: в одном нет ссылок, в другом ссылки собраны внутри инструмента ответаЧетыре стадии от security gate до инструмента ответа, пять фаз выполнения и два ответа: в одном нет ссылок, в другом ссылки собраны внутри инструмента ответа

Задокументированные компоненты:

  1. Security Gate Agent: проверка перед выполнением, которая валидирует права по правилам вики до запуска основного цикла.
  2. Context Extraction Agent: вытаскивает ключевые правила из системных промптов длиннее 500 строк и предзагружает данные о пользователе, проекте и клиенте.
  3. Execution Agent: планирование в стиле ReAct с 5 внутренними фазами (Identity → Threat Detection → Info Gathering → Access Validation → Execution).
  4. LinkGeneratorAgent: встроен в инструмент ответа, разбирает контекст, чтобы добавить обязательные ссылки на сущности.

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

Стек: фреймворки atomic-agents и instructor с gpt-5.1-codex-max, gpt-4.1 и claude-sonnet-4.5.


3. Schema-guided reasoning с валидацией шагов (команда NLN7Dw / Ilia Ris)

Schema-guided reasoning (SGR) заставляет модель на каждом шаге заполнять фиксированную схему вывода, например ризонинг, план и следующий tool call, чтобы программа могла прочитать и проверить каждое поле. Статья про SGR в этом блоге показывает, как навязать такую схему с помощью vLLM. Эта команда совместила SGR с быстрым инференсом и валидатором на каждом предложенном шаге. Такая схема удешевляет исправления: отклонить ошибочный шаг до того, как он станет tool call, и попросить основной поток переделать его с учётом комментариев валидатора.

Модель читает план, записи и сжатую историю, пишет один шаг как схему, а StepValidator возвращает ошибочный шаг до любого tool callМодель читает план, записи и сжатую историю, пишет один шаг как схему, а StepValidator возвращает ошибочный шаг до любого tool call

Ключевые компоненты:

КомпонентФункция
StepValidatorПроверяет каждый предложенный шаг. Если что-то не так, возвращает его на доработку с комментариями.
Управление контекстомПолный план с предыдущего хода плюс сжатая история для более старых ходов
Динамическое обогащениеАвтоматически подтягивает профиль пользователя, проекты, клиентов; LLM фильтрует и подставляет только данные, релевантные задаче
Обёртки автоматической пагинацииВсе list-эндпоинты автоматически возвращают полный результат

Команда сообщила, что запускала gpt-oss-120b на Cerebras со скоростью до примерно 3000 токенов в секунду. Команда совместила валидацию с высоким throughput инференса, что, возможно, снизило её цену в латентности. Публичный результат не позволяет выделить этот эффект.

Стек: модифицированный агент NextStep — пример SGR-агента, опубликованный для ERC3.


4. Система enricher и guard (команда J8Gvbi / @mishka)

Это решение добавило к базе на SGR неблокирующие подсказки и многоуровневую систему гардов. По мере поступления ответов API enricher’ы проверяли их и добавляли в последующий контекст операционные указания. Гарды проверяли ответ агента перед отправкой.

Два enricher'а превращают ответы API в подсказки, затем три режима гарда: hard block отклоняет, soft block принимает повторный ответ, soft hint принимает с подсказкойДва enricher'а превращают ответы API в подсказки, затем три режима гарда: hard block отклоняет, soft block принимает повторный ответ, soft hint принимает с подсказкой

Более 20 компонентов обогащения проверяли ответы API и добавляли контекстные подсказки:

RoleEnricher: "You are LEAD of this project, proceed with update."
PaginationHintEnricher: "next_offset=5 means MORE results! MUST paginate."

Система гардов с тремя режимами:

РежимПоведение
Hard blockОтвет, который невозможен по данным API, например называет сотрудника вне команды проекта, отклоняется
Soft blockРискованный ответ один раз отклоняется с предупреждением и принимается, если агент отправляет его повторно после этого предупреждения
Soft hintПодсказка добавляется без блокировки

Гибридная RAG-вики: команда искала по локальной копии корпоративной вики тремя способами: regex для структурированных шаблонов вроде salary|privacy, эмбеддинги sentence-transformer для семантических совпадений и пересечение токенов как запасной поиск по ключевым словам. Моё объяснение, зачем три: regex находит точные имена полей и термины, а эмбеддинги находят правила, сформулированные иначе, чем вопрос.

Стек: qwen/qwen3-235b-a22b-2507 на SGR-фреймворке LangChain.


5. Plan-execute REPL (команда 5qsp7i / key_concept_parallel)

Эта архитектура разделяла планирование и написание кода по разным вызовам модели. Сгенерированный Python выполняется в REPL (read-eval-print loop): сессии Python, которая сохраняет переменные между шагами. Решение попало в более широкий Ultimate-лидерборд, а не в замороженную призовую пятёрку. Его публичное описание всё равно полезно, потому что показывает другую форму декомпозиции: изоляцию по фазе выполнения, а не по бизнес-роли.

Планировщик, модель кода, REPL и модель решения с их исходами, и трейс из четырёх шагов, где повторное планирование переписывает шаги 3 и 4, но сохраняет переменные REPL s1 и s2Планировщик, модель кода, REPL и модель решения с их исходами, и трейс из четырёх шагов, где повторное планирование переписывает шаги 3 и 4, но сохраняет переменные REPL s1 и s2

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

Мультимодельная конфигурация:

СтадияМодель
Планированиеopenai/gpt-5.1
Генерация кодаdeepseek/deepseek-v3.2
Решение после шагаopenai/gpt-4.1
Финальный ответopenai/gpt-4.1

REPL завершения шага:

  1. Планировщик создаёт шаг высокого уровня.
  2. Модель генерации кода работает в свежем контексте модели и пишет для этого шага скрипт на Python.
  3. Скрипт выполняется в REPL, привязанном к задаче, переменные которого сохраняются между шагами.
  4. Модель решений смотрит на результат и выбирает один из четырёх исходов: продолжить со следующим шагом, завершить, потому что задача выполнена, прервать, потому что она провалена, или перепланировать.

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


Паттерны, которые повторялись в решениях

Реализации различались, но несколько инженерных задач повторялись в публичных описаниях снова и снова.

Управление контекстом было явным

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

Контекст, разделённый на правила вики, записи, результаты поиска и историю ходов, каждый с политикой, моментом срабатывания и командами, которые её использовалиКонтекст, разделённый на правила вики, записи, результаты поиска и историю ходов, каждый с политикой, моментом срабатывания и командами, которые её использовали

СтратегияПодходЛучше всего для
Выделение правилПредобработка правил вики в компактные инструкции с сохранением ограниченийКомпактные промпты, быстрый старт
Предварительная загрузка данныхЗагрузка данных о пользователе, проекте и клиенте до выполненияМинимум tool calls
Гибридный RAGПотоки поиска: regex + семантический + по ключевым словамСложные задачи retrieval
Сжатие историиНедавние ходы хранятся полностью, старая история сжимаетсяДлинные диалоги

Компромисс: NLN7Dw сжимала старые ходы, а f1Uixf сообщила, что сжатие истории ухудшило её эксперименты, и оставила полный диалог. Относитесь к сжатию как к измеряемому выбору, а не как к значению по умолчанию. Сильные решения различались и размером промпта. Kc7F2N (3-е призовое место) свела собственные инструкции к минимуму, опиралась на дистиллированные правила вики и строила инструменты поиска на эмбеддингах. MMzXeM (4-е призовое место) удерживала основной промпт в 320 токенов и спрятала всю вики за инструментом ask_wiki, который полагался на кэширование контекста, чтобы оставаться дешёвым.


Проверки до, во время и после основного цикла

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

Временная шкала от задачи до грейдера: security gate перед циклом, проверка шага внутри него и проверка в трёх режимах после него, каждый с тем, что он видит и останавливаетВременная шкала от задачи до грейдера: security gate перед циклом, проверка шага внутри него и проверка в трёх режимах после него, каждый с тем, что он видит и останавливает

Тип гардрейлаКогдаПример
Проверки до выполненияДо начала основного циклаSecurity Gate Agent валидирует права по правилам вики
Валидаторы внутри циклаВо время ризонингаStepValidator проверяет каждое предложенное действие и запускает доработку, если оно ошибочно
Проверки после выполненияПеред финальной отправкойТрёхрежимная система гардов сверяет ответ агента с данными API и политикой

Обёртки над инструментами

Несколько команд изменили слой инструментов, который видит модель, вместо того чтобы добавлять инструкции про сырой API:

  • Автопагинация: NLN7Dw убрала пагинацию из каждого инструмента. Одна функция проходит по всем страницам и возвращает полный список.
  • Нечёткая нормализация: парсеры инструментов J8Gvbi сопоставляют человеческие формулировки с именами в API, так что «Willingness to travel» становится полем will_travel.
  • Очистка схем: f1Uixf убрала неиспользуемые поля из схем инструментов и расширила описания параметров. NLN7Dw пересобрала Req_LogTimeEntry — единственный инструмент SDK, у которого поля шли в другом порядке, потому что этот порядок сбивал модель.
  • Инструменты ризонинга: xoDvsa (7-е призовое место, 0.515) добавила инструменты plan, think и critic к обычному ReAct-агенту. Инструмент critic возвращает structured output с отдельными полями для ризонинга.

Обёртка скрывает пагинацию от модели: агент запрашивает список один раз, а list_all следует за next_offset, пока значение не станет -1 — признаком конца из официального примера ERC3. Код ниже иллюстрирует шаг 1 порядка внедрения в конце статьи; это не код какой-либо команды. respond строит ссылки на сущности из ID, которые агент получил, и отклоняет ID, которого агент никогда не видел. Поэтому каждая ссылка создаётся кодом, а выдуманный ID отклоняется ещё до того, как его увидит оценщик.

# Stand-in for the benchmark API: 12 projects, 5 per page.
PROJECTS = [{"id": f"proj_{i}", "name": f"Project {i}"} for i in range(12)]

def call_api(endpoint: str, offset: int = 0, limit: int = 5) -> dict:
    page = PROJECTS[offset : offset + limit]
    more = offset + limit < len(PROJECTS)
    return {"items": page, "next_offset": offset + limit if more else -1}

def list_all(endpoint: str) -> list[dict]:
    """Follow next_offset until the API returns the terminal value -1."""
    items, offset = [], 0
    while offset != -1:
        page = call_api(endpoint, offset=offset)
        items.extend(page["items"])
        offset = page["next_offset"]
    return items

def respond(text: str, entity_ids: list[str], fetched: list[dict]) -> dict:
    """Build required links from IDs; refuse IDs the agent never fetched."""
    known = {row["id"] for row in fetched}
    unknown = [i for i in entity_ids if i not in known]
    if unknown:
        raise ValueError(f"unknown entity ids: {unknown}")
    return {"message": text, "links": [{"id": i} for i in entity_ids]}

projects = list_all("/projects/list")
assert len(projects) == 12  # three pages, one list
print(respond("You lead two projects.", ["proj_3", "proj_11"], projects))

Агент никогда не видит границу страниц, а proj_11 с третьей страницы — корректная ссылка.


Типичные сбои и структурные исправления, о которых сообщали команды

В разборах постоянно упоминаются сбои, когда агент вызывает API или применяет политику компании. Самые переиспользуемые исправления переносили требование в код или в отдельный шаг валидации:

Тип сбояОписаниеАрхитектурное исправление
Обход прав доступаВыполнение запрещённых действий без проверки прав пользователяPre-execution Security Gate Agent; обязательная последовательность Identity → Permissions → Execution
Отсутствующие ссылки на сущностиПравильный текстовый ответ, но без обязательных ссылокВстроенный LinkGeneratorAgent в инструменте ответа
Неполная пагинацияОбработка только первой страницы спискаОбёртки с автопагинацией для всех list-эндпоинтов
Повторяющиеся tool callsПовторные вызовы с небольшими вариациямиЛимиты ходов; более понятные схемы инструментов; выбор модели, проверенный на реальном воркфлоу
Избыток контекстаЗаполнение контекста нерелевантными разделами викиДистилляция правил; динамическая фильтрация контекста

Два отчёта добавляют деталей к строке про циклы. f1Uixf наблюдала циклы tool calls с GPT-5, но не с меньшей моделью Qwen3. NLN7Dw поставила лимит ходов слишком низким, и 5 из 103 задач не завершились, так что лимиту ходов нужен запас.


Практический порядок внедрения

ERC3 — это одна симулированная компания, а не общее исследование абляций агентов. Используйте его как источник гипотез о дизайне, а затем проверяйте эти гипотезы на собственных трейсах. Разумный порядок внедрения такой:

  1. Сначала сделайте корректность API детерминированной. Автопагинируйте list-эндпоинты, нормализуйте нечёткие поля, валидируйте схемы и генерируйте обязательные ссылки внутри инструмента ответа.
  2. Добавьте проверки там, где ошибка дорого стоит. Проверяйте личность и права перед изменением; валидируйте шаг до выполнения только тогда, когда дополнительный вызов модели ловит сбои, стоящие своей цены.
  3. Запишите политику контекста. Решите, что предзагружается, извлекается, сжимается или хранится дословно. Измеряйте политику по срезам задач, а не только по числу токенов.
  4. Превращайте неудачные трейсы в регрессионные кейсы. Классифицируйте сбой, меняйте один механизм и перезапускайте затронутый срез. Автоматизируйте правку промпта только после того, как этот цикл станет надёжным.
  5. Декомпозируйте, когда зоны ответственности становятся яснее. Отдельный компонент оправдан, если он может отвечать за ограничение, использовать другую модель или инструмент либо тестироваться независимо, а не просто потому, что «multi-agent» звучит солиднее.

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

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

Источники