Когда в агенте становится больше десяти шагов, инструкция в стиле «сделай всё возможное» ломается. Агент путается в условиях, вызывает не те инструменты, теряет контекст между ветками. Action-Based Workflow Engine — это способ вынести всю механику в набор независимых действий, а агенту оставить только выбор: какое действие и когда вызвать. Паттерн лежит в основе n8n, Zapier, GitHub Actions и любых систем, где шаги переиспользуются в разных сценариях.
Для AI-агента это особенно важно: модель сама решает, какое действие вызвать, но сами действия описаны заранее как типизированные функции с понятной схемой параметров. В результате система остаётся предсказуемой даже при десятках шагов.
Что это
Action-Based Workflow Engine — это архитектурный паттерн, в котором вся логика системы разбивается на атомарные действия. Каждое действие делает ровно одну вещь, имеет имя, описание, схему параметров и функцию-обработчик. Агент (или внешний оркестратор) выбирает действия из набора и вызывает их по цепочке, параллельно или по условию.
Главное отличие от процедурного подхода — каждое действие независимо. Его можно вызвать из любого места, переиспользовать в другом сценарии и тестировать отдельно. В большом агенте это превращает «кашу из условий» в читаемый набор операций, которые видно по именам.
Ключевое правило: действие — это одна функция с одной зоной ответственности. Если в обработчике появляется второе «и» («прочитать страницу и сразу обновить статус») — это два действия.
Зачем нужно
- Когда шагов становится больше 5–10. Агент уже не может держать их все в одной инструкции без потери контекста.
- Когда одни и те же операции повторяются в разных сценариях. Например, чтение карточки нужно и в обработке заявок, и в модерации, и в аналитике.
- Когда нужна прозрачная отладка. Каждое действие логирует вход, выход и ошибку — видно, на каком шаге сломалось.
- Когда хочется добавлять новые операции без переписывания агента. Достаточно зарегистрировать новое действие в наборе.
- Когда нужна типобезопасность. Схема параметров действия фиксирует типы — модель не передаст строку вместо объекта.
Как устроено
Любое действие описывается четырьмя обязательными параметрами:
name — уникальный идентификатор. Используется как ключ при вызове из оркестратора и как имя в логах. Примеры: read\_page, send\_message, update\_status.
description — что делает действие и зачем оно нужно агенту. Этот текст уходит прямо в контекст LLM, поэтому от его качества зависит, правильно ли модель выберет действие.
parameters — схема входных данных с типами и описаниями каждого поля. Модель использует её, чтобы заполнить параметры корректно.
handler — функция, которая выполняет логику. Принимает типизированные параметры, возвращает результат, который добавляется в контекст для следующего шага.
Пример регистрации на TypeScript:
const actions = {
read_notion_page: {
name: "read_notion_page",
description: "Прочитать страницу Notion по URL и вернуть содержимое в виде markdown",
parameters: {
url: { type: "string", description: "URL страницы Notion" }
},
handler: async ({ url }) => {
const pageId = extractId(url);
return await notionClient.pages.retrieve({ page_id: pageId });
}
},
send_telegram: {
name: "send_telegram",
description: "Отправить сообщение в указанный Telegram-чат",
parameters: {
chat_id: { type: "string", description: "ID чата или канала" },
text: { type: "string", description: "Текст сообщения" }
},
handler: async ({ chat_id, text }) => {
return await telegram.sendMessage(chat_id, text);
}
}
};
Оркестратор устроен как цикл:
- Агент получает задачу и текущий контекст.
- LLM выбирает одно или несколько действий из набора и заполняет параметры по схеме.
- Действия выполняются — последовательно, параллельно или по условию. Результат добавляется в контекст.
- LLM снова анализирует состояние: задача завершена или нужно ещё действие.
- Цикл повторяется до завершения задачи или до достижения лимита шагов.
Когда использовать
Режимы выполнения:
- Последовательно (chain). Каждое действие запускается только после завершения предыдущего. Простой и предсказуемый поток — подходит для большинства пайплайнов.
- Параллельно (parallel). Несколько действий запускаются одновременно, результаты собираются после. Ускоряет выполнение, но требует аккуратной балансировки нагрузки и отсутствия зависимостей между шагами.
- По условию (conditional). Агент выбирает следующее действие в зависимости от результата предыдущего. Например, если парсинг вернул ошибку — попробовать обходной маршрут через резервный парсер.
Когда паттерн оправдан:
- Агент выполняет больше 5–10 разных шагов.
- Разные действия повторяются в разных сценариях.
- Нужна прозрачность в отладке — понятно, на каком шаге сломалось.
- Несколько разработчиков работают над одним агентом — действия изолированы и не конфликтуют.
Когда паттерн избыточен:
- Агент делает 2–3 действия — достаточно простой инструкции без формального набора.
- Все шаги линейны и никогда не переиспользуются — выделение в отдельные действия добавит бюрократию без выгоды.
- Логика меняется каждый запуск — динамическая регистрация действий съест больше времени, чем сэкономит.
Пример
Контент-агент, который обрабатывает новые задачи из Notion-инбокса, может использовать пайплайн из десяти действий:
read_inbox_card
→ check_status # проверить, что карточка новая
→ set_status_processing # статус → «В обработке»
→ read_source_url # прочитать исходную страницу
→ classify_content # определить целевую базу
→ write_draft # написать черновик
→ create_page # создать страницу в CMS
→ link_result # привязать результат к инбокс-карточке
→ set_status_done # статус → «Обработан»
Каждый шаг — отдельная функция со своей схемой параметров. Если что-то сломалось, легко понять, на каком именно шаге это произошло: достаточно открыть лог выполнения и найти первое действие со статусом failed.
Ограничения
Ограничения
Что учитывать
Несколько практических нюансов, которые всплывают при росте числа действий.
Рост описаний действий — каждое описание уходит в контекст LLM.
После 30–40 действий контекст раздувается, и модель начинает путаться. Решение — группировка или динамическая подгрузка.
Стоимость токенов — на длинных сценариях расход растёт заметно. Каждый цикл «выбор
→ выполнение → анализ» добавляет в историю все описания действий.
Зависимость от качества описаний — если description расплывчатое, модель будет выбирать не то действие или передавать не те параметры.
Это самая частая причина «странного» поведения агента.
Холодный старт новых действий — модель не «узнаёт» действие, пока не увидит его в контексте.
Новые операции нужно либо подробно описывать, либо давать примеры использования в description.
Безопасность handler’ов — handler выполняется «как есть», без песочницы.
Любая ошибка в обработчике ломает весь пайплайн, поэтому обработчики нужно писать защищённо и логировать подробно.
Антипаттерны
Антипаттерны
Чего не делать
Частые ошибки при проектировании набора действий.
Не делать: объединять несколько операций в одно действие «для краткости».
«Прочитать страницу и сразу обновить статус» — это два действия, иначе теряется переиспользуемость.
Не делать: передавать в параметрах сырые большие объекты (HTML-страницы, JSON-документы целиком).
Лучше передавать идентификатор, а содержимое читать внутри handler’а.
Не делать: держать описание действия короче одной строки.
Если модель не понимает, зачем действие и когда его вызывать, она выберет не то действие или пропустит нужное.
Не делать: регистрировать 80 действий «на вырост».
При росте числа действий модель начинает путаться. Лучше группировать по доменам или подгружать по контексту.
Не делать: обрабатывать ошибки внутри handler’а «молча».
Если действие упало — это должно быть видно в результате и попадать в контекст для следующего шага.
Чеклист
Чеклист
Проверка перед запуском
Перед тем как отдать агент в работу, пройдитесь по этим пунктам.
Каждое действие делает одно
— нет составных операций с «и» в описании.
Описание содержит когда применять
— модель должна понимать, в каком сценарии действие уместно.
Схема параметров типизирована
— каждый параметр имеет тип и пояснение.
Логирование входа и выхода
— на каждом handler’е есть трассировка, по которой видно, что и зачем вызвалось.
Лимит шагов задан
— оркестратор не зациклится, если модель не придёт к выводу о завершении.
Тест на 2–3 сценариях прошёл
— пайплайн отрабатывает ожидаемо хотя бы на коротких сценариях, прежде чем идти в прод.
Ссылки
Ссылки
- OpenAI Function Calling — ближайший аналог для одиночных действий в LLM: https://platform.openai.com/docs/guides/function-calling
- Anthropic Tool Use — аналогичная концепция с описанием инструментов: https://docs.anthropic.com/en/docs/build-with-claude/tool-use/overview