Суть
Без этого свойства любая нестабильность сети, таймаут или гонка между запусками начинает стоить денег или инцидентов. Причём в агентной системе поводов для повтора больше, чем в обычном сервисе: повтор бывает не только сетевым, но и логическим — модель решила вызвать инструмент второй раз, потому что не увидела результата первого.
Ключ идемпотентности — часть протокола, а не необязательная договорённость. Если он опционален, его рано или поздно забудут именно в том вызове, где он был нужен.
Граница ответственности: инструмент, а не оркестратор
Важное различие, которое постоянно путают. Оркестратор может быть сколь угодно атомарен относительно своего состояния — например, супершаг графа не закрывает снапшот при сбое узла (Pregel Model). Но вызов, который узел успел сделать наружу, уже произошёл: письмо отправлено, платёж проведён, запись создана. Никакой механизм графа этого не вернёт.
Отсюда правило: ключ идемпотентности лежит на инструменте, а не на оркестраторе. Повтор узла после паузы или сбоя начинается с первой строки функции, и защитить внешний мир может только сам инструмент (LangGraph Reliability).
Повтор без классификации ошибок множит хаос
Стратегия «не получилось — повторим ещё три раза» опасна, потому что исходы не равнозначны:
| Класс исхода | Что делать |
|---|---|
validation_failure |
Повторять почти никогда не нужно — вход не станет валиднее |
permission_denied |
Количеством повторов не чинится |
retryable_failure |
Как раз здесь уместен повтор с экспоненциальной задержкой |
side_effect_unknown |
Осторожность, а не слепой повтор |
Политика повторов зависит от класса исхода, а не от надежды, что в этот раз получится.
Самый неприятный статус — side_effect_unknown
Категория, в которой неизвестно, произошёл побочный эффект или нет: таймаут после отправки запроса, обрыв соединения после фиксации транзакции, падение адаптера до сохранения подтверждения, ответ внешнего API, из которого итоговое состояние неясно.
Наивный повтор здесь особенно опасен. Правильные ветки другие:
- проверить текущее состояние во внешней системе;
- выполнить сверку по корреляционному идентификатору;
- запросить человека (Approval Path);
- остановить процесс и зафиксировать неопределённость.
На примере агента поддержки: самый опасный момент — не ошибка в рассуждении, а таймаут после вызова создания тикета. Без ключа идемпотентности повторный вызов превращает одно обращение клиента в два инцидента. Правильная ветка сначала ищет тикет по корреляционному идентификатору и либо привязывает найденный результат к трассе, либо останавливает запуск.
Выполнение и доставка — два разных факта
Для сообщения или webhook недостаточно статуса done. Вход может быть durably accepted и пережить рестарт до исполнения; исходящее действие может выполниться, но подтверждение доставки потеряться. Поэтому трасса хранит отдельно accepted, executed и delivered, а неопределённая доставка остаётся delivery_unknown, не превращаясь автоматически в retry.
Blind retry такого статуса создаёт дубли ровно так же, как повтор платежа. Сначала нужна сверка по correlation/idempotency key; если внешний канал не умеет её дать, система сохраняет неопределённость и эскалирует, а не делает вид, что exactly-once достижимо.
Ветка восстановления проектируется, а не импровизируется
Тяжёлые инциденты чаще происходят не в счастливом пути, а в плохо спроектированной ветке восстановления. Заранее определяется: какие классы исходов требуют сверки вместо повтора, где частичный успех должен порождать следующую задачу, когда само восстановление требует подтверждения, и где опасный путь восстановления лучше остановить, чем «помочь пользователю ещё раз».
Лимиты частоты — тоже часть безопасности
Когда лимиты считают вопросом производительности, слой выполнения недооценивает их архитектурную роль. Они нужны, чтобы сорвавшийся агент не положил внешнюю систему, циклическое планирование не превратилось в лавину вызовов, дорогая возможность не съела бюджет, а шторм повторов не убил интеграцию.
Поэтому лимит задаётся не только на сервис целиком, но и на инструмент (Agent CostControl).
Связано с
- Tool Gateway — где проверяется ключ и класс риска
- Rollback Boundary — что делать, когда повтор невозможен
- Agent Failure Modes — каталог отказов, включая тихие
- Approval Path — эскалация при неизвестном исходе
- LangGraph Reliability — идемпотентность узлов в конкретном фреймворке
- Pregel Model — почему атомарность графа не защищает внешний мир
- AI Integration Patterns — идемпотентность инференса на границе систем
- EDA For AI — дедупликация при доставке «хотя бы один раз»