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

Durable Execution — это реальное инфраструктурное требование для долгоживущих агентов

Инвестиции и продукты вокруг durable execution указывают на настоящую сложную проблему в инфраструктуре агентов: детерминированный реплей и идемпотентные эффекты для запусков, которые длятся часами и порождают внешние побочные эффекты.

Fuel train and refinery tanks in Trzebinia, Poland, showcasing industrial energy infrastructure.

Почему запуски агентов ломают модель запрос-ответ

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

Долгоживущий агент — это не один inference. Это workflow: последовательность решений, tool call'ов, ожиданий и записей во внешние системы. Каждый шаг может отказать независимо. Процесс может быть перезапущен при выкатке деплоя. Провайдер может отвалиться по таймауту посреди вызова. Воркер может быть вытеснен. Когда происходит что-либо из этого, запуск остаётся в несогласованном состоянии: часть побочных эффектов уже применилась, часть — нет, а буфер диалога, в котором хранился план, потерян.

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

Два свойства, которые имеют значение

Durable execution для агентов опирается на два свойства. Оба хорошо поняты в распределённых системах. Ни одно из них не является стандартом в агентных фреймворках.

Детерминированный реплей

При тех же записанных решениях и результатах инструментов запуск должен возобновиться в той же точке. Это значит, что каждый недетерминированный вход — вывод модели, ответ инструмента, показание часов, случайное зерно — записывается в append-only лог. При перезапуске рантайм воспроизводит лог, повторно выполняет детерминированные части workflow и пропускает записанные побочные эффекты. Запуск продолжается с шага, который выполнялся в момент смерти процесса.

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

Идемпотентные эффекты

Каждая внешняя запись должна нести ключ, который делает повторную попытку no-op. Если запуск вызывает платёжный API, вызов включает ключ идемпотентности, производный от ID запуска и ID шага. Если API получает один и тот же ключ дважды, он возвращает исходный результат вместо повторного списания. Если запуск отправляет письмо, отправка снабжена ключом так, что ретрай не создаёт дубликат. Если запуск пишет в базу данных, запись — это upsert с ключом по запуску и шагу.

Идемпотентность — это не свойство агента. Это свойство контракта между агентом и каждой внешней системой, к которой он обращается. Этот контракт нужно спроектировать, задокументировать и протестировать. Его нельзя вывести из промпта.

Detailed view of a metallic pipe system with valves in an industrial setting.

Где это меняет дизайн агента

Как только вы принимаете детерминированный реплей и идемпотентные эффекты как требования, несколько проектных решений меняются.

Классификация инструментов

Tool call'ы должны быть разнесены по трём категориям:

  • Чистые: нет внешнего эффекта, безопасно повторять. Чтение файла, вычисление хеша, форматирование строки.
  • Идемпотентные: есть внешний эффект, безопасно повторять с тем же ключом. Upsert'ы, вызовы API с ключом, идемпотентные отправки сообщений.
  • Неповторяемые: внешний эффект, который нельзя безопасно повторить. Отправка разового уведомления, исполнение сделки, удаление ресурса без пути soft-delete.

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

Состояние в durable-хранилище

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

Это имеет практическое следствие: модель можно заменить, промпт можно переписать, и запуск всё равно сможет возобновиться. Состояние не связано с контекстным окном модели.

Бюджет, привязанный к запуску

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

Механизм прост: бюджет — это поле в записи durable-запуска, уменьшаемое на каждом шаге и сохраняемое до того, как предпринят побочный эффект шага. Компромисс в том, что проверки бюджета добавляют запись на каждом шаге, что увеличивает задержку и стоимость хранения. Для запусков с множеством мелких шагов эти накладные расходы измеримы. Альтернатива — потеря состояния бюджета при падении — хуже.

Close-up of a professional audio mixer showcasing control dials and sliders used in sound mixing.

Последствия для оценки

Durable execution меняет то, как тестируются агентные системы.

Crash-injection как стандартный тест

Самый полезный тест — crash-injection: убить воркер на каждом шаге и убедиться, что запуск сходится к тому же терминальному состоянию. Это не unit-тест. Это property-тест над конечным автоматом запуска. Он ловит баги, которые имеют значение: шаги, которые не идемпотентны, состояние, которое не сохраняется до побочного эффекта, пути реплея, которые расходятся с исходным выполнением.

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

Логи реплея как фикстуры для оценки

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

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

Что строить первым

Порядок имеет значение. Начните с лога реплея: append-only записи решений, результатов инструментов и границ шагов. Затем сделайте каждую внешнюю запись идемпотентной с ключом, производным от запуска и шага. Затем классифицируйте инструменты и добавьте подтверждение человеком для неповторяемого класса. Затем привяжите бюджет к записи запуска. Затем постройте харнесс для crash-injection.

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

Цикл промптов — не сложная часть. Сложная часть — это инфраструктура, которая позволяет запуску пережить процесс, который его начал.

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

Связанное чтение

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

What is deterministic replay in an agent run?

Deterministic replay means the runtime records every non-deterministic input — model output, tool response, clock reading, random seed — in an append-only log. On restart, it replays the log, re-executes the deterministic parts, and skips recorded side effects, so the run resumes at the same step it was in when the process died.

Why is idempotency necessary for agent tool calls?

Without idempotency, a retry after a crash duplicates every external write that already succeeded. Idempotency keys derived from the run ID and step ID make a repeated attempt a no-op, so the runtime can safely retry without reconciling state manually.

How does durable execution change agent evaluation?

Crash-injection becomes a standard test: kill the worker at each step and assert the run converges to the same terminal state. Replay logs also double as evaluation fixtures, letting teams re-run a trajectory against a new model without re-executing side effects.

What is the trade-off of attaching budget to the durable run?

Budget checks add a write to every step, which increases latency and storage cost. For runs with many small steps, that overhead is measurable. The alternative — losing budget state on crash and silently multiplying cost across restarts — is worse.