
# Оркестрація агентів

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

Для більшості потоків роботи агентів не потрібен механізм DAG, який можна змінювати під час виконання. На практиці більшість систем можна змоделювати за допомогою кількох надійних механізмів оркестрації. `for_each()` розгортає роботу в межах одного запуску робочого процесу. `start_agents()` та `wait_for_agents()` передають виявлену під час виконання роботу окремим робочим процесам верхнього рівня. `wait_for_decision()` та `wait_for_input()` призупиняють виконання, щоб передати керування людині. `wait_for_workflow()`, `wait_for_workflows()` і `wait_for_agent_group()` дають одному запуску верхнього рівня змогу чекати на інший запуск або на запуск необхідної кількості процесів.

## Зручна ментальна модель

Оркестрацію агентів найпростіше розуміти пошарово. Планувальник визначає, яку роботу потрібно виконати. Queuety перетворює її на надійні завдання або робочі процеси. Спеціалізовані запуски створюють результати й зберігають артефакти. Контролювальний етап об’єднує результати й визначає подальші дії. На будь-якому етапі людина може погодити, відхилити або виправити виконання, перш ніж воно продовжиться.

Важлива відмінність у тому, що агент вирішує, яку роботу виконати, але Queuety і далі визначає, як цю роботу зберігати, повторювати, відновлювати й об’єднувати. Якщо оркеструється довготривалий сеанс, а не обмежений запуск, поєднайте це з [Машинами станів](https://queuety.inline0.dev/uk/docs/state-machines).

## Шаблон 1: планувальник і виконавець з окремими запусками агентів

Використовуйте `start_agents()`, якщо на етапі планування під час виконання виявляються завдання, кожне з яких має стати окремим робочим процесом верхнього рівня.

```php
use Queuety\Enums\WaitMode;
use Queuety\Queuety;

$agent_run = Queuety::workflow( 'agent_run' )
    ->then( FetchSourcesStep::class )
    ->then( DraftFindingStep::class );

Queuety::workflow( 'brief_research' )
    ->version( 'brief-research.v1' )
    ->idempotency_key( 'brief:42:research' )
    ->max_transitions( 20 )
    ->then( PlanResearchTasksStep::class )
    ->start_agents( 'agent_tasks', $agent_run, group_key: 'researchers' )
    ->wait_for_agent_group( 'researchers', WaitMode::Quorum, 2, 'agent_results' )
    ->then( SynthesizeBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
```

У цьому шаблоні `PlanResearchTasksStep` записує виявлені під час виконання елементи до `$state['agent_tasks']`, `start_agents()` запускає окремий надійний робочий процес для кожного завдання, а `wait_for_agent_group()` призупиняє батьківський процес до виконання вибраної умови завершення. Після цього `SynthesizeBriefStep` отримує стани завершених дочірніх процесів у `$state['agent_results']`.

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

## Шаблон 2: перевірка людиною перед продовженням виконання

Використовуйте `wait_for_decision()`, коли робочий процес має зупинитися й отримати чітку відповідь «так» або «ні», а `wait_for_input()` — коли оператору потрібно надіслати структурований відгук назад до процесу.

```php
use Queuety\Queuety;

$workflow_id = Queuety::workflow( 'brief_review' )
    ->then( DraftBriefStep::class )
    ->wait_for_decision( result_key: 'review' )
    ->then( HandleReviewDecisionStep::class )
    ->wait_for_input( result_key: 'revision_notes' )
    ->then( ApplyRevisionNotesStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
```

Якщо перевіряльник погоджує:

```php
Queuety::approve_workflow(
    $workflow_id,
    [
        'reviewer' => 'editor@example.com',
        'notes' => 'Looks good, publish after legal check',
    ],
    'approved'
);
```

Якщо перевіряльник відхиляє:

```php
Queuety::reject_workflow(
    $workflow_id,
    [
        'reviewer' => 'editor@example.com',
        'reason' => 'Needs citations and a stronger conclusion',
    ],
    'rejected'
);
```

Після `wait_for_decision()` робочий процес отримує структуровані дані з остаточним результатом, сигналом, що відновив виконання, та будь-якими даними від перевіряльника. Так ви отримуєте повноцінну контрольну точку з участю людини, не залишаючи процес PHP відкритим під час очікування.

## Шаблон 3: один робочий процес верхнього рівня очікує на інший

Іноді найпростіша модель — це не один величезний робочий процес. Один процес може завершити дослідження, а інший — дочекатися його завершення, перш ніж розпочати наступний етап.

```php
use Queuety\Enums\WaitMode;
use Queuety\Queuety;

$research_id = Queuety::workflow( 'research_brief' )
    ->then( PlanResearchTasksStep::class )
    ->start_agents( 'agent_tasks', $agent_run )
    ->wait_for_agents( mode: WaitMode::All, result_key: 'agent_results' )
    ->then( SynthesizeBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );

Queuety::workflow( 'publish_brief' )
    ->wait_for_workflow( $research_id, 'research' )
    ->wait_for_decision( result_key: 'editor_review' )
    ->then( PublishBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
```

Так утворюється надійна межа між етапами дослідження й публікації. Кожен запуск має власний операційний життєвий цикл, а другий робочий процес автоматично відновлюється після завершення залежного процесу.

## Як вибрати потрібний механізм

`for_each()` — правильний інструмент, коли робота належить до одного запуску робочого процесу, а розгалуження фактично є паралельним виконанням кроків зі спільним набором стану.

`start_agents()` краще підходить, коли кожне виявлене завдання має стати окремим надійним запуском верхнього рівня, який можна переглядати, повторювати або експортувати окремо.

`wait_for_workflow()` і `wait_for_workflows()` підходять, коли один робочий процес верхнього рівня залежить від іншого й потрібна надійна асинхронна координація між цими рівнями оркестрації.

`wait_for_decision()` і `wait_for_input()` доречні там, де людині потрібно погодити, відхилити чи спрямувати виконання, поки робочий процес призупинено й він не займає ресурси робочих процесів.

## Рекомендовані домовленості щодо стану

Системи агентів легше налагоджувати, якщо ключі стану передбачувані. На практиці `agent_tasks` добре підходить для результатів планування, `agent_workflow_ids` — для запущених процесів верхнього рівня, `agent_results` — для стану завершених дочірніх процесів, а `review` або `decision` — для даних погодження чи відхилення. Великі результати, як-от чернетки, цитати або маніфести досліджень, зазвичай варто зберігати в сховищі артефактів, а не в основному наборі стану робочого процесу.

## Рекомендовані обмеження для запусків агентів

Системам агентів обмеження потрібні чи не більше, ніж будь-якому іншому типу завдань, адже за своєю природою вони динамічні.

```php
Queuety::workflow( 'agent_research' )
    ->version( 'agent-research.v2' )
    ->idempotency_key( 'brief:42:agent-research' )
    ->max_transitions( 20 )
    ->max_for_each_items( 12 )
    ->max_state_bytes( 32768 );
```

Ці засоби контролю допомагають відповісти на важливі для робочого середовища запитання: версія якого визначення створила запуск, чи можуть повторні зовнішні запити запустити його двічі, чи не створить планувальник забагато гілок і чи не зростатиме стан робочого процесу без обмежень. Для більшості систем агентів спершу налаштуйте ці обмеження, а вже потім — кількість робочих процесів або структуру черг.

## Див. також

- [Приклади](https://queuety.inline0.dev/uk/docs/examples)
- [Тригери дій](https://queuety.inline0.dev/uk/docs/features/action-triggers)
- [Динамічний цикл для кожного елемента](https://queuety.inline0.dev/uk/docs/workflows/for-each)
- [Асинхронне передавання](https://queuety.inline0.dev/uk/docs/workflows/async-handoffs)
- [Залежності робочих процесів](https://queuety.inline0.dev/uk/docs/workflows/dependencies)
- [Артефакти](https://queuety.inline0.dev/uk/docs/features/artifacts)
- [Сигнали робочого процесу](https://queuety.inline0.dev/uk/docs/workflows/signals)
- [Обмеження робочого процесу](https://queuety.inline0.dev/uk/docs/workflows/guardrails)
