Phase: почему мы сделали именно так

от автора

Мы с партнёром @skazkin разработали концепцию Phase — архитектурный подход к построению бизнес‑систем с ИИ‑агентами. В этом тексте я рассказываю, почему были приняты те или иные архитектурные решения. Для каждого ключевого решения перед его выбором мы рассматривали разные альтернативы.

Полную концепцию Phase мы опубликовали отдельно — читать здесь. Дальше я буду опираться на её понятия.

Почему вообще понадобилась концепция

Мы используем агентский подход к разработке и одновременно встраиваем агентов в операционные процессы предприятий. В этом пересечении быстро обнаружилась проблема: существующие платформы — BPM, low‑code, ERP — создавались до эпохи ИИ.

Приходится как‑то интегрировать агентов к существующим системам, вызывать LLM на нужных шагах, делать это по‑разному в каждом проекте.

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

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

Решение 1: объект, а не процесс

Альтернатива: процессный слой поверх объектов — стандартное решение в BPM и workflow‑системах. Это то, то часто применяется в бизнесе.

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

Мы от него отказались. Причин две.

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

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

Нам показалась правильнее применять единую базовую модель для описания бизнес‑процессов — модель изменения состояния объекта: не граф шагов, а объект, который меняется. Договор не «проходит процесс согласования» — договор меняет состояние. Мы выбрали это в качестве единицы системы.

Но «состояние объекта» и «статус объекта» — термины, которые уже широко применяются сейчас в системах и нагружены разными смыслами. Нам же хотелось термин, в котором смысл не будет размытым. Мы хотели выбрать термин, с помощью которого мы будем описывать: деление деятельности на логические части в целях управления. Для целей управления мы не описываем данным движком все активности внутри бизнеса — мы выбираем, где провести границы, чтобы в каждой части было понятно, кто отвечает, что происходит и каков критерий завершения. Поразмыслив, мы выбрали для описания такой части в границах термин фаза. Данный термин сейчас не используется активно в описании бизнеса, и можно ему придать однозначность значения.

Фаза — выделенная часть деятельности бизнеса, логически связанная с объектом управления.

Итого: систему мы рассматриваем как набор объектов, которые меняются. Объекты всегда находятся в какой‑то фазе. Изменение объекта — это смена его фазы. Бизнес‑процесс программируется описанием того как объекты меняют фазы и порождают друг друга. Но отдельного процессного слоя нет.

Объект не проходит процесс - он меняет состояние. Фаза - это намеренно выбранная граница, за которой стоит конкретный ответственный и критерий завершения

Объект не проходит процесс — он меняет состояние. Фаза — это намеренно выбранная граница, за которой стоит конкретный ответственный и критерий завершения

Решение 2: три примитива, не больше

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

BPMN насчитывает несколько десятков типов элементов. Temporal позволяет описывать логику произвольным кодом. Это очень гибко, и позволяет решать любую задачу.

Но мы выбрали другой подход. Мы выбрали бедный в элементах подход. В Phase три примитива: фазапорождениеподписка. Больше ничего нет.

Про фазу уже сказано выше. Почему именно порождение и подписка — и почему этого будет достаточно?

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

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

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

Вместе фаза, порождение и подписка покрывают три фундаментальных вопроса о любом бизнес‑объекте: в каком он состоянии, что из него возникает, на что он реагирует.

Почему так мало? Потому что систему будет программировать ИИ‑агент. У агента профиль ограничений, противоположный человеческому: ему не нужно удерживать всё в памяти, но ему критична однородность. Один простой паттерн он воспроизводит в сотнях экземпляров без ошибок. Десять разных конструкций для схожих ситуаций заставляют его выбирать — и он начинает ошибаться. Мы это видим на практике, когда программируем с ИИ.

Решение 3: подписка, а не событийная шина

Альтернатива: события на шине — объект публикует событие, подписчики слушают. Стандартная event‑driven архитектура.

Шина событий — хорошо известный и масштабируемый паттерн. Мы его не выбрасывали: шина в Phase есть и используется для транспорта. Но мы не сделали её основным механизмом взаимодействия между объектами.

Причина: у шины событий проблема с проведением анализа. Когда объект публикует событие, подписчики разбросаны по системе — и заранее неизвестно, кто и как отреагирует. Цепочку реакций нельзя отследить статически, без запуска системы.

Мы хотели другого. Подписка в Phase — декларативна и хранится в конфигурации объекта‑подписчика. Это значит: зная конфигурации типов объектов, можно построить полный граф зависимостей и проверить его до запуска. «Что произойдёт в системе, если Заказ перейдёт в фазу Отгружен?» — это вопрос со статическим ответом, а не вопрос, который можно выяснить только запустив систему.

