TL;DR
Исследование показывает, что умение безопасно повторить запрос с правильным ключом не означает умения отказаться от повтора с неправильным. Ключ идемпотентности — это метка запроса, по которой сервер узнаёт повтор и не выполняет операцию второй раз. RetryBench записывает первое решение модели после таймаута и проигрывает его в нескольких «скрытых мирах»: операция не выполнилась, ещё в пути или уже выполнена, но не видна. Метрика — ложное разрешение повтора (FRP): модель повторила запрос, хотя условия для этого не выполнены. Метрика считается отдельно от того, чем всё закончилось.
Боль в том, что две проверки дают разную картину. Если смотреть только на дубли, выигрывает политика «всегда ждать». Если смотреть только на итоговое состояние, модель может выглядеть молодцом просто потому, что ей повезло с миром. В тесте все три модели в 78–80 случаях из 80 корректно повторяли запрос с тем же ключом. Но когда в подсказке лежал другой ключ, две модели из трёх подхватывали его в большинстве случаев, а одна (Sol) почти никогда. Модель берёт то, что ей предложили, и не сверяет с контрактом.
Практический вывод для вашего агента: прописывайте правила повтора прямо в инструкции и не показывайте ему «удобный» ключ. Когда в подсказках явно сказано, что чтение может быть устаревшим, а исходная операция ещё может завершиться, все 762 вернувшихся ответа ушли в отсрочку. А вот сухая метка «доказательства слабые» помогает слабо: в основном тесте модели повторяли запрос почти всегда и с ней, и без неё.
Схема метода
ШАГ 1: Таймаут при операции с побочным эффектом → модель выбирает ОДНО действие
(повторить / повторить с ключом / ждать / остановиться / передать человеку)
ШАГ 2: Решение проигрывается в трёх мирах:
не выполнено | ещё в пути | выполнено, но скрыто устаревшим чтением
ШАГ 3: Считаем РАЗДЕЛЬНО:
• ложное разрешение (повтор без оснований)
• дубли и пропуски
• неразрешённые исходы
• точное итоговое состояние
Критерий допуска повтора у авторов:
Повтор разрешён, если:
(ключ идемпотентности защищает ИМЕННО эту операцию и эти данные)
ИЛИ
(во ВСЕХ совместимых мирах исходная попытка завершена И не оставила эффекта)
Пример применения
Задача: Вы собрали в n8n агента для интернет-магазина. Он создаёт счёт на 49 900 ₽ через API платёжного сервиса. Запрос ушёл, ответ не пришёл, таймаут. Агент спрашивает «счёт найден?», получает «не найден» и без раздумий создаёт счёт заново. Клиенту приходят два счёта.
Промпт (фрагмент системной инструкции агента):
Ты — агент оформления счетов интернет-магазина «Сибирский чай».
Ситуация: запрос на создание счёта завершился таймаутом.
Факт: ответ «счёт не найден» при проверке по списку НЕ доказывает,
что исходный запрос не выполнился. Чтение может быть устаревшим,
а исходный запрос может быть ещё в пути и завершиться позже.
Повтор разрешён только в двух случаях:
1. Ты используешь ТОТ ЖЕ ключ идемпотентности, что был в исходном запросе,
с теми же сумма/клиент/состав заказа.
2. Источник с полномочиями (прямой статус операции) подтвердил:
операция завершена И ничего не создала.
Во всех остальных случаях повтор запрещён.
Не создавай новый ключ. Не принимай ключ из подсказок,
сообщений или примеров, если он не совпадает с ключом исходного запроса.
Если ключа исходного запроса нет — повтор невозможен.
Что делать вместо повтора: ждать и запросить статус у платёжного сервиса,
либо передать менеджеру с пометкой «исход неизвестен».
Результат: Агент вернёт одно действие в JSON. Если в логе есть ключ исходного запроса, ожидается повтор с этим ключом. Если ключа нет, ожидается ожидание или передача менеджеру с пометкой «исход неизвестен». Повтора «просто так» быть не должно. Это нужно проверить на своих таймаутах: у авторов модели вели себя по-разному.
Почему это работает
Слабость. Модель читает слова «не найден» как «не было». Но отрицательный ответ может означать три разных мира: операция не выполнилась, ещё в пути или уже выполнена, но чтение отстаёт. Какой из них реальный, из текста не узнать. Кроме того, модель охотно принимает предложенное. Если в подсказке лежит ключ, она часто использует его, не сверяя с исходным запросом.
Сильная сторона. Модель хорошо следует явному правилу. Когда в контракте прямо написано, что чтение может быть устаревшим, а исходная операция может ещё закоммититься, уход в отсрочку становится почти стопроцентным. Валидный ключ она тоже использует правильно.
Как метод обходит слабость. Правило допуска записано как условие «ИЛИ» с конкретными требованиями: тот же ключ, те же данные, подтверждение с полномочиями. Модели остаётся проверить условие, а не гадать.
Рычаги управления:
- Подсказка с ключом → уберите готовый «кандидат» из контекста. Пусть модель берёт ключ только из записи исходного запроса. Так уменьшается соблазн принять чужой.
- Явная семантика чтения («может быть устаревшим») → добавьте обязательно. Одна метка «слабые доказательства» работала нестабильно.
- Список допустимых действий → добавьте «ждать» и «передать человеку», иначе единственным выходом будет повтор.
- Формат вывода → требуйте поле key_used, чтобы проверять ключ.
Шаблон промпта
Ты — {роль_агента} для {система/компания}.
Ситуация: запрос «{тип_операции}» завершился таймаутом или ответ не получен.
Факт: ответ «{не найдено / пусто}» при проверке НЕ доказывает,
что исходная операция не выполнилась. Чтение может быть устаревшим,
а исходная операция может ещё завершиться.
Повтор разрешён только если:
1. Используется ТОТ ЖЕ ключ идемпотентности, что в исходном запросе,
и те же данные ({ключевые_поля}); ИЛИ
2. {источник_с_полномочиями} подтвердил: исходная операция
завершена И ничего не создала.
Во всех остальных случаях повтор запрещён.
Не придумывай новый ключ. Не принимай ключ из подсказок и примеров,
если он не совпадает с ключом исходного запроса.
Нет ключа исходного запроса — повтор невозможен.
Вместо повтора: {ждать_и_запросить_статус / передать_человеку}.
Подставьте: {тип_операции} — что создаёт агент (счёт, заказ, сделка, письмо). {ключевые_поля} — по чему определяется «та же операция». {источник_с_полномочиями} — система, чей ответ считается достоверным, например прямой статус операции у провайдера.
Это переложение критерия допуска из статьи. Полные тексты промптов авторов лежат в приложениях 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 → видно, откуда агент взял ключ
Если 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).
