
# Agentorkestrering

Queuety passer godt til agentsystemer, når du vil have adaptivt arbejde uden at give afkald på persistent tilstand, genforsøg, inspektion og eksplicitte ventebetingelser.

Du behøver ikke en DAG-motor, der kan redigeres under kørsel, til de fleste agentflows. I praksis kan de fleste systemer modelleres med et lille sæt persistente orkestreringstrin. `for_each()` udvider arbejdet inden for én workflowkørsel. `start_agents()` og `wait_for_agents()` overdrager arbejde, der opdages under kørsel, til uafhængige workflows på topniveau. `wait_for_decision()` og `wait_for_input()` sætter kørslen på pause, så et menneske kan styre den. `wait_for_workflow()`, `wait_for_workflows()` og `wait_for_agent_group()` lader én kørsel på topniveau vente på en anden eller på et startet quorum.

## En nyttig mental model

Agentorkestrering er lettest at forstå i lag. En planlægger beslutter, hvilket arbejde der findes. Queuety omdanner arbejdet til persistente jobs eller workflows. Specialiserede kørsler producerer resultater og gemmer artefakter. Et overvågende trin samler resultaterne og beslutter, hvad der skal ske derefter. Når som helst kan et menneske godkende, afvise eller rette kørslen, før den fortsætter.

Den vigtige forskel er, at agenten beslutter, hvilket arbejde der skal udføres, mens Queuety stadig afgør, hvordan arbejdet gemmes, prøves igen, genoptages og samles. Når orkestreringsmålet er en langlivet session frem for en afgrænset kørsel, kan du kombinere det med [Tilstandsmaskiner](https://queuety.inline0.dev/da/docs/state-machines).

## Mønster 1: Planlægger/udfører med uafhængige agentkørsler

Brug `start_agents()`, når et planlæggertrin finder opgaver under kørsel, og hver opgave skal blive til sit eget workflow på topniveau.

```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 ] );
```

I dette mønster skriver `PlanResearchTasksStep` elementer, der findes under kørsel, til `$state['agent_tasks']`, `start_agents()` sender ét persistent workflow af sted pr. opgave, og `wait_for_agent_group()` sætter det overordnede workflow på pause, indtil den valgte fuldførelsesbetingelse er opfyldt. `SynthesizeBriefStep` modtager derefter tilstandene for de færdige underordnede workflows under `$state['agent_results']`.

Dette er det mest ligetil udgangspunkt for planlægger-/udførersystemer, fordi hver agentkørsel fortsat kan inspiceres og prøves igen for sig.

## Mønster 2: Menneskelig gennemgang, før kørslen fortsætter

Brug `wait_for_decision()`, når workflowet skal stoppe for en reel ja/nej-beslutning, og `wait_for_input()`, når operatøren skal sende struktureret feedback tilbage til kørslen.

```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 ] );
```

Hvis den, der gennemgår, godkender:

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

Hvis den, der gennemgår, afviser:

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

Efter `wait_for_decision()` modtager workflowet en struktureret payload med det endelige resultat, signalet, der genoptog kørslen, og eventuelle data fra den, der gennemgik, og som fulgte med. Det giver dig et reelt kontrolpunkt med et menneske i processen uden at holde en PHP-proces åben, mens kørslen venter.

## Mønster 3: Ét workflow på topniveau venter på et andet

Nogle gange er den mest enkle model ikke ét kæmpe workflow. Ét workflow kan afslutte researchen, mens et andet venter på det, før næste fase starter.

```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 ] );
```

Det giver dig en persistent grænse mellem researchfasen og publiceringsfasen. Hver kørsel har sin egen driftslivscyklus, men det andet workflow genoptages stadig automatisk, når afhængigheden er fuldført.

## Valg af det rette grundelement

`for_each()` er det rette værktøj, når arbejdet hører hjemme i én workflowkørsel, og grenene reelt blot er parallel udførelse af trin med én delt tilstandspakke.

`start_agents()` er bedre, når hver opgave, der findes, skal have sin egen persistente kørsel på topniveau, og du vil inspicere, prøve igen eller eksportere kørslerne separat.

`wait_for_workflow()` og `wait_for_workflows()` passer, når ét workflow på topniveau afhænger af et andet, og du ønsker persistent asynkron koordinering mellem disse orkestreringslag.

`wait_for_decision()` og `wait_for_input()` hører til dér, hvor et menneske skal godkende, afvise eller styre kørslen, mens workflowet forbliver sat på pause uden at bruge workerkapacitet.

## Foreslåede tilstandskonventioner

Agentsystemer er lettere at fejlfinde, når tilstandsnøglerne er forudsigelige. I praksis fungerer `agent_tasks` godt til planlæggeroutput, `agent_workflow_ids` til startede kørsler på topniveau, `agent_results` til fuldført tilstand for underordnede workflows og `review` eller `decision` til godkendelses- eller afvisningspayloads. Større output som udkast, kildehenvisninger eller researchmanifester hører som regel hjemme i artefaktlageret frem for i workflowets primære tilstandspakke.

## Anbefalede sikkerhedsforanstaltninger til agentkørsler

Agentworkflows har større gavn af sikkerhedsforanstaltninger end næsten alle andre anvendelser, fordi de af natur er dynamiske.

```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 );
```

Disse kontroller besvarer de praktiske spørgsmål, der betyder noget i produktion: hvilken definitionsversion der skabte en kørsel, om dublerede eksterne anmodninger kan sende den af sted to gange, om en planlægger kan oprette for mange grene, og om workflowtilstanden kan vokse uden grænser. For de fleste agentsystemer bør du begynde med disse sikkerhedsforanstaltninger, før du justerer antallet af workere eller køtopologien.

## Se også

- [Eksempler](https://queuety.inline0.dev/da/docs/examples)
- [Handlingsudløsere](https://queuety.inline0.dev/da/docs/features/action-triggers)
- [Dynamisk For-hver](https://queuety.inline0.dev/da/docs/workflows/for-each)
- [Asynkrone overdragelser](https://queuety.inline0.dev/da/docs/workflows/async-handoffs)
- [Workflowafhængigheder](https://queuety.inline0.dev/da/docs/workflows/dependencies)
- [Artefakter](https://queuety.inline0.dev/da/docs/features/artifacts)
- [Workflowsignaler](https://queuety.inline0.dev/da/docs/workflows/signals)
- [Workflowbeskyttelse](https://queuety.inline0.dev/da/docs/workflows/guardrails)
