Создание Workflows
Это руководство охватывает создание workflow с нуля, включая типовые паттерны, циклы валидации и лучшие практики.
Быстрый старт
- Определите цель workflow и основные этапы 2. Спроектируйте структуру графа узлов 3. Создайте JSON с правильными определениями узлов 4. Проверьте связи и достижимость 5. Сохраните через MCP tools
Структура Workflow
Каждый workflow должен содержать:
{ "id": "my-workflow", "metadata": { "name": "Читаемое название", "version": "1.0.0", "description": "Что делает этот workflow" }, "nodes": [ // start узел (ровно один) // action узлы // condition узлы (для ветвления) // end узел (минимум один) ]}Типовые паттерны
Цикл валидации
Используйте когда нужно проверить результат и повторить при ошибке:
flowchart LR
A[action] --> B[check]
B -->|success| C[next]
B -->|failure| D[fix]
D --> E[increment-iteration]
E --> A
{ "id": "do-work", "type": "agent-directive", "directive": "Выполни задачу", "completionCondition": "Задача выполнена", "inputSchema": { "type": "object", "properties": { "result_valid": { "type": "string", "enum": ["yes", "no"] } }, "required": ["result_valid"] }, "connections": { "success": "check-result" }},{ "id": "check-result", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "result_valid" }, "right": "yes" }, "connections": { "true": "next-step", "false": "fix-issues" }},{ "id": "fix-issues", "type": "agent-directive", "directive": "Исправь найденные проблемы", "connections": { "success": "increment-iteration" }},{ "id": "increment-iteration", "type": "agent-directive", "directive": "Увеличь счетчик итераций", "inputSchema": { "type": "object", "properties": { "iteration": { "type": "number" } }, "required": ["iteration"] }, "connections": { "success": "do-work" }}Разделяйте ответственность: action узлы ВЫПОЛНЯЮТ работу, check узлы ТОЛЬКО проверяют, fix узлы ТОЛЬКО исправляют. Используйте счетчики итераций для предотвращения бесконечных циклов.
Ветвление по типу действия
Используйте когда workflow имеет разные пути для разных сценариев:
{ "id": "get-action", "type": "agent-directive", "directive": "Спроси пользователя: создать новый или редактировать существующий?", "inputSchema": { "properties": { "action": { "type": "string", "enum": ["create", "edit"] } }, "required": ["action"] }, "connections": { "success": "route-action" }},{ "id": "route-action", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "action" }, "right": "create" }, "connections": { "true": "create-branch", "false": "edit-branch" }}Gate подтверждения
Используйте для критических действий требующих подтверждения:
{ "id": "show-plan", "type": "agent-directive", "directive": "Представь план пользователю и спроси подтверждение", "inputSchema": { "properties": { "approved": { "type": "string", "enum": ["yes", "no"] }, "feedback": { "type": "string" } }, "required": ["approved"] }, "connections": { "success": "check-approval" }},{ "id": "check-approval", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "approved" }, "right": "yes" }, "connections": { "true": "proceed", "false": "revise-plan" }}Паттерны Input Schema
Ответ Да/Нет
{ "inputSchema": { "type": "object", "properties": { "result": { "type": "string", "enum": ["yes", "no"] }, "details": { "type": "string" } }, "required": ["result"] }}Числовой счетчик
{ "inputSchema": { "type": "object", "properties": { "count": { "type": "number", "minimum": 0 }, "total": { "type": "number", "minimum": 1 } }, "required": ["count", "total"] }}Массив элементов
{ "inputSchema": { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "string" }, "minItems": 1 } }, "required": ["items"] }}Выбор из нескольких вариантов
{ "inputSchema": { "type": "object", "properties": { "action": { "type": "string", "enum": ["create", "edit", "delete", "cancel"] }, "reason": { "type": "string" } }, "required": ["action"] }}Путь к файлу с паттерном
{ "inputSchema": { "type": "object", "properties": { "file_path": { "type": "string", "pattern": "^[a-zA-Z0-9/_.-]+\\.(json|yaml|yml)$" } }, "required": ["file_path"] }}Операторы условий
| Оператор | Описание | Пример |
|---|---|---|
eq | Равно | "right": "value" |
neq | Не равно | "right": "value" |
lt | Меньше | "right": 10 |
gt | Больше | "right": 0 |
lte | Меньше или равно | "right": 100 |
gte | Больше или равно | "right": 1 |
and | Логическое И | "conditions": [...] |
or | Логическое ИЛИ | "conditions": [...] |
exists | Переменная существует | — |
isEmpty | Массив/строка пусты | — |
Пример сложного условия
{ "condition": { "operator": "and", "conditions": [ { "operator": "eq", "left": { "contextPath": "status" }, "right": "ready" }, { "operator": "gt", "left": { "contextPath": "count" }, "right": 0 } ] }}Объявление знаний как глобальных переменных
Объявляйте переиспользуемые знания как глобальные переменные в variableRegistry workflow со значением default:
{ "variableRegistry": { "quality_rules": { "type": "string", "description": "Переиспользуемые правила качества, применяемые агентом на шагах", "default": "Правило 1: ... Правило 2: ..." }, "validation_checklist": { "type": "string", "description": "Чеклист, который агент проверяет перед завершением шага", "default": "Проверка 1: ... Проверка 2: ..." } }}Обращение в директивах:
{ "directive": "Следуй этим правилам: {{quality_rules}}"}Это делает workflow самодокументируемым. Все знания встроены, внешняя документация не нужна.
Чеклист валидации
Перед сохранением проверьте:
-
Структура
- Ровно один start узел
- Минимум один end узел
- Все ID узлов уникальны
- Все connections указывают на существующие узлы
-
Достижимость
- Все узлы достижимы от start
- Нет orphan узлов
- Все пути ведут к end
-
Определения узлов
directiveне пустойcompletionConditionопределенconnections.successуказанinputSchema— валидный JSON Schema
-
Условия
trueиfalseconnections определены- Оператор валиден
Сохранение Workflows
Создать новый
mcp__moira__manage({ action: "create", workflow: { id: "my-workflow", metadata: { name: "...", version: "1.0.0", description: "..." }, nodes: [...] }})Редактировать
mcp__moira__manage({ action: "edit", workflowId: "my-workflow", changes: { metadata: { version: "1.1.0" }, updateNodes: [{ nodeId: "step-1", changes: { directive: "Новый текст" } }], },});Загрузить файл
// Для агентов с доступом к файловой системеconst { uploadUrl } = await mcp__moira__token({ action: "upload" });// Загрузите JSON файл по uploadUrlОпределение возможностей агента
Разные агенты имеют разные возможности. Проектируйте workflow для определения и адаптации:
Категории возможностей
| Возможность | Примеры | Метод определения |
|---|---|---|
| Файловая система | Read, Write, создание файлов | Спросить агента |
| Web доступ | Fetch URL, поиск | Проверить наличие web tools |
| Только MCP | Только инструменты Moira | Предположение по умолчанию |
Паттерн определения
{ "id": "detect-capabilities", "type": "agent-directive", "directive": "Сообщи свои возможности: есть ли доступ к файловой системе? можешь ли получать URL?", "inputSchema": { "type": "object", "properties": { "has_file_access": { "type": "boolean" }, "has_web_access": { "type": "boolean" } }, "required": ["has_file_access", "has_web_access"] }, "connections": { "success": "route-by-capabilities" }}Условное ветвление
{ "id": "route-by-capabilities", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "has_file_access" }, "right": true }, "connections": { "true": "file-based-flow", "false": "mcp-only-flow" }}Всегда предоставляйте fallback пути для агентов с ограниченными возможностями. MCP tools доступны всегда.
Паттерн планирования
Используйте когда workflow должен создать и выполнить план с подтверждением пользователя и возможностью пересмотра.
Проблема
Workflow часто требуют этапа планирования, но:
- Планы создаются один раз и не пересматриваются
- Требования к качеству плана не формализованы
- Нет возможности адаптировать план по ходу выполнения
- Агент теряет контекст в длинных сессиях
Структура паттерна
flowchart LR
A[understand_task] --> B[decompose_into_steps]
B --> C[present_plan]
C --> D{user_approval}
D -->|approved| E[execute_steps]
D -->|rejected| F[revise_plan]
F --> C
E -->|during_execution| G[update_plan]
G --> H[reinitialize]
Ключевые компоненты
- variableRegistry.plan_writing_requirements — правила написания планов (агент видит при создании)
- decompose_into_steps — директива с
{{plan_writing_requirements}}для создания плана - user_approval_branch — approved → execute, rejected → revise_plan → present_plan
- update_during_execution — возможность адаптировать план по ходу выполнения
Требования к написанию плана
Главная проблема: агент теряет контекст (архивация сессии, простое забывание). Планы должны быть написаны так, чтобы любой шаг можно было выдать агенту БЕЗ остального плана — и он смог бы выполнить.
| Требование | Почему важно | Пример |
|---|---|---|
| Плоский линейный список | Легче отслеживать без иерархии | 1, 2, 3… не 1.1, 1.2, 1.2.1 |
| Самодостаточные шаги | Любой шаг выполним без контекста | “Шаг 3: Создать файл X.ts с функцией Y” не “Продолжить работу” |
| Явные действия | Не “как обычно”, а конкретно | “Сделать коммит” в каждом шаге где нужен |
| Измеримый результат | Легко проверить выполнение | “expected_output: файл X.ts создан и содержит функцию Y” |
| Независимость | Минимум зависимостей между шагами | Шаг 4 не должен требовать знания деталей шага 2 |
| Полные пути к файлам | Агент не должен угадывать | /full/path/to/file.json, не “в соответствующей папке” |
| Избыточность там, где применима | Повторяйте то, что пункту действительно нужно | «Сделать коммит» — в пункте, который коммитом заканчивается, а не в каждом |
Атомарность пункта (S9)
Каждый пункт плана или задачи должен быть самодостаточным. Агент часто получает директиву ОДНОГО пункта изолированно — без остального плана — поэтому пункт должен нести всё необходимое для его выполнения:
- Повторить нюансы, от которых зависит пункт.
- Повторить релевантное исходное требование внутри пункта.
- Повторить сквозное действие (отчёт о прогрессе, запуск тестов, коммит) в тех пунктах, которым оно действительно нужно.
Общего или глобального scope между пунктами нет, поэтому пункт, опирающийся на «как выше», невыполним. Ответ — то, что нужно исполнителю в одиночестве, и решается это по каждому пункту, а не безусловным дублированием: повторённый текст становится вторым источником правды и расходится, а пункт, обязанный нести всё, разрастается, пока не начинает нести сам результат. См. Обязательная избыточность каждого пункта плана.
{ "id": "execute-plan-item", "type": "agent-directive", "directive": "Execute one plan item.\n\nThe item text is self-contained: it states the original requirement, the files to read/modify with full paths, and the cross-cutting actions (run tests, make commit) that apply to THIS item.\n\nDo NOT assume any context from other items.", "completionCondition": "Item executed, tests run, and commit made as stated in the item", "connections": { "success": "next-item" }}Два связанных паттерна развивают это руководство: паттерн Replan пересматривает многошаговый план по ходу выполнения, а паттерн Completeness Self-Review проверяет каждое требование против реального артефакта перед выдачей.
Пример реализации
{ "variableRegistry": { "plan_writing_requirements": { "type": "string", "description": "Правила, которым агент следует при написании плана", "default": "ТРЕБОВАНИЯ К НАПИСАНИЮ ПЛАНА:\n\n- Плоский линейный список — без иерархии, без вложенных подпунктов, просто 1, 2, 3...\n- Один пункт = одна задача — не микрошаг ('скачать файл'), а законченная задача ('обновить workflow до v2.1.0')\n- Полная самодостаточность — содержит ВСЁ для выполнения: зачем делать, что делать, какие файлы читать/менять, куда сохранять, что коммитить\n- НЕТ отдельных 'глобальных правил' — всё нужное для пункта должно быть В пункте\n- Явные действия — не 'как обычно', а конкретно: 'загрузить на moira-local через token', 'сделать коммит'\n- Избыточность разрешена — лучше повторить 'сделать коммит' в каждом пункте, чем забыть\n- Полные пути к файлам — не 'в соответствующей папке', а /full/path/to/file.json\n- Измеримый результат — легко проверить выполнение пункта" } }, "nodes": [ { "type": "start", "id": "start", "connections": { "default": "analyze-task" } }, { "id": "decompose-into-steps", "type": "agent-directive", "directive": "Создай план выполнения задачи.\n\nСледуй требованиям: {{plan_writing_requirements}}\n\nДля каждого шага укажи:\n- Что делать (action)\n- Ожидаемый результат (expected_output)", "inputSchema": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "action": { "type": "string" }, "expected_output": { "type": "string" } }, "required": ["action", "expected_output"] } } }, "required": ["steps"] }, "connections": { "success": "present-plan" } }, { "id": "present-plan", "type": "agent-directive", "directive": "Представь план и спроси, утверждён ли он. `approved` записывает собственный ответ пользователя; без ответа записывать нечего.", "inputSchema": { "type": "object", "properties": { "plan_approved": { "type": "string", "enum": ["да", "нет"] }, "user_feedback": { "type": "string" } }, "required": ["plan_approved"] }, "connections": { "success": "check-plan-approval" } }, { "id": "check-plan-approval", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "plan_approved" }, "right": "да" }, "connections": { "true": "execute-steps", "false": "revise-plan" } }, { "id": "revise-plan", "type": "agent-directive", "directive": "Пользователь не одобрил план. Фидбек: {{user_feedback}}\n\nДоработай план на основе фидбека.\nСледуй: {{plan_writing_requirements}}", "connections": { "success": "present-plan" } } ]}Обновление плана по ходу выполнения
Для длинных workflows добавьте возможность обновить план в процессе:
{ "id": "update-plan-during-execution", "type": "agent-directive", "directive": "Обнови план по ходу выполнения.\n\nТекущий шаг: {{current_step_index}}\nПричина обновления: {{update_reason}}\n\n1. Проанализируй текущий прогресс\n2. Обнови оставшиеся шаги (не меняй завершённые)\n3. Сохрани историю в ./plan-changes-history.md\n\nСледуй: {{plan_writing_requirements}}", "connections": { "success": "reinitialize-tracking" }},{ "id": "reinitialize-tracking", "type": "agent-directive", "directive": "Реинициализируй tracking после обновления плана.\n\n1. Обнови tracking.json с новым total_steps\n2. Скорректируй current_step_index если нужно\n3. Продолжи выполнение", "connections": { "success": "execute-current-step" }}Храните план в файле (например, ./plan.md) вместо контекста для больших планов. Это
предотвращает переполнение контекста и позволяет восстановиться после архивации сессии.
Паттерн эскалации
Используйте когда workflow имеет циклы валидации которые могут застрять. Предоставляет механизм выхода после повторных неудач.
Проблема
Когда агент застревает в цикле валидации:
- Бесконечные повторы без прогресса
- Одни и те же ошибки повторяются
- Нет способа выйти из цикла
- Пользователь ждёт бесконечно
Структура паттерна
flowchart TD
A[action] --> B[validate]
B -->|fail| C[increment_retry]
C --> D{check_retry_limit}
D -->|retry < max| A
D -->|retry >= max| E[ESCALATION]
E --> F[revise_plan / ask_user / skip]
Когда применять
- Workflows с планированием (robust-task, development)
- Workflows с валидацией результатов (workflow-management, test-generation)
- Любые циклы “сделай → проверь → повтори”
Варианты эскалации
| Вариант | Когда использовать | Пример |
|---|---|---|
revise_plan | Текущий план неверен | Тесты падают из-за неправильного дизайна |
ask_user | Нужно решение человека | Неясные требования |
skip | Шаг не критичен | Опциональное улучшение |
Пример реализации
{ "id": "increment-retry", "type": "agent-directive", "directive": "Увеличь счётчик повторов. Текущий: {{step_retry}}", "inputSchema": { "type": "object", "properties": { "step_retry": { "type": "number", "minimum": 1 } }, "required": ["step_retry"] }, "connections": { "success": "check-retry-limit" }},{ "id": "check-retry-limit", "type": "condition", "condition": { "operator": "gte", "left": { "contextPath": "step_retry" }, "right": 3 }, "connections": { "true": "notify-escalation", "false": "retry-action" }},{ "id": "notify-escalation", "type": "user-notification", "message": "⚠️ *Требуется эскалация*\n\nШаг не удался после {{step_retry}} попыток.\n\nВарианты:\n- revise_plan\n- ask_user\n- skip", "format": "markdown", "connections": { "default": "ask-escalation-decision", "error": "ask-escalation-decision" }},{ "id": "ask-escalation-decision", "type": "agent-directive", "directive": "Шаг не удался после {{step_retry}} попыток.\n\nСпроси пользователя:\n1. **revise_plan** — вернуться к планированию и пересмотреть подход\n2. **ask_user** — запросить помощь человека с конкретной проблемой\n3. **skip** — пропустить этот шаг и продолжить\n\n`decision` записывает собственный выбор пользователя: каждый из трёх вариантов ведёт в своё место, поэтому предположенный ответ выбирает маршрут за него.", "inputSchema": { "type": "object", "properties": { "escalation_decision": { "type": "string", "enum": ["revise_plan", "ask_user", "skip"] }, "user_input": { "type": "string" } }, "required": ["escalation_decision"] }, "connections": { "success": "route-escalation" }},{ "id": "route-escalation", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "escalation_decision" }, "right": "revise_plan" }, "connections": { "true": "revise-plan", "false": "route-escalation-skip" }},{ "id": "route-escalation-skip", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "escalation_decision" }, "right": "skip" }, "connections": { "true": "mark-step-skipped", "false": "handle-user-help" }}Комбинация с паттерном планирования
При использовании обоих паттернов — Planning и Escalation:
flowchart LR
A[plan] --> B[execute]
B --> C[validate]
C -->|fail| D[retry]
D -->|max_retries| E[escalate]
E -->|revise_plan| A
E -->|skip| F[next_step]
E -->|ask_user| G[wait_for_input]
Вариант revise_plan возвращает к фазе Planning, позволяя агенту пересмотреть подход на основе того, что он узнал из неудач.
Устанавливайте max_retries в зависимости от сложности задачи. Простые задачи: 2-3 повтора.
Сложные задачи: 3-5 повторов. Всегда предоставляйте вариант skip для некритичных шагов.
Production паттерны
Реальные паттерны из production workflows (development-flow, 104 ноды).
Express/Full Mode ветвление
Маршрутизация в упрощённый или полный flow в зависимости от сложности:
[get-requirements] → [check-mode] → express=true → [express-flow] → express=false → [full-flow]{ "id": "check-development-mode", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "development_mode" }, "right": "express" }, "connections": { "true": "express-implementation", "false": "analyze-and-plan" }}Цикл уточнения плана
Представить план → получить фидбек → уточнить → подтвердить:
[present-plan] → [check-approval] → approved → [continue] → rejected → [refine] → [confirm] → [continue]Паттерн числовой валидации (рекомендуемый)
Проблема boolean валидации: Агенты склонны к оптимизму. На вопрос “Результат валиден? да/нет” они могут ответить “да” даже когда нашли проблемы. Это обесценивает validation loops.
Решение: Используйте числовой счётчик проблем вместо boolean. Движок механически проверяет равен ли счётчик нулю — нет места для интерпретации.
{ "id": "validate-result", "type": "agent-directive", "directive": "ТОЛЬКО ПРОВЕРЬ результат. Подсчитай найденные проблемы.", "inputSchema": { "type": "object", "properties": { "issues_count": { "type": "number", "minimum": 0, "description": "Количество найденных проблем (0 = валидно)" }, "issues": { "type": "array", "items": { "type": "string" }, "description": "Список проблем если есть" } }, "required": ["issues_count"] }, "connections": { "success": "route-validation" }},{ "id": "route-validation", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "issues_count" }, "right": 0 }, "connections": { "true": "next-step", "false": "fix-issues" }}Почему это работает:
- Агент не может соврать про число (количество объективно)
- Условие
issues_count == 0проверяется механически движком - Нет места для “почти готово” или “незначительные проблемы”
Когда использовать: ВСЕ validation loops должны использовать этот паттерн. Замените существующие is_valid: enum["да","нет"] на issues_count: number.
Числовая валидация с результатами тестов
Валидация с числовыми проверками вместо да/нет:
{ "id": "run-tests", "type": "agent-directive", "directive": "Запусти тесты и сообщи результаты", "inputSchema": { "type": "object", "properties": { "tests_passed": { "type": "number" }, "tests_failed": { "type": "number" } }, "required": ["tests_passed", "tests_failed"] }, "connections": { "success": "check-tests" }},{ "id": "check-tests", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "tests_failed" }, "right": 0 }, "connections": { "true": "continue", "false": "fix-tests" }}Уведомления пользователя
Уведомления держат пользователя в курсе во время долгих workflows. Используйте их стратегически — слишком много уведомлений становятся шумом.
Когда использовать уведомления
| Сценарий | Зачем уведомлять |
|---|---|
| Начало этапа (долгие задачи) | Пользователь видит прогресс, может планировать время |
| Требуется ввод пользователя | Пользователь знает что нужно ответить |
| Критические ошибки | Немедленное информирование о блокерах |
| Завершение задачи | Пользователь может проверить результаты |
Когда НЕ использовать
- Короткие workflows (< 5 минут)
- Между каждым мелким шагом
- Для внутренних validation loops
- Когда ошибка авто-восстанавливаема
Паттерн: Уведомление о начале этапа
Для многошаговых задач уведомляйте на каждом крупном этапе:
{ "id": "notify-step-start", "type": "user-notification", "message": "🚀 *Шаг {{current_step}}/{{total_steps}}*\n\n{{current_step_description}}", "format": "markdown", "connections": { "default": "execute-step", "error": "execute-step" }}Паттерн: Требуется ввод пользователя
Оповещение когда workflow заблокирован ожиданием пользователя:
{ "id": "notify-approval-needed", "type": "user-notification", "message": "⏳ *Ожидаю подтверждения*\n\nПлан готов к ревью. Подтвердите для продолжения.", "format": "markdown", "connections": { "default": "present-plan-to-user", "error": "present-plan-to-user" }}Паттерн: Оповещение об эскалации
Когда автоматические retry не помогли и нужно решение человека:
{ "id": "notify-escalation", "type": "user-notification", "message": "⚠️ *Требуется действие*\n\nШаг {{current_step}} не удался после {{max_retries}} попыток.\n\nВарианты:\n- Пропустить этот шаг\n- Выполнить вручную", "format": "markdown", "connections": { "default": "ask-user-decision", "error": "ask-user-decision" }}Паттерн: Итоговое уведомление
Уведомление при завершении задачи:
{ "id": "notify-completion", "type": "user-notification", "message": "✅ *Задача выполнена*\n\n{{task_name}}\n\nРезультат: {{deliverable_summary}}", "format": "markdown", "connections": { "default": "end", "error": "end" }}Укажите для connections.error ту же цель, что и для default, если сбой уведомления не должен
блокировать workflow. Без error connection полный сбой уже продолжает выполнение через default
с явным результатом all_failed.
Для очень долгих задач (часы) рассмотрите периодические heartbeat уведомления “всё ещё работаю”, чтобы пользователь знал что процесс жив.
Паттерны файловой персистенции
Для агентов с доступом к файловой системе используйте файлы для:
- Выгрузки больших данных из контекста workflow
- Отслеживания прогресса выполнения между итерациями
- Восстановления после прерываний
- Создания аудит-лога
Эти паттерны работают только для агентов с файловым доступом. Предусмотрите fallback для MCP-only агентов.
Структура директорий
Используйте шаблоны для организации файлов:
./{{task_name}}/├── process-id.txt # ID выполнения workflow├── plan.md # Текущий план├── step-{{step_index}}/│ ├── iteration-{{iteration}}/│ │ ├── result.md # Результат шага│ │ └── artifacts/ # Сгенерированные файлы│ └── summary.md # Сводка по шагу└── final-report.md # Финальный отчётОтслеживание прогресса
Сохраняйте process ID для восстановления:
{ "id": "save-process-id", "type": "agent-directive", "directive": "Сохрани process ID в ./{{task_name}}/process-id.txt для восстановления", "completionCondition": "Файл создан с process ID", "connections": { "success": "next-step" }}Снимки итераций
Сохраняйте результаты итераций в файлы вместо контекста:
{ "id": "save-iteration-result", "type": "agent-directive", "directive": "Сохрани результат итерации {{current_iteration}} в ./{{task_name}}/step-{{step_index}}/iteration-{{current_iteration}}/result.md", "completionCondition": "Результат сохранён в файл", "inputSchema": { "type": "object", "properties": { "file_path": { "type": "string" } }, "required": ["file_path"] }, "connections": { "success": "next-iteration" }}Выгрузка контекста
Ссылайтесь на файлы вместо хранения больших данных в контексте:
{ "id": "analyze-with-file-reference", "type": "agent-directive", "directive": "Прочитай анализ из {{analysis_file_path}} и продолжи обработку", "completionCondition": "Анализ загружен и обработан"}Когда использовать файловую персистенцию
| Сценарий | Файловый подход | Контекстный подход |
|---|---|---|
| Большой анализ кода | Сохранить в файл, ссылаться | Не рекомендуется |
| История итераций | Сохранять каждую итерацию | Хранить только текущую |
| Данные восстановления | process-id.txt обязателен | Теряется при прерывании |
| Аудит-лог | Дописывать в лог-файл | Недоступно |
| Маленькие флаги статуса | Оба подхода | Проще |
Сначала определите возможности агента (см. Определение возможностей агента) и предусмотрите оба пути — файловый и контекстный.
Проблема получения ответа от пользователя
Когда workflow требует подтверждения от пользователя, агент может “оптимизировать” — заполнить поля inputSchema не дожидаясь реального ответа.
Проблема
{ "id": "approve-plan", "directive": "Покажи план пользователю. Спроси: 'Подтверждаете? (да/нет)'", "inputSchema": { "properties": { "approved": { "type": "string", "enum": ["да", "нет"] } } }}Что происходит: Агент показывает план, затем сразу заполняет approved: "да" не дожидаясь ответа пользователя.
Почему: Агент видит что может заполнить поле самостоятельно и “оптимизирует” не останавливаясь.
Решение: скажите, чем является ответ
Скажите, что поле записывает случившееся, и что будет, если оно не случилось:
{ "id": "approve-plan", "directive": "Представь план и спроси, утверждён ли он. `approved` записывает собственный ответ пользователя: без ответа записывать нечего, а предположенный ответ уводит прогон в ветку, которую пользователь не выбирал. `user_response_text` — этот ответ дословно.", "completionCondition": "Пользователь явно ответил да или нет (не предполагаемый ответ)", "inputSchema": { "properties": { "approved": { "type": "string", "enum": ["да", "нет"] }, "user_response_text": { "type": "string", "description": "Точный текст ответа пользователя" } }, "required": ["approved", "user_response_text"] }}Ключевые техники
- Скажите, чей ответ записывает поле —
approvedхранит ответ пользователя, поэтому без ответа записывать туда нечего - Требуйте
user_response_text— дословный ответ и делает запись проверяемой потом - Назовите следствие каждого ответа — куда ведёт «нет», что закрывает «да»; предположенный ответ уводит прогон в ветку, которую пользователь не выбирал
- Разделите ноду, когда риск оправдывает лишний ход — см. ниже
Разделение на две ноды (альтернатива)
Для критичных подтверждений разделите на отдельные ноды:
[show-information] → [get-user-confirmation] → [route-decision]Первая нода только показывает, вторая только получает ответ:
{ "id": "show-plan", "directive": "Покажи план пользователю. Объясни каждый этап.", "inputSchema": { "properties": { "plan_shown": { "type": "string", "enum": ["да"] } } }, "connections": { "success": "get-plan-approval" }},{ "id": "get-plan-approval", "directive": "План показан выше. Спроси, утверждён ли он. `approved` записывает собственный ответ пользователя; предположенный ответ уводит прогон в ветку, которую он не выбирал.", "inputSchema": { "properties": { "approved": { "type": "string", "enum": ["да", "нет"] } } }, "connections": { "success": "route-approval" }}Это известное ограничение workflows выполняемых агентами. Всегда тестируйте ноды с пользовательским вводом вручную перед деплоем.
Лучшие практики
- Один узел = одна ответственность — не смешивайте проверку и исправление
- Ясные директивы — начинайте с глагола: Создай, Проверь, Исправь
- Явные отрицания — “НЕ исправляй, ТОЛЬКО проверь”
- Используйте inputSchema — всегда определяйте ожидаемую структуру ответа
- Числовая валидация — используйте счётчики вместо да/нет для точных проверок
- Счетчики итераций — предотвращайте бесконечные циклы
- Gate подтверждения — для критических действий
- Самодокументирование — объявляйте знания как значения по умолчанию в variableRegistry
- Graceful уведомления — ошибки каналов связи не должны блокировать workflow
Связанное
- Узлы — Справочник типов узлов
- Шаблоны — Динамический контент
- Инструменты — Справочник MCP tools
- Паттерн Replan — Пересмотр многошагового плана по ходу выполнения
- Completeness Self-Review — Проверка каждого требования перед выдачей