Эфир 18.11 · Поток 318 ноября в 19:00 МСК — бесплатный практический эфир по ИИ-агентам · Живой Поток 3 стартует 23.11Эфир 18 ноября →Поток 3 (23.11)
РелизAPI / Продукт · В работуHabr AI→ оригинал

Агент поддержки в проде: Temporal, сага и circuit breaker спасают возвраты от сбоев

Агент поддержки в одном файле работает в демо, а в продакшене падает: перезапуск стирает диалоги, а сбой между возвратом и ответом оставляет вопрос, ушли ли деньги. Автор Habr собирает систему по шагам: API и база, Temporal для долгих процессов, LLM-шлюз с circuit breaker, сага для возврата и оператор для крупных сумм. Каждый компонент добавляется, только когда появилась конкретная боль.

AI-обработка оригинала Habr AI; редакция Hamidun News
Агент поддержки в проде: Temporal, сага и circuit breaker спасают возвраты от сбоев
Источник: Habr AI. Коллаж: Hamidun News.
Слушать статью
Паспорт материала и цифры
ПараметрДанные
ПервоисточникHabr AI ↗
Главный редактор
Workflow ID = id диалогадвойной клик не создаст дубль
Ключевой факт #2Circuit breaker ставьте в LLM-шлюзе с общим состоянием в Redis
Ключевой факт #3Деньги двигает код сагой, крупные возвраты одобряет человек

Клиент пишет: «Посылка не пришла, верните деньги». Агента, который на это ответит, можно написать за вечер: цикл, три инструмента, и в демо всё работает. А потом процесс перезапускается посреди возврата, провайдер модели ложится на полчаса, а клиент жмёт «отправить» дважды. Оказывается, что агент — лишь малая часть системы. Заключительная часть серии на Habr собирает эту систему шаг за шагом, и главная ценность в том, что каждый компонент появляется как ответ на конкретную поломку.

От одного файла к API, воркеру и Temporal

Начальная версия держит историю диалога в памяти процесса. Перезапуск стирает все диалоги, клиентов обслуживается по одному, а если процесс упал между вызовом refund_payment и ответом, никто не знает, вернулись деньги или нет.

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

Но воркер всё равно может упасть на середине обращения. Повторять возврат опасно: можно заплатить дважды. Не повторять тоже плохо: можно не заплатить вообще. Здесь нужен Temporal: он пишет каждый шаг в журнал, и другой воркер продолжает с того же места, не выполняя готовые шаги заново. Цикл агента живёт в workflow, а вызовы модели и инструментов становятся activities.

Два важных уточнения. У Temporal своя база, и бизнес-данные клиентов в ней не хранят: журнал одного выполнения ограничен 51 200 событий или 50 МБ. Воркеры с вашим кодом запускаете вы сами, сервис Temporal их не выполняет. А Workflow ID задаёте вы: возьмите id диалога, и повторная отправка не создаст дубль. Только не кладите в ID персональные данные, он виден в интерфейсе и логах.

Ретрай — это не circuit breaker

Когда провайдер модели лежит полчаса, Temporal честно ретраит activity. Сто воркеров и тысяча открытых обращений дружно долбят упавший API, а когда он поднимается, на него обрушивается вся очередь.

Ретрай рассчитан на сбой, который пройдёт за секунды. Для долгого отказа нужен circuit breaker. Он считает сбои, после порога размыкается и сразу возвращает ошибку, не ходя к сервису, а через время пропускает пробный вызов. Состояние выключателя должно быть общим для всех воркеров, иначе каждый будет заново узнавать, что провайдер лёг. Поэтому его место в LLM-шлюзе между воркерами и провайдерами. LiteLLM, например, выводит модель из ротации после серии сбоев, переключает на запасную и хранит состояние в Redis.

Практический совет автора: пусть activity различает два вида ошибок. Временную повторяет политика Temporal. Ошибку «выключатель разомкнут» не нужно ретраить: workflow сам решает, уйти ли на запасную модель, подождать или передать обращение оператору. Те же выключатели ставят перед службой доставки и платёжкой.

Сага, оператор и роутер

Возврат затрагивает три системы без общей транзакции: этикетка у службы доставки, деньги в платёжке, уведомление клиента и обновление заказа. Это сага: у каждого шага есть компенсация. Ключевое понятие — точка невозврата (pivot transaction). До возврата денег шаги можно отменить, после него письмо клиенту и обновление заказа нужно довести до конца, сколько бы ретраев ни понадобилось. Каждое действие получает ключ идемпотентности, например id решения, и платёжка не спишет деньги повторно.

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

Последний шаг касается стоимости. Не каждое обращение требует полного агентного цикла. Роутер на маленькой модели отправляет FAQ в один вызов, вопрос «где заказ» в заранее прописанную цепочку, и только спорный возврат попадает к агенту. Принцип простой: брать самый низкий уровень сложности, который надёжно решает задачу.

Что с этим делать

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

Ограничения тоже есть. Код в статье — псевдокод. Утверждение, что на Temporal работает веб-агент Codex, исходит от самого вендора, и независимого подтверждения автор не нашёл. Но как карта типовых отказов агентной системы текст полезен любому, кто выпускает агента в прод. Начните с вопроса, что случится, если процесс упадёт после самого рискованного вызова.

Сюжет

Вопросы и ответы по материалу

Что известно по теме: от одного файла к API, воркеру и Temporal?

Начальная версия держит историю диалога в памяти процесса. Перезапуск стирает все диалоги, клиентов обслуживается по одному, а если процесс упал между вызовом refund_payment и ответом, никто не знает, вернулись деньги или нет. Первый шаг: разделить скрипт на API и воркер. API принимает сообщение, пишет его в базу и сразу отвечает чату. Модель он не вызывает, поэтому отвечает за миллисекунды. Агентный цикл живёт в отдельных воркерах, которых можно добавлять под нагрузку. История теперь в базе и переживает рестарты.

Что известно по теме: ретрай — это не circuit breaker?

Когда провайдер модели лежит полчаса, Temporal честно ретраит activity. Сто воркеров и тысяча открытых обращений дружно долбят упавший API, а когда он поднимается, на него обрушивается вся очередь. Ретрай рассчитан на сбой, который пройдёт за секунды. Для долгого отказа нужен circuit breaker. Он считает сбои, после порога размыкается и сразу возвращает ошибку, не ходя к сервису, а через время пропускает пробный вызов.

Что известно по теме: сага, оператор и роутер?

Возврат затрагивает три системы без общей транзакции: этикетка у службы доставки, деньги в платёжке, уведомление клиента и обновление заказа. Это сага: у каждого шага есть компенсация. Ключевое понятие — точка невозврата (pivot transaction). До возврата денег шаги можно отменить, после него письмо клиенту и обновление заказа нужно довести до конца, сколько бы ретраев ни понадобилось. Каждое действие получает ключ идемпотентности, например id решения, и платёжка не спишет деньги повторно.

ЖХ
Жемал Хамидун — CPO Alpina Digital, продакт-менеджер AlpinaGPT. Делает AI-продукты с 2019 года. Hamidun News — pet project, который вырос в production-агрегатор с 6000+ читателей.
✦ Закрытый клуб практиков · Vibe Club

Внедряйте ИИ быстрее рынка вместе с инженерами и фаундерами

Внутри Vibe Club (hamidun.com/club): еженедельные живые мастермайнды и разборы архитектуры с Жемалом Хамидуном, закрытый Tech Radar, LMS и обновляемая база из 370+ боевых скиллов.

Вступить в Vibe Club →Тест-драйв Академии (72ч)
Что вы думаете?
Загружаем комментарии…