Если агент искусственного интеллекта дает сбой в процессе выполнения задачи, наличие надежных записей о действиях и четко определенных границ использования инструментов позволяет заменить его другим агентом, который продолжит работу безопасно и без дублирования операций, пишет на портале The New Stack Манвир Чавла — соучредитель компании Zenith (ранее занимал должность директора по разработке в Confluent и руководил направлением Growth Engineering в Dropbox).
Представим ситуацию: агент получает одобрение на частичный возврат средств. Он отправляет запрос к платежному API, но в этот момент происходит сбой. Возможно платежный сервис успел провести возврат, а возможно запрос даже не дошел до него. На смену приходит новый агент, который обнаруживает запись об операции со статусом «отправлено» (dispatched), но без зафиксированного результата.
Подобная неопределенность свойственна не только ИИ-агентам. С такой же проблемой сталкиваются любые распределенные системы, если рабочий процесс прерывается в момент внесения изменений. Однако обычный программный агент (worker) в такой ситуации просто возобновляет заранее заданный алгоритм с последней контрольной точки. ИИ-агент действует иначе: он принимает решения самостоятельно — и это создает дополнительные риски. Столкнувшись с тем же запросом от клиента при отсутствии записи о результате, агент может выстроить совершенно иной план, выбрать другие параметры или решить инициировать новый возврат, вместо того чтобы завершить уже одобренную операцию.
Если первый возврат прошел успешно, то вторая попытка приведет к тому, что клиенту вернут средства дважды. Поскольку на исходном платеже достаточно средств для еще одного частичного возврата, ничто не помешает совершить эту ошибку.
Новый агент должен «унаследовать» исходную операцию, а не интерпретировать ее заново.
Операция должна пережить агента
Процесс агента, его переменные в оперативной памяти, временный контекст рассуждений — все это может быть утрачено без ущерба для дела. Но бизнес-операция — например, возврат средств, его одобрение, параметры и текущий статус — должна быть сохранена. Агент, работающий в течение длительного времени, должен сохранять полезные данные, пока он активен. Однако важно соблюсти условие: ни одна критически важная операция не должна зависеть от того, продолжает ли работать исходный экземпляр агента.
Перед отправкой запроса на возврат средств приложение сохраняет запись об операции в надежном хранилище (транзакционной базе данных). Эта запись содержит одобренную сумму, соответствующие права доступа, ключ идемпотентности (передаваемый платежному провайдеру), идентификатор операции в метаданных провайдера, а также текущий статус.
Статус меняется с «создано» (created) на «отправлено» (dispatched) в момент отправки запроса, а на «подтверждено» (confirmed) или «сбой» (failed) — только после получения ответа от провайдера. Если агент выходит из строя, его преемник считывает эту запись и связанные с ней идентификаторы, что позволяет корректно продолжить выполнение задачи. Если запись находится в состоянии «отправлено», это означает, что была предпринята попытка выполнения операции, но результат не был зафиксирован.
При повторном запуске (замещающий процесс) используется уже одобренная операция, а не создается новая.
Если замещающему процессу необходимо проверить результат, он может запросить список возвратов средств, связанных с исходным платежом, и сопоставить идентификатор операции в полученных метаданных.
Однако такая «устойчивая» (durable) запись служит не просто контекстом для повторного запуска. Приложение обеспечивает ее соблюдение на границе взаимодействия с внешними инструментами: уровень отправки запросов проверяет каждый исходящий вызов на соответствие зафиксированной записи. Агент может предложить следующий шаг, но до провайдера доходят только те операции, которые были одобрены ранее — с сохранением исходных параметров и идентификатора. Модель не может изменить то, что уже было утверждено.
Пример: бизнес-данные, включая эталонную запись об операции, определяющую допустимые действия для замещающего процесса, хранятся в управляемой ClickHouse базе данных Postgres. С помощью технологии CDC (Change Data Capture) эти данные реплицируются в ClickHouse. Телеметрия приложения передается в ClickStack, а трассировки агента — в Langfuse; обе системы настроены на использование того же экземпляра ClickHouse в качестве основной базы данных.
Поскольку бизнес-данные, телеметрия приложения и трассировки агента попадают в одну базу данных, для связывания операции с конкретным запуском агента (который инициировал запрос) и неудачным HTTP-вызовом достаточно одного запроса по идентификатору. Это избавляет от необходимости сопоставлять данные из трех разных инструментов.
Здесь есть два условия. Во-первых, приложение должно передавать этот идентификатор дальше. Идентификатор операции должен присутствовать в строке Postgres, в атрибутах трассировки Langfuse и в контексте логов сервиса, поскольку автоматической корреляции между ними не существует. Во-вторых, замещающий процесс должен считывать запись непосредственно из Postgres, а не из ее реплицированной копии. CDC работает с задержкой в несколько секунд. Эталонная запись в основной базе данных является той самой, которую контролирует механизм на границе взаимодействия с внешними системами.
Перезапуск выполнения — это еще не безопасное возобновление работы
Фреймворки для обеспечения «устойчивого» выполнения (durable execution), такие как LangGraph и Temporal, фиксируют прогресс выполнения и позволяют возобновить работу после сбоя. В обоих случаях рекомендуется делать побочные эффекты идемпотентными, поскольку простое возобновление процесса не решает проблему повторного выполнения. Если возврат средств был успешно проведен в тот момент, когда шаг еще числился как «ожидающий», фреймворк может перезапустить агента, но не сможет сообщить ему, был ли исходный запрос принят платежным провайдером.
Запись об «устойчивой» операции реализует этот принцип идемпотентности для агента, чей следующий шаг заранее не определен.
Ключ идемпотентности из такой записи связывает замещающий процесс с исходным запросом. Если при повторной попытке используется тот же ключ, поставщик услуг может распознать, что речь идет об одной и той же операции, вместо того чтобы выполнять ее как отдельный запрос на возврат средств. Это справедливо даже в том случае, если исходный запрос, отправленный агентом, был завершен уже после сбоя, или если процесс, который ошибочно сочли «мертвым», возобновил свою работу. В библиотеке AWS Builders’ Library этот шаблон формализован: идентификатор, предоставляемый вызывающей стороной, сохраняется атомарно вместе с операцией изменения данных (mutation).
Однако повторная попытка не всегда безопасна. Результат может оставаться неопределенным. В документации Stripe указано, что ответ с кодом 500 при выполнении mutation все равно может привести к внешним последствиям. Если исход неизвестен, замещающему агенту требуются доказательства для проведения расследования.
Langfuse позволяет увидеть, какой инструмент использовал предыдущий агент — например, запрос на возврат средств, отправленный с зафиксированным ключом идемпотентности. ClickStack дополняет картину на операционном уровне: показывает исходящий HTTP-запрос к платежному сервису, за которым последовал разрыв соединения, что позволяет сузить временной интервал возникновения ошибки.
Оба источника данных доступны замещающему агенту напрямую. MCP-сервер Langfuse позволяет запрашивать трассировку предыдущего агента по идентификатору операции, а MCP-сервер ClickStack — искать события в сервисе за тот же промежуток времени. Предоставьте замещающему агенту только инструменты для чтения данных: он сможет проанализировать произошедшее, но границы доступных инструментов по-прежнему будут ограничивать его действия.
Ни одна из трассировок не является доказательством того, что провайдер действительно выполнил возврат средств. Отсутствие трассировки также не доказывает, что запрос не был отправлен, поскольку Langfuse передает данные асинхронно, и сбой в системе мог помешать их доставке. Платежный провайдер остается первоисточником информации о внешнем результате операции. Телеметрия выполнения помогает сузить область поиска, но не заменяет собой официальное подтверждение.
Продолжайте работу, а не начинайте всё сначала
В распоряжении замещающего агента есть постоянная запись о действиях, а в случаях, когда результат остался неясным — еще и свидетельства выполнения операции. Теперь ему необходимо предпринять дальнейшие шаги, но не путем принятия нового решения о том, что нужно сделать.
Замещающий агент следует протоколу восстановления, определенному в приложении, а не полагается на собственное суждение о ситуации клиента.
Если провайдер подтверждает, что возврат выполнен, агент фиксирует результат и переходит к следующим задачам. Если провайдер сообщает, что возврат находится в ожидании или в процессе выполнения, агент ждет — повторная попытка может привести к дублированию операции. Если же возврат определенно не удался и не повлек за собой никаких внешних изменений, агент заново проверяет предварительные условия перед новой санкционированной попыткой. Если результат по-прежнему остается неясным, агент эскалирует задачу на более высокий уровень, а не пытается угадать исход. Отсутствие записи у провайдера не означает, что возврат не был обработан — возможно, провайдер еще не завершил транзакцию.
Даже после выяснения внешнего результата замещающий агент должен убедиться, что состояние системы не изменилось. Например, сумма, доступная для возврата, могла измениться. Сотрудник мог оформить возврат средств через другой интерфейс. Статус учетной записи клиента мог измениться. Кто-то мог отозвать первоначальное разрешение.
Сохраненное одобрение — это лишь историческое свидетельство, а не действующее полномочие для выполнения операций.
С инженерной точки зрения ключевой вопрос заключается в том, сможет ли новый агент определить текущую цель работы, невыполненные обязательства и возможные неопределенные последствия, а затем безопасно продолжить процесс — не воспринимая при этом сведения, оставшиеся от предшественника, как руководство к действию.






























