3,583 papers
arXiv:2610.15884 82 11 окт. 2026 г. FREE

RetryBench: проверка, когда агент вправе повторить запрос после таймаута

КЛЮЧЕВАЯ СУТЬ
Парадокс: агент, который грамотно повторяет запрос со своим ключом, так же охотно повторит его с чужим. В тесте RetryBench все три модели в 78–80 случаях из 80 верно повторяли запрос с тем же ключом. Но когда в подсказке лежал другой ключ, две модели из трёх брали его в большинстве случаев. Метод позволяет прописать в агенте, когда повтор после таймаута (запрос завис, ответа нет) разрешён, а когда нет. Это защищает от дублей счетов, заказов и сделок. Правило допуска записано как условие «ИЛИ»: тот же ключ и те же данные, либо надёжный источник подтвердил, что операция завершена и ничего не создала. Ключ идемпотентности — это метка запроса, по которой сервер узнаёт повтор. Модель перестаёт гадать по ответу «не найдено» и просто сверяет условия.
Адаптировать под запрос
⚡

TL;DR

Исследование показывает, что умение безопасно повторить запрос с правильным ключом не означает умения отказаться от повтора с неправильным. Ключ идемпотентности — это метка запроса, по которой сервер узнаёт повтор и не выполняет операцию второй раз. RetryBench записывает первое решение модели после таймаута и проигрывает его в нескольких «скрытых мирах»: операция не выполнилась, ещё в пути или уже выполнена, но не видна. Метрика — ложное разрешение повтора (FRP): модель повторила запрос, хотя условия для этого не выполнены. Метрика считается отдельно от того, чем всё закончилось.

Боль в том, что две проверки дают разную картину. Если смотреть только на дубли, выигрывает политика «всегда ждать». Если смотреть только на итоговое состояние, модель может выглядеть молодцом просто потому, что ей повезло с миром. В тесте все три модели в 78–80 случаях из 80 корректно повторяли запрос с тем же ключом. Но когда в подсказке лежал другой ключ, две модели из трёх подхватывали его в большинстве случаев, а одна (Sol) почти никогда. Модель берёт то, что ей предложили, и не сверяет с контрактом.

Практический вывод для вашего агента: прописывайте правила повтора прямо в инструкции и не показывайте ему «удобный» ключ. Когда в подсказках явно сказано, что чтение может быть устаревшим, а исходная операция ещё может завершиться, все 762 вернувшихся ответа ушли в отсрочку. А вот сухая метка «доказательства слабые» помогает слабо: в основном тесте модели повторяли запрос почти всегда и с ней, и без неё.

🔬

Схема метода

ШАГ 1: Таймаут при операции с побочным эффектом → модель выбирает ОДНО действие
        (повторить / повторить с ключом / ждать / остановиться / передать человеку)
ШАГ 2: Решение проигрывается в трёх мирах:
        не выполнено | ещё в пути | выполнено, но скрыто устаревшим чтением
ШАГ 3: Считаем РАЗДЕЛЬНО:
        • ложное разрешение (повтор без оснований)
        • дубли и пропуски
        • неразрешённые исходы
        • точное итоговое состояние

Критерий допуска повтора у авторов:

Повтор разрешён, если:
  (ключ идемпотентности защищает ИМЕННО эту операцию и эти данные)
  ИЛИ
  (во ВСЕХ совместимых мирах исходная попытка завершена И не оставила эффекта)
🚀

Пример применения

Задача: Вы собрали в n8n агента для интернет-магазина. Он создаёт счёт на 49 900 ₽ через API платёжного сервиса. Запрос ушёл, ответ не пришёл, таймаут. Агент спрашивает «счёт найден?», получает «не найден» и без раздумий создаёт счёт заново. Клиенту приходят два счёта.

Промпт (фрагмент системной инструкции агента):


Ты — агент оформления счетов интернет-магазина «Сибирский чай».



Ситуация: запрос на создание счёта завершился таймаутом.

Факт: ответ «счёт не найден» при проверке по списку НЕ доказывает,
что исходный запрос не выполнился. Чтение может быть устаревшим,
а исходный запрос может быть ещё в пути и завершиться позже.

Повтор разрешён только в двух случаях:
1. Ты используешь ТОТ ЖЕ ключ идемпотентности, что был в исходном запросе,
   с теми же сумма/клиент/состав заказа.