Для автономной системы это принципиально. Чем больше агентов в контуре, тем важнее предсказуемость поведения без прогона.

Решение 4: три типа полей, не один

Альтернатива: поле — просто поле. Кто угодно пишет, что хочет. Ограничения — через логику приложения.

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

Мы разделили поля на три типа по источнику изменения: system (сигналы интеграций, планировщик), agent (ИИ‑агент), user (сотрудник). Это не техническая деталь — это архитектурное решение о том, кто несёт ответственность за значение.

Три потока данных - из реального мира, от агента, от человека - сходятся в одном месте для принятия решения.

Три потока данных — из реального мира, от агента, от человека — сходятся в одном месте для принятия решения.

Зачем это нужно?

По имени и типу поля сразу понятно, откуда оно берётся: оплата_получена — system, это сигнал из банковской интеграции; риск_клиента — agent, это оценка агента; одобрено_менеджером — user, здесь нужно действие человека. Схема объекта становится читаемым контрактом.

Это основа для симметрии агента и сотрудника. Движок при проверке условий перехода к типам слеп — он проверяет только значение поля. Само разделение на типы делает понятным, чья ответственность за каждое значение. При аудите сразу видно, кто принял решение.

И наконец, это механизм управления автономией. Хочешь убрать человека из условия перехода — переводишь user‑поле в agent‑поле. Изменение конфигурации, не переписывание кода. (Подробно про это — в решении 10.)

Решение 5: условие — проверка, не вычисление

Раз объект меняет фазы, нужно определить, когда именно происходит переход. В Phase у каждой фазы есть условие выхода — набор проверок полей объекта, при выполнении которых движок переводит объект в следующую фазу.

Альтернатива: условие перехода — произвольное выражение: можно вызвать функцию, агрегировать, считать.

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

Мы это закрыли. Условие в Phase — только проверка значений полей: равенство, сравнение, заполненность. Никаких вычислений, никаких вызовов.

Всё, что требует вычисления — сумма по позициям, оценка риска, признак просрочки — вычисляется участником: агентом, адаптером, дочерним объектом — и фиксируется в поле. Условие читает поля, а не считает их.

Зачем это ограничение? Два следствия. Первое: условие перехода всегда можно прочитать вслух — «оплата получена и риск ниже порога» — и это чтение в точности совпадает с тем, что проверит движок. Для ИИ‑агента это невозможность ошибиться в семантике: нет функций, нет побочных эффектов. Второе: таблица переходов с простыми условиями — математический объект. До запуска системы можно механически проверить достижимость каждой фазы, отсутствие фаз‑ловушек, соблюдение инвариантов. С произвольным кодом в условиях это невозможно.

Решение 6: два слоя внутри фазы

Альтернатива: поля объекта — просто текущее состояние. История — в отдельном логе, если вообще нужна.

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

В Phase мы явно разделили два слоя. Поток фактов — неизменяемая хроника всего, что произошло в фазе: каждый сигнал, каждое действие агента, каждое решение сотрудника. Дистиллят — поля объекта, наилучшее доступное знание на текущий момент.

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

Следствие: поле оценка_риска может обновиться три раза за время пребывания объекта в фазе — каждый раз, когда человек или агент получил новые данные и пересмотрел оценку. Движок проверяет условие перехода после каждого обновления — и переходит ровно тогда, когда накопленная картина достигла порога.

Решение 7: временной разрыв как явная часть модели

Альтернатива: система знает текущее состояние объекта. Точка.

Классическое допущение в большинстве систем: поле содержит актуальное значение. Работать с давностью данных — не задача движка.

Мы отказались от этого допущения. В Phase каждое поле хранит не только значение, но и время, когда это знание было актуальным. Цифровая модель — это наилучшее доступное знание о реальном объекте, а не абсолютная истина о нём.

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

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

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

Решение 8: управление адаптацией теми же примитивами

Цель предприятия, изменение конфигурации системы, стратегическая инициатива — это тоже объекты с жизненным циклом, фазами и участниками. Ничто не мешает описать их тем же механизмом.

Альтернатива: отдельный привилегированный слой для управления системой — панель администратора, релиз кода, ручная миграция.

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

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

Решение: изменение конфигурации — это обычный объект Phase. Его поля содержат предлагаемую версию конфигурации и результаты проверок. Его жизненный цикл — предложено → проверено → одобрено → применено. Статический анализ таблицы переходов заполняет поля проверок автоматически. Одобрение человека — user‑поле в условии перехода.

