Перейти к основному содержимому

Надёжного выполнения недостаточно: чекпоинтинг в стиле Restate и интент, который он теряет

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

A checklist with a red checkmark symbolizing a completed task on a pastel blue background.

Что на самом деле гарантирует надёжное выполнение

Движки надёжного выполнения — Restate, Temporal и подобные системы — решают реальную и сложную задачу: они позволяют workflow пережить смерть процесса, сетевые разделения и деплои. Гарантии точны, и их стоит сформулировать прямо.

  • Однократное выполнение шага. Завершённый шаг не выполняется повторно при воспроизведении. Его результат читается из надёжного журнала.
  • Возобновляемость после сбоя. Воркер может умереть посреди запуска; другой подхватывает журнал и продолжает с последней зафиксированной границы.
  • Детерминированное воспроизведение завершённой работы. При том же журнале рантайм реконструирует ту же последовательность побочных эффектов.

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

Путаница возникает легко, потому что терминология пересекается. «Надёжный» звучит как «заслуживающий доверия». «Однократный» звучит как «корректный». В обычном workflow — списать с карты, отправить письмо, обновить строку — интент фиксируется на этапе написания и закодирован в самом графе. Граф и есть интент. В запуске агента граф порождается во время выполнения из рассуждений модели над целью. Журнал фиксирует, что агент сделал, а не почему ему было позволено это сделать.

Разрыв интента в момент возобновления

Рассмотрим, что на самом деле содержит запуск в момент старта. Есть цель («урегулировать запрос этого клиента на возврат»), план (последовательность вызовов инструментов, предложенная агентом), набор принятых ограничений (потолок возврата, разрешённые инструменты, данные, которые агент может читать) и бюджет (токены, астрономическое время, число внешних вызовов).

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

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

Это порождает специфический и неприятный режим отказа: возобновлённый запуск, который успешно завершается, делая то, что исходная траектория никогда не санкционировала. Завершение выглядит правдоподобно. Логи чистые. Последовательность шагов воспроизводится детерминированно. И действие неверно, потому что интент, оправдывавший его, устарел.

Dynamic stock market trading chart showcasing live financial data and indicators for analysis.

Это баг корректности, а не баг доступности. Он не проявляется в тестах на восстановление после сбоя. Он проявляется в продакшене, недели спустя, когда кто-то спрашивает, почему агент выдал возврат, который политика уже запретила.

Фиксация контекста решения

Решение — сохранять контекст решения рядом с состоянием. Конкретно, чекпоинт должен нести:

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

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

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

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

Идемпотентность — это не согласие

Ключи идемпотентности — хорошо понятный механизм: они гарантируют, что повторный внешний вызов не спишет дважды, н

Ключ идемпотентности предотвращает двукратное срабатывание одного и того же вызова. Он ничего не делает с единственным вызовом, сделанным по истёкшему мандату. Если полномочия агента на выдачу возвратов истекли в 14:00, а запуск возобновляется в 14:05, идемпотентный вызов возврата выполнится ровно один раз — и будет несанкционированным.

Historic US Army checkpoint at Berlin's Mauermuseum near former Berlin Wall.

Эти два понятия должны быть разделены в рантайме:

  • ключ идемпотентности идентифицирует операцию, поэтому повторы безопасны;
  • токен полномочий идентифицирует мандат, поэтому выполнение разрешено.

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

Правила проектирования для длинных запусков

Из сказанного следует несколько правил. Они не бесплатны, но дешевле молчаливого отказа корректности.

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

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

Логируйте каждое событие возобновления с разницей между исходным и повторно валидированным интентом. Разница — это интересный артефакт. Она фиксирует, что изменилось — политика, бюджет, область, состояние мира — и почему запуск продолжился или остановился. Без неё пост-инцидентный разбор не имеет опоры.

Конкретный работающий механизм: запись контекста решения, хранимая рядом с журналом, версионируемая и проверяемая небольшим сервисом-валидатором на каждой границе возобновления. Валидатор берёт запись и текущий снимок политики и возвращает continue, pause или terminate. Журнал остаётся заботой рантайма; контекст решения — заботой агента. Их разделение делает разрыв интента видимым, а не прячет его внутри сериализованного стека.

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

ПоделитьсяXLinkedInПостоянная ссылка6 мин чтения

На какие вопросы это отвечает

What is the intent gap in durable agent execution?

The intent gap is the difference between the state a checkpoint serialises (variables, step index, tool outputs) and the decision context that justified the run (goal, plan version, tool scope, budget, reason for the next step). A resumed run can replay state correctly while acting under intent that is no longer valid.

Why is idempotency not the same as consent?

Idempotency ensures a retried call does not take effect twice. It does not ensure the call was authorised. A single call made under an expired mandate will execute exactly once and still be wrong. Idempotency keys and authority tokens must both be valid at execution time.

How should a runtime handle a failed re-validation on resume?

Treat it as a terminal state, not a retry. Retrying a policy failure produces the same refusal and burns budget. The run should stop, log the delta between original and re-validated intent, and hand back to a human or orchestrator.

Should an agent replay its plan on resume?

No. The plan should be treated as a proposal, not a script. On resume, re-derive the next step from the goal, current world state, and remaining budget. The journal constrains what has already happened; it should not dictate what happens next.