12. Воркфлоу
🔵 Воркфлоу — декларативные многошаговые пайплайны поверх агентов и
инструментов. Каждый воркфлоу — YAML-файл в config/workflows/, описывающий
упорядоченный список шагов, работающих с накапливающимся скоупом переменных
(payload input плюс output_key каждого шага).
Шаги hot-reload'ятся; запуск — POST /v1/workflows/<name>/run.
12.1 Типы шагов
type |
Назначение |
|---|---|
agent |
запустить шаблон (или inline instructions) с шаблонизированным prompt; опционально — структурированный результат через output_schema |
tool |
вызвать инструмент напрямую с шаблонизированными args |
condition |
ветвление на id шага по шаблонизированному булевому выражению |
for_each |
итерация по коллекции с вложенным списком шагов на каждый элемент |
Шаблоны — MiniJinja ({{ var }}, {% if %}), рендерятся от скоупа переменных;
{{ x | tojson }} встраивает структурированные значения, env_var('NAME')
читает переменную окружения.
12.2 Пример
name: triage
description: Просмотреть входящие коммиты и завести тикеты.
steps:
- id: fetch
type: tool
tool: git_commits
args: { since: "{{ input.since | default('yesterday') }}" }
output_key: commits
- id: process
type: for_each
over: commits.items # dot-path в скоуп переменных → массив
item: commit # переменная цикла
concurrency: 3
max_items: 100
steps:
- id: analyze
type: agent
template: review
prompt: "Отревьюй {{ commit.sha }}: {{ commit.message }}"
output_key: review
output_schema:
type: object
properties:
needs_action: { type: boolean }
summary: { type: string }
required: [needs_action, summary]
retry: { max: 2, backoff_secs: 5 }
timeout_secs: 120
- id: branch
type: condition
when: "{{ review.needs_action }}"
then: file_ticket
- id: file_ticket
type: tool
tool: send_report
args: { body: "{{ review.summary }}" }
collect:
reviews: "{{ results | tojson }}"
- id: done
type: tool
tool: send_report
args: { body: "{{ reviews }}" }
12.3 Справочник шагов
agent
| Поле | Описание |
|---|---|
template |
шаблон для запуска (взаимоисключается с instructions) |
instructions |
inline-системный промпт без шаблона |
tools |
доп. имена инструментов (сливаются с шаблонными) |
prompt |
сообщение пользователя (MiniJinja) |
output_key |
куда сохранить результат в скоуп |
output_schema |
JSON Schema — агент завершается через job_done; проверенный payload становится значением output_key |
session |
ключ стейтфул-сессии (шаги с одним ключом в одном запуске делят контекст) |
retry |
{ max, backoff_secs } — ретраи всего шага при ошибке |
timeout_secs |
лимит хода по времени |
budget |
лимит токенов { max_per_turn, max_per_minute, max_total }; для inline instructions заменяет дефолтный лимит (4000 / 50000 / 200000); для template игнорируется |
next |
явный id следующего шага (см. §12.9) |
Без output_schema вывод шага — текст финального ответа агента. С ним шаг
падает, если агент не вернул валидный структурированный результат.
tool
| Поле | Описание |
|---|---|
tool |
имя зарегистрированного инструмента |
args |
аргументы (строковые листья — MiniJinja; лист, рендерящийся в JSON, передаётся структурой) |
output_key |
куда сохранить результат — data инструмента, если есть, иначе content |
next |
явный id следующего шага |
condition
| Поле | Описание |
|---|---|
when |
MiniJinja-выражение → true/false |
then |
id шага при истинности |
else |
id шага при ложности |
for_each
| Поле | Описание |
|---|---|
over |
dot-path в скоуп → массив (напр. commits.items) |
item |
имя переменной цикла (по умолчанию item) |
concurrency |
максимум параллельных итераций (по умолчанию 1) |
max_items |
жёсткий лимит элементов |
steps |
вложенный под-воркфлоу, запускается на каждый элемент |
collect |
карта имя → шаблон, сворачивающая per-item результаты (доступны как results) обратно в родительский скоуп |
next |
явный id следующего шага |
Каждая итерация работает с копией родительского скоупа + item. Её выводы
становятся per-item результатом в results (массив), который collect может
переформатировать.
12.4 Контроль доступа
Воркфлоу может объявить шаблоны, которые трогает, — тогда скоупед-оператор запустит его только если эти шаблоны в его скоупе:
name: reports
templates: [rss-agent, summarizer] # шаблоны, которые воркфлоу может трогать
steps: [ ... ]
Scope::All(полный админ) запускает любой воркфлоу.- Скоупед-оператор (
templates: [...]вauth.admin_tokens) запускает воркфлоу только если все егоtemplatesв его скоупе, и видит только такие воркфлоу. - Воркфлоу без
templates— только для админа.
run / get_run возвращают 403 для скоупед-оператора вне его скоупа; list
их не показывает.
12.5 Триггеры
Воркфлоу может стартовать без явного API-вызова:
name: reports
triggers:
cron:
- schedule: "0 0 9 * * *" # cron: sec min hour dom month dow (UTC)
input: { topic: daily } # фиксированный input (по умолчанию {})
webhook:
token_env: WF_REPORTS_TOKEN # опциональный bearer (рекомендуется)
steps: [ ... ]
| Триггер | Описание |
|---|---|
cron[].schedule |
cron-выражение (6 полей, секундное разрешение) |
cron[].input |
фиксированный input на запуск |
webhook |
включает POST /v1/workflows/<name>/webhook; JSON-тело становится input |
webhook.token_env |
env с bearer-токеном; не задан/пуст → все запросы отклоняются |
12.6 HTTP API
| Endpoint | Auth | Описание |
|---|---|---|
GET /v1/workflows |
админ | список воркфлоу + последние запуски (?runs=N) |
POST /v1/workflows/<name>/run |
админ | запустить; JSON-тело становится input. Возвращает { ok, id } |
POST /v1/workflows/<name>/webhook |
свой токен | запустить с webhook (JSON-тело → input) |
GET /v1/workflows/runs/<id> |
админ | статус запуска + история шагов |
GET /workflows |
админ | HTML-страница (запуск + просмотр) |
Запуски пишутся в logs/workflows.db (workflow_runs); статус running →
success / error, с per-step записями (id, status, output, error, retries,
timings). Состояние между рестартами не персистится — только история запусков.
12.7 Запуск из агентов и инструментов
Воркфлоу можно запустить из другого агента через workflow_tool:
kind: workflow_tool
name: run_triage
description: Запустить воркфлоу триажа.
workflow: triage # дефолтный воркфлоу (перекрывается аргументом `workflow`)
Аргументы: workflow (имя, опционально при конфиге) и input (объект).
Инструмент возвращает run id; запуск продолжается асинхронно.
12.8 Локальное тестирование
workflow_tool config/workflows/smoke.yaml '{"items":["Cargo.toml","README.md"]}'
# или input из файла (удобно на Windows):
workflow_tool config/workflows/agent_demo.yaml --args-file args.json
tool-шаги работают со встроенными + YAML-инструментами из config/agents/;
agent-шаги используют провайдер из config/server.yaml (или
DEEPSEEK_API_KEY). Запускай из корня репозитория, чтобы config/ резолвился.
12.9 Примечания
- Поток управления. Шаги идут по порядку;
conditionпрыгает на idthen/else, выполнение продолжается оттуда. Шаг сnextпрыгает на него вместо следующего по списку — используйnext, чтобы закрытьif-ветку и пропуститьelse. Прыжки защищены от бесконечных циклов. for_eachпо пустому массиву — no-op (шаг успешен с[]).- Упавший шаг валит весь запуск;
retryприменяется к шагу до этого. - Стейтфул-сессии. Дай двум и более
agent-шагам один ключsession— они поделят один разговор: первый создаёт сессию (лениво), следующие её переиспользуют. Сессия закрывается, когда заканчивается охватывающий скоуп. Каждая итерацияfor_eachполучает свою сессию на ключ. output_schemaшагаagentпереиспользует тот же контракт структурированного завершения, что и агенты (см. §4): схема заменяет параметрыjob_done, а проверенные аргументы становятся результатом.