Разбирая записи конференции GoCloud под свои статьи, натолкнулся на интересную мысль про внедрение беспилотных поездов: “мы оставляем человека в контуре, и при любом сомнении система принимает безопасное решение – тормозит или останавливает, а человек уже должен принять окончательное решение”.
Нюанс в последовательности: система сначала снижает риск своими силами и только потом зовет человека. Тот подключается, когда система уже сбила непосредственный риск, и решает менее алертно.
У AI-агентов такой контур называют Human-in-the-loop (HITL), и один из его вариантов выглядит так: выполнение приостанавливают перед чувствительным действием и отдают решение человеку. Но пауза отвечает только за то, кто дергает стоп-кран, и ничего не говорит про системы, куда агент уже успел сходить.
Допустим, агент оформляет возврат клиенту и в этом процессе 12 шагов. На 7-м система замечает, что агент отклонился от ожидаемого хода, и останавливает его.
К этому моменту агент успел поменять статус обращения в CRM и отправить клиенту письмо с обещанием вернуть деньги. Сам платеж еще не запущен, но процесс завис посередине: клиент ждет денег, а доделать некому.
У поезда торможение хотя бы гасит кинетическую энергию и убирает главный источник опасности, пусть даже остановка на оживленном перегоне сама создает проблемы. У агента не рассеивается ничего: отправленное письмо останется отправленным, а статус в CRM сам не откатится.
Поэтому кажется, что безопасное состояние надо определять для всего процесса, а не для отдельного шага. После “нажатия на тормоз” должно быть заранее понятно, что агенту разрешено читать, куда запрещено писать, какие действия можно компенсировать и в какой момент управление переходит к человеку. Статуса STOPPED для этого мало.
И сам переход должен оставлять след: что уже ушло наружу, какое действие прервали или собирались сделать следующим и почему сработала остановка. Пишет этот след среда выполнения, а не остановленный агент.
Как говорил один мой коллега, “все уже придумано в Симпсонах”. OpenAI Agents SDK может поставить агента на паузу перед чувствительным действием, сохранить ход работы, дождаться решения человека и продолжить. Но такая пауза сама не отменит уже отправленное письмо или изменение в CRM.
В LangGraph после ответа человека прерванный шаг запускается с начала. Код перед вопросом выполнится снова, поэтому письмо может уйти второй раз. Необратимое советуют выполнять после одобрения или выносить в отдельный шаг.
OWASP рекомендует предусматривать прерывание и откат операций агента. А в июньском препринте Cordon собирают среду выполнения, которая придерживает необратимые действия, пока вся задача не зафиксирована.
Для распределенных систем задача знакома по Saga pattern: если один из шагов срывается, выполненные локальные транзакции компенсируют отдельными действиями. Но в классической саге поток и компенсации проектируют заранее, а автономный агент может выбирать следующие шаги уже по ходу. И часть внешних последствий не обратить вовсе: письмо клиенту уже прочитано, данные уже раскрыты.
Получается, шаги процесса надо заранее раскладывать по обратимости. Сначала выполнять те, которые можно отменить или безопасно повторить. Необратимые действия оставлять после проверок, насколько позволяет сам процесс.
Сама обратимость при этом зависит от момента. Письмо можно убрать из очереди, пока оно не ушло, а после доставки остается только компенсировать отдельным действием. Статус в CRM вернуть, пока по нему не приняли следующее решение. То есть состояние процесса определяется еще и тем, что успело произойти снаружи.
Есть у такого решения и цена. Железная дорога цену остановки знает и платит ее ради безопасности. У агента к простою добавятся незавершенная работа и восстановление измененных систем, и эту цену тоже надо принять заранее.
Поэтому HITL я бы проверял одним вопросом. Мы остановили агента на шаге 7 из 12. Что система приведет в порядок сама, прежде чем позвать человека?