То же самое с целями: цель предприятия — обычный объект Phase. Его агентское поле — оценка траектории, его system‑поле — текущее значение метрики, его user‑поле — целевой ориентир от владельца. Отклонение от цели — условие фазового перехода, при котором цель порождает корректирующие объекты.

Следствие: степень контроля над самоизменением системы — тоже конфигурация. Сначала каждое изменение одобряет инженер; накопив доверие, рутинные правки система применяет автономно, а структурные — всегда подтверждает человек.

Решение 9: симметрия человека и агента

Альтернатива: отдельный механизм для агента — специальный «шаг агента», отдельный тип узла в процессе, отдельный API.

Большинство систем, которые добавляют ИИ‑агента в процесс, делают это через выделенный узел: «здесь работает агент, здесь — человек». Это явное разделение выглядит логично.

Мы пошли в другую сторону. В Phase нет специального «шага агента» и специального «шага человека». Оба работают через один механизм: записывают значение в поле. Разница только в типе поля. Движок при проверке условия перехода не различает, чья это запись — он смотрит только на значение.

Почему так? Выделенный «шаг агента» — это архитектурное решение о том, кто принимает решение. А мы хотели, чтобы это было конфигурационное решение, а не архитектурное. Сегодня это поле заполняет человек, завтра — агент. Если механизм один, это просто смена типа поля. Если механизмы разные — это переработка архитектуры.

Но симметрия механизма — только одна сторона. Есть вторая, не менее важная: симметрия информации. Человек и агент должны принимать решения на одних и тех же данных.

На практике это означает требование к поведению человека: если сотрудник знает что‑то, что влияет на решение — прошлый опыт с клиентом, неформальную договорённость, интуитивную оценку — он обязан внести это в поля объекта до принятия решения. Не держать в голове, не учитывать молча. Если знание не зафиксировано, агент его не видит, аудит его не фиксирует.

Это требование выглядит как ограничение для человека — и так и есть. Но только оно делает симметрию реальной.

Решение 10: автономия как конфигурация, а не архитектура

Альтернатива: степень участия агента фиксируется при проектировании системы.

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

Мы хотели возможности менять степень участия человека или агента без переработки кода, постепенно, по мере накопления доверия к агенту.

Это стало следствием симметрии из решения 9. Раз человек и агент работают через один механизм, управление балансом между ними сводится к одному вопросу: чьё поле стоит в условии перехода. Условие включает user‑поле — переход ждёт человека. Убрали user‑поле, оставили agent‑поле — переход происходит по решению агента.

На практике это управляемая кривая передачи полномочий. Команда начинает с режима «агент предлагает, человек подтверждает»: агент заполняет своё поле, человек подтверждает своим. Накопили данные, убедились в качестве решений — убрали user‑поле из условия перехода. Агент теперь действует самостоятельно на этом шаге. Следующий шаг — та же процедура.

Решение 11: обучающие данные как побочный продукт

Альтернатива: отдельный процесс сбора и разметки данных для улучшения агентов.

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

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

Эта структура появляется как следствие того, что система просто работает. Никакой отдельной разметки не нужно.

Система работает -> фиксирует решения и исходы -> агент улучшается -> принимаются больше решений без участия человека -> генерируется больше данных

Система работает → фиксирует решения и исходы → агент улучшается → принимаются больше решений без участия человека → генерируется больше данных

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

Что осталось открытым

Phase — концепция, не готовый движок. Мы сейчас работаем над реализацией Phase Engine. Несколько вещей остаются вопросами реализации, а не концепции.

Язык условий. Мы описали его минималистично: равенство, сравнение, заполненность, логические связки. Достаточно ли этого для всех реальных случаев — покажет практика. Подозреваю, что в каких‑то сценариях нам не хватит, но пока не видели таких случаев.

Производительность каскадов. Когда дочерний объект обновляет родителя, а тот — своего родителя, цепочка переходов может быть длинной. Движок гарантирует атомарность каждого отдельного перехода — но каскад занимает время. Насколько это проблема в реальных сценариях — вопрос нагрузочного тестирования, которого у нас пока нет.

Граница разработчика и инженера. Разработчик строит словарь возможного (типы объектов, системные поля, инструменты), инженер собирает из него поведение (конфигурации фаз, условия переходов, агентские поля). Где именно проходит эта граница в конкретных реализациях — предстоит уточнять.

Конечно, открытых вопросов много больше, чем три. Но эти три мы выделили как для себя как наиболее важные.


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

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

Полную концепцию Phase мы опубликовали отдельно — phaseconcept.tech.

ссылка на оригинал статьи https://habr.com/ru/articles/1053756/