2. Источник с полномочиями (прямой статус операции) подтвердил:
   операция завершена И ничего не создала.

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

Что делать вместо повтора: ждать и запросить статус у платёжного сервиса,
либо передать менеджеру с пометкой «исход неизвестен».



Верни JSON: {"action": "retry_same_key | wait | escalate | stop",
"reason": "...", "key_used": "... или null"}

Результат: Агент вернёт одно действие в JSON. Если в логе есть ключ исходного запроса, ожидается повтор с этим ключом. Если ключа нет, ожидается ожидание или передача менеджеру с пометкой «исход неизвестен». Повтора «просто так» быть не должно. Это нужно проверить на своих таймаутах: у авторов модели вели себя по-разному.

🧠

Почему это работает

Слабость. Модель читает слова «не найден» как «не было». Но отрицательный ответ может означать три разных мира: операция не выполнилась, ещё в пути или уже выполнена, но чтение отстаёт. Какой из них реальный, из текста не узнать. Кроме того, модель охотно принимает предложенное. Если в подсказке лежит ключ, она часто использует его, не сверяя с исходным запросом.

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

Как метод обходит слабость. Правило допуска записано как условие «ИЛИ» с конкретными требованиями: тот же ключ, те же данные, подтверждение с полномочиями. Модели остаётся проверить условие, а не гадать.

Рычаги управления: - Подсказка с ключом → уберите готовый «кандидат» из контекста. Пусть модель берёт ключ только из записи исходного запроса. Так уменьшается соблазн принять чужой. - Явная семантика чтения («может быть устаревшим») → добавьте обязательно. Одна метка «слабые доказательства» работала нестабильно. - Список допустимых действий → добавьте «ждать» и «передать человеку», иначе единственным выходом будет повтор. - Формат вывода → требуйте поле key_used, чтобы проверять ключ.

📋

Шаблон промпта


Ты — {роль_агента} для {система/компания}.



Ситуация: запрос «{тип_операции}» завершился таймаутом или ответ не получен.

Факт: ответ «{не найдено / пусто}» при проверке НЕ доказывает,
что исходная операция не выполнилась. Чтение может быть устаревшим,
а исходная операция может ещё завершиться.

Повтор разрешён только если:
1. Используется ТОТ ЖЕ ключ идемпотентности, что в исходном запросе,
   и те же данные ({ключевые_поля}); ИЛИ
2. {источник_с_полномочиями} подтвердил: исходная операция
   завершена И ничего не создала.

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

Вместо повтора: {ждать_и_запросить_статус / передать_человеку}.



JSON: {"action": "retry_same_key | wait | escalate | stop",
"reason": "...", "key_used": "... или null"}

Подставьте: {тип_операции} — что создаёт агент (счёт, заказ, сделка, письмо). {ключевые_поля} — по чему определяется «та же операция». {источник_с_полномочиями} — система, чей ответ считается достоверным, например прямой статус операции у провайдера.

Это переложение критерия допуска из статьи. Полные тексты промптов авторов лежат в приложениях C и E, в присланном фрагменте их нет.

🚀 Быстрый старт — вставь в чат:

Вот шаблон политики повтора для агента. Адаптируй под мою задачу: [твоя задача, например «агент в Make создаёт сделки в Bitrix24»].
Задавай вопросы, чтобы заполнить поля.

[вставить шаблон выше]

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

⚠️

Ограничения

⚠️ Узкая зона: проверяли одно решение: что делать сразу после таймаута. Дальнейшие ходы, ожидание и повтор после ожидания не измерены.

⚠️ Один вендор и четыре задачи: модели только из одной линейки, четыре задачи из разработки (CI, задача, релиз, комментарий). Перенос на платежи, CRM и почту — ваша гипотеза.

⚠️ Модели ведут себя по-разному: одна почти не принимает чужой ключ, две принимают в большинстве случаев. Проверяйте свою модель на своих сценариях.

⚠️ Отсрочка — не восстановление: когда все ответы уходят в ожидание, исход остаётся неразрешённым. Сколько из этих случаев потом закончится хорошо, исследование не выяснило.

⚠️ Метки работают нестабильно: сухая метка «слабые доказательства» помогала не везде. В основном блоке с меткой модель повторяла чуть реже, но всё равно почти всегда. Делайте ставку на явный текст правил, а не на ярлык.

⚠️ Симулятор, не реальный провайдер: защита ключами и хранение работают в симуляторе. Настоящие платёжные API ведут себя иначе. Причины поведения моделей авторы не раскрывают.

🔍

Как исследовали

Идея была простой: решение модели записывают один раз и проигрывают в трёх мирах. В первом исходный запрос не выполнился. Во втором он ещё в пути и позже завершится. В третьем он уже выполнен, но чтение отстаёт. Модель видит одно и то же сообщение «не найдено» во всех трёх мирах. Дальше считают ложные разрешения (повтор без оснований), дубли, пропуски, неразрешённые исходы и точное итоговое состояние.

Проверили три модели одной линейки на четырёх задачах. Основной контроль ключей: 720 ответов. В нём меняли метку, формулировку семантики чтения и состояние ключа: валидный, изменённый или отсутствующий. Результат: валидный ключ почти всегда давал безопасное продолжение. Но в подсказке с изменённым ключом две модели из трёх брали его в большинстве случаев (55 из 80 и 60 из 80), а третья — один раз из 80. Удивило, что у Terra при отсутствующем исходном ключе было 0 ошибок из 80. Она не повторяла вслепую, но легко принимала предложенный ключ.

Чтобы проверить, виновата ли подсказка, провели второй эксперимент (240 ответов). Кандидата убрали, модель должна была подставить ключ сама. Две модели ошибок не сделали. Luna всё равно сделала 8 небезопасных отправок из 80. Значит, одним лишь «принял предложенное» всё не объяснить. Вывод осторожный: схема вывода и время сбора различались, это не чистое сравнение.

Дальше проверили метки: убирали строку «Evidence contract: weak». В блоке с кодированными действиями у двух моделей число повторов выросло. В каноническом блоке (1 536 ответов) у Terra повторов стало больше (124 из 128 против 115 из 128), но эффект сосредоточен в двух условиях. Остальные пять контрастов после поправки на множественность не подтвердились. В последнем контроле (762 вернувшихся ответа) явный текст про устаревшее чтение дал отсрочку во всех ответах, но восстановление осталось неразрешённым.

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

💡

Адаптации и экстраполяции

🔧 Техника: добавить поле key_used → видно, откуда агент взял ключ


JSON: {"action": "...", "reason": "...",
"key_used": "ключ или null",
"key_source": "исходный_запрос | подсказка | сгенерирован"}

Если key_source не равен исходный_запрос, автоматизация блокирует вызов. Так видно сразу то, что в исследовании пришлось восстанавливать по ответам: модель взяла чужой или придуманный ключ. Это моя адаптация, авторы такое поле не проверяли.

Экстраполяция: проверка перед каждым повтором в любом агенте с побочными эффектами

Перед любым повтором операции с побочным эффектом ответь на три вопроса:
1. Что я наверняка знаю об исходной попытке?
2. Какие миры совместимы с моим наблюдением
   (не выполнено / в пути / выполнено, но не видно)?
3. Во всех ли этих мирах повтор безопасен
   (тот же ключ ИЛИ исходная попытка точно завершена без эффекта)?
Если «нет» хотя бы в одном мире — не повторяй.

Это перенос принципа «универсального квантора» из критерия допуска на чат-агента. Сама схема трёх вопросов в статье не проверялась.

🔗

Ресурсы

  • RetryBench: Separating Retry Permission from Recovery Outcomes in GPT Tool Use, You Liu, Yue Liu, Quanchao Lu.
  • Прямые предшественники: Did It Happen? (Sun, 2026), Verified Tool Calls (Mansoor et al., 2026), Limbo (Li, 2026), UndoBench (Sah et al., 2026), ContractBench (Wang et al., 2026), CapLease (Xu et al., 2026).
  • Чувствительность к формату промпта: Sclar et al. (2024), He et al. (2024), Errica et al. (2025).
  • Идемпотентность и неоднозначные исходы: Helland (2012); документация AWS EC2 по eventual consistency; контракт идемпотентности Stripe.
  • Репозитории: OpenOnce (memovai/openonce), IdempotencyBench (gssanjana4/idempotencybench).

📋 Дайджест исследования

Ключевая суть

Парадокс: агент, который грамотно повторяет запрос со своим ключом, так же охотно повторит его с чужим. В тесте RetryBench все три модели в 78–80 случаях из 80 верно повторяли запрос с тем же ключом. Но когда в подсказке лежал другой ключ, две модели из трёх брали его в большинстве случаев. Метод позволяет прописать в агенте, когда повтор после таймаута (запрос завис, ответа нет) разрешён, а когда нет. Это защищает от дублей счетов, заказов и сделок. Правило допуска записано как условие «ИЛИ»: тот же ключ и те же данные, либо надёжный источник подтвердил, что операция завершена и ничего не создала. Ключ идемпотентности — это метка запроса, по которой сервер узнаёт повтор. Модель перестаёт гадать по ответу «не найдено» и просто сверяет условия.

Принцип работы

Принцип — контракт вместо интуиции. Ответ «не найден» может значить три разных мира: операция не выполнилась, ещё в пути или уже выполнена, но чтение отстаёт. Из текста не понять, какой из них настоящий. Поэтому агента нельзя спрашивать «как думаешь, повторить?». Ему надо дать проверяемое условие. Это как турникет в метро: пускает по билету, а не по честному лицу. Нет ключа исходного запроса — повтор невозможен, точка. Рядом с повтором всегда лежат запасные выходы: ждать, запросить статус, передать человеку. Иначе единственным действием останется повтор.

Почему работает

Слабость моделей в том, что они читают «не найден» как «не было». Ещё они охотно берут всё, что лежит в подсказке. Увидели ключ — используют, не сверяя с исходным запросом. Сильная сторона в том, что явное правило они выполняют отлично. Когда в контракте прямо написано «чтение может быть устаревшим, исходная операция ещё может завершиться», все 762 вернувшихся ответа ушли в отсрочку. Модели не хватает не ума, а явного условия: дай проверяемое правило, и она перестанет гадать. Сухая метка «доказательства слабые» работала хуже. С ней модели повторяли чуть реже, но всё равно почти всегда. Ставить надо на текст правил, а не на ярлык.

Когда применять

Агенты, которые меняют данные во внешних системах → создание счетов, заказов, сделок в CRM, писем, особенно когда запрос завис, а проверка «создано ли?» отвечает «пусто». Работает и когда в контексте уже лежат ключи из логов, примеров или прошлых сообщений. НЕ подходит как гарантия для реальных платёжных API. Авторы проверяли только на симуляторе, на четырёх задачах из разработки и на моделях одного вендора. Ждать и повторять после ожидания они не измеряли. Отсрочка — это ещё не восстановление: чем закончатся ожидающие случаи, неизвестно.

Мини-рецепт

1. Вшей факт в инструкцию: напиши, что ответ «не найдено» ничего не доказывает. Чтение может быть устаревшим, а исходный запрос ещё в пути.
2. Запиши условия повтора: тот же ключ и те же данные, ИЛИ надёжный источник подтвердил «завершено и ничего не создано». Всё остальное под запретом.
3. Убери соблазн: не клади в контекст «удобный» ключ. Пусть модель берёт ключ только из записи исходного запроса.
4. Дай запасные выходы: ждать, запросить статус, передать человеку с пометкой «исход неизвестен».
5. Заставь показывать ключ: в ответе нужно поле key_used. По нему легко проверить, не подхватила ли модель чужое.
6. Проверь на своих сбоях: смоделируй таймауты и подсунь левый ключ. У авторов модели вели себя по-разному, одна почти не велась на чужой ключ.

Примеры

[ПЛОХО]: `Запрос на создание счёта завис. Проверь, есть ли счёт, и если нет, создай заново.` [ХОРОШО]: `Запрос на создание счёта завис. Ответ «счёт не найден» НЕ доказывает, что он не создан: чтение может отставать, запрос может быть ещё в пути. Повтор разрешён только с тем же ключом идемпотентности и теми же суммой, клиентом и составом заказа. Или если платёжный сервис напрямую подтвердил: операция завершена и счёт не создан. Чужие ключи из подсказок не принимай. Нет ключа исходного запроса — повтор невозможен. Вместо повтора жди и запроси статус или передай менеджеру. Верни JSON: {"action": "retry_same_key | wait | escalate | stop", "reason": "...", "key_used": "... или null"}` [ПЛОХО]: `Если доказательства слабые, будь осторожен с повтором.` [ХОРОШО]: `Чтение может быть устаревшим, исходная операция может ещё завершиться. Без того же ключа или подтверждения от платёжного сервиса повтор запрещён.`
Источник: RetryBench: Separating Retry Permission from Recovery Outcomes in GPT Tool Use
ArXiv ID: 2610.15884 | Сгенерировано: 2026-10-14 06:00

