Temporal (temporal.io) — платформа, которая хранит состояние длительного процесса и после сбоя продолжает его с того же места, поэтому ИИ-шаг с повторами и ожиданием человека описывается обычным кодом. Выбор оправдан, когда процесс живёт часами и днями, содержит вызовы внешних сервисов и обязан пережить перезапуск сервера. Если цепочка короткая и укладывается в минуту, хватит очереди задач или сценария в конструкторе.
Зачем нужен движок
Temporal записывает каждый шаг процесса в историю событий и после падения воспроизводит его, пропуская уже выполненную работу. Для ИИ-процесса это значит: результат завершённого вызова модели берётся из истории, а заново выполняется лишь прерванная попытка.
Возьмём процесс обработки возврата: клиент присылает заявку, модель готовит заключение по условиям договора, менеджер подтверждает решение, система отправляет ответ и делает запись в учёте. Между шагами проходят часы, а то и дни. Хранить такое состояние в памяти скрипта нельзя, а склеивать из таймеров и таблиц статусов тяжело. Движок берёт эту обязанность на себя.
- Процесс идёт дольше обычного запроса и переживает перезапуск сервиса.
- Есть внешние вызовы, которые сбоят: модель, почта, учётная система.
- На каком-то шаге нужно ждать решения человека.
- Нужен журнал, по которому видно, что происходило с каждой заявкой.
Есть и ещё один критерий, касающийся владельца процесса. Кто отвечает за заявку, пока она висит в ожидании? Кто получает сообщение, когда все попытки исчерпаны? Движок хранит состояние, однако назначать людей на эти роли приходится вам. Без ответа на оба вопроса даже безупречно настроенный процесс остановится на первом сбое и тихо повиснет.
Если подходит один пункт, чаще хватает более простых средств. Для коротких сценариев с готовыми узлами посмотрите разбор n8n workflows. Когда пунктов три или четыре, а процесс затрагивает деньги или обязательства перед клиентом, надёжность хранения состояния становится главным аргументом.
Workflow и Activity
В Temporal процесс разделён на два слоя. Workflow — код, который описывает последовательность шагов и ветвления. Activity — отдельные действия с внешним миром. По документации, вызовы API, запросы к базе и обращения к языковой модели относятся именно к Activity, потому что их результат записывается один раз и затем переиспользуется. Сам Workflow обязан быть детерминированным: время берётся из контекста процесса, а паузы задаются средствами самого Temporal.
| Слой | Что в нём живёт | Типичный сбой |
|---|---|---|
| Workflow | Порядок шагов, условия, ожидание сигнала, таймеры | Случайные значения и системное время внутри кода |
| Activity: модель | Запрос к языковой модели и разбор ответа | Таймаут, превышение лимитов, ответ вне схемы |
| Activity: учёт | Запись в CRM или 1С после подтверждения | Недоступность сервиса, отказ в правах |
| Activity: почта | Отправка ответа клиенту | Временный отказ получателя |
Разделение полезно ещё и тем, что Activity тестируются отдельно. Вызов модели проверяется на наборе тестовых заявок без запуска всего процесса, а Workflow проверяется с подставными Activity, которые возвращают заранее заданные ответы. Так ошибки логики процесса и ошибки модели остаются раздельными, а сбой легко локализовать. Практическое следствие для ИИ-шага: промпт, вызов модели и разбор ответа выносятся в Activity целиком. Рассуждать о смысле ответа внутри Workflow нельзя, там только решения вида «ответ прошёл проверку схемы, идём дальше». Проверку формата выполняет код, модель к ней непричастна, и полные данные заявки обрабатывает скрипт, который передаёт модели лишь нужный фрагмент.
Повторы вызова
Для Activity повторы включены изначально: по документации, при сбое Temporal пробует снова с нарастающей паузой, а предельного числа попыток по умолчанию нет. Целый Workflow по умолчанию автоповтора лишён: повтор той же логики дал бы тот же сбой. Политику повторов настраивают: начальный интервал, множитель паузы, максимум попыток и список ошибок, повторять которые бессмысленно.
Ошибки модели делятся на два рода. Временные — таймаут, перегрузка, ограничение частоты — хорошо лечатся паузой и новой попыткой. Постоянные — слишком длинный вход, запрет по политике, ответ вне ожидаемой схемы — повтор бесполезен, их помечают как неповторяемые и отправляют на разбор человеку. Бесконечные попытки к платному сервису дают растущий счёт без пользы, поэтому предел задайте явно. Для ИИ-шага полезен и общий срок: если заключение за разумное окно отсутствует, заявка уходит менеджеру в ручную обработку с пометкой о причине.
Отдельно подумайте об идемпотентности. Повтор Activity может выполнить действие второй раз, если первое успело пройти, а подтверждение потерялось. Операции с последствиями, например отправку письма, защищайте ключом запроса: сервер получателя отличает дубль от нового действия. Эту же мысль, применительно к входящим событиям, мы разбирали в статье про защиту n8n webhooks от повторов.
Какой шаг вашего процесса чаще всего падает на внешнем вызове?
Ожидание человека
Подтверждение менеджера в Temporal оформляется через сигналы. Документация описывает сигнал как асинхронное сообщение в работающий процесс: его можно отправить из клиента, из командной строки или из другого Workflow. Процесс дошёл до шага согласования, сохранил состояние и ждёт, а воркер тем временем освобождается для других заявок. Менеджер нажимает кнопку во внутреннем интерфейсе, сервис отправляет сигнал с решением, и процесс продолжается ровно с этого места.
- Модель готовит заключение по заявке, Activity возвращает структурированный результат и ссылку на источники.
- Процесс публикует карточку согласования в интерфейсе менеджера и переходит в ожидание сигнала.
- Менеджер видит заключение рядом с исходными фактами, принимает или отклоняет его и пишет причину.
- Сервер проверяет права менеджера на это решение, и только затем отправляется сигнал.
- Процесс записывает итог в учётную систему отдельной Activity и закрывает заявку.
Что показывать менеджеру на карточке? Заключение модели, исходные фрагменты заявки, ссылку на пункт договора и кнопки решения с обязательным полем причины. Полный текст переписки скрипт подгружает по требованию, а модель получает только необходимый кусок. Следите за сроком ожидания. Если менеджер молчит, добавьте таймер: напоминание, передача коллеге, эскалация руководителю. Решение модели остаётся предложением до сигнала, а право подтверждать проверяет сервер, поэтому защиту от подмены сигнала обеспечивают доступ к вашему интерфейсу и к самому кластеру: закройте оба.
Что видно потом
История событий хранит весь путь заявки: какие Activity запускались, сколько попыток потребовалось, когда пришёл сигнал, чем закончился процесс. Это готовая основа для разбора спорного случая: сотрудник спрашивает, почему клиенту отправили именно такой ответ, и по истории видно заключение модели, версию инструкции и фамилию подтвердившего. Тексты заявок в истории оказываются реальными данными, поэтому доступ к интерфейсу ограничьте и обезличивайте всё лишнее до записи.
Изменения кода процесса требуют аккуратности. Запущенные процессы воспроизводятся по старой истории, поэтому правка порядка шагов в Workflow без учёта версий ломает воспроизведение. Менять промпт или модель внутри Activity безопаснее, хотя и тут решение записывают вместе с версией инструкции, и такие правки удобно проверять набором тестовых заявок, как в статье про состояние и восстановление в LangGraph.
Помните о границах применимости. Платформа требует развёртывания кластера или облачной подписки, а команде нужны навыки работы с воркерами. Для небольшого отдела, где заявок немного, это избыточно. Если вы выбираете между вариантами, начните с карты процесса и обсудите её с нами на странице про автоматизацию бизнес-процессов.
Нарисуйте процесс на листе и отметьте три точки: где он ждёт человека, где зовёт внешний сервис, где пишет в учётную систему. Если каждая точка требует отдельной политики повторов и ответственного, процесс созрел для движка. Если точек одна-две, откройте более лёгкий инструмент.