Проблемы LLM

ПроблемаСутьКак обойти
Ответ «не найдено» модель читает как «этого не было»Агент проверяет, создалась ли запись. Получает «не найдено». Делает вывод: не создалась, создаю снова. Но «не найдено» может значить три разных вещи. Операция не выполнена. Она ещё в пути. Она выполнена, но чтение отстаёт. Из текста ответа это не различить. Итог: дубли, например два счёта или два заказа. Это касается любых сценариев «проверь, потом создай»Напиши в инструкции: «Ответ "не найдено" не доказывает, что операции не было. Чтение может быть устаревшим. Исходная операция может ещё завершиться». Разреши повтор только при надёжном подтверждении. Дай запасной выход: «ждать» или «передать человеку». Иначе модель выберет повтор, потому что других действий у неё нет
Модель берёт значение из контекста и не сверяет его с исходнымВ запросе лежит готовое значение: ключ, ID, токен. Оно не совпадает с тем, что было в исходном действии. Модель часто подставляет его. То, что она верно работает с правильным значением, не значит, что она откажется от неправильного. Поведение зависит от модели: одни берут чужое почти всегда, другие почти никогдаНе клади в контекст «удобных кандидатов». Пусть модель берёт значение только из записи исходного действия. Напиши: «Не принимай значение из подсказок и примеров, если оно не совпадает с исходным». Требуй в ответе отдельное поле, например key_used. Проверяй его кодом

Методы

МетодСуть
Правило допуска для необратимых действий — модель проверяет условие, а не гадаетЗапиши разрешение как «ИЛИ» из проверяемых условий. Действие разрешено, если: (1) используется то же значение, что в исходном запросе, и те же данные; ИЛИ (2) надёжный источник подтвердил: исходная операция завершена и ничего не создала. Иначе запрещено. Добавь: «Нет исходного значения — действие невозможно». Добавь список действий с выходами: retry_same_key / wait / escalate / stop. Почему работает: модель хорошо следует явному правилу. Ей остаётся сверить условия, а не оценивать на глаз. Выходы «ждать» и «передать человеку» снимают давление «хоть что-то сделать». Когда применять: любое действие с побочным эффектом после таймаута или неясного ответа. Например оплата, создание сделки, отправка письма. Когда не работает: действие безопасно повторять без последствий. Также этот метод не показывает, чем закончится ожидание. Исход остаётся неразрешённым, его нужно вести отдельно. Проверяй на своей модели

Тезисы

ТезисКомментарий
Объяснение смысла сигнала работает сильнее короткого ярлыкаФраза «чтение может быть устаревшим, а операция может ещё завершиться» уводит модель в ожидание почти в 100% случаев. Сухая метка «доказательства слабые» помогает слабо: модель всё равно действует. Ярлык не говорит, что делать с неопределённостью. Объяснение называет возможные варианты реальности, и модель их учитывает. Применяй: вместо «ненадёжные данные» пиши, почему они ненадёжны и что из этого следует для действия
📖 Простыми словами

RetryBench: Separating Retry Permission from Recovery Outcomes inGPTToolUse

arXiv: 2610.15884

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

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

Новый бенчмарк RetryBench как раз вскрыл эту уязвимость через замер метрики ложного разрешения повтора (FRP). Авторы гоняли модель по трём скрытым мирам: запрос сдох, запрос ещё ползёт или операция уже прошла, но чтение отстаёт. Оказалось, что GPT радостно хватает любой подсунутый ключ идемпотентности и давит на газ, когда операцию повторять категорически нельзя.

Тестировали на выставлении счетов, но грабли абсолютно универсальны. Та же фигня взорвёт любой прод: от самописных n8n-агентов до сложных интеграций со складом или CRM. Везде, где AI бездумно кликает на внешние API при бронировании отелей или отправке платных SMS, иллюзия автономности рушится на первом же миллисекундном лаге.

Мораль простая: никогда не доверяй языковой модели решение о повторе сетевых действий. Идемпотентность должна жить в коде инфраструктуры, а не держаться на честном слове и надежде, что агент сам догадается. Иначе твой умный ассистент влепит клиенту лишний счёт на 49 900 ₽, а разгребать косяки пойдёшь ты.

Работа с исследованием

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

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с