Orchestration d’agents
Queuety convient aux systèmes d’agents qui ont besoin d’un travail adaptatif tout en conservant un état durable, des tentatives, des outils d’inspection et des mécanismes d’attente explicites.
Vous n’avez pas besoin d’un moteur DAG modifiable à l’exécution pour la plupart des flux d’agents. En pratique, la plupart des systèmes peuvent être modélisés à l’aide d’un petit ensemble d’opérations d’orchestration durables. for_each() développe le travail au sein d’une même exécution de workflow. start_agents() et wait_for_agents() confient le travail découvert à l’exécution à des workflows indépendants de premier niveau. wait_for_decision() et wait_for_input() mettent le processus en pause pour permettre un contrôle humain. wait_for_workflow(), wait_for_workflows() et wait_for_agent_group() permettent à une exécution de premier niveau d’attendre une autre exécution ou un quorum démarré.
Un modèle mental utile
L’orchestration d’agents est plus facile à comprendre lorsqu’on la considère par couches. Un planificateur détermine le travail à effectuer. Queuety transforme ce travail en tâches ou workflows durables. Les exécutions spécialisées produisent des résultats et enregistrent des artefacts. Une étape de supervision regroupe ces résultats et décide de la suite. À tout moment, une personne peut approuver, rejeter ou corriger l’exécution avant qu’elle ne continue.
La distinction importante est que l’agent décide du travail à effectuer, tandis que Queuety décide toujours comment ce travail est conservé, relancé, repris et regroupé. Si l’orchestration cible une session de longue durée plutôt qu’une exécution délimitée, associez-la aux machines à états.
Modèle 1 : planificateur/exécuteur avec des exécutions d’agents indépendantes
Utilisez start_agents() lorsqu’une étape du planificateur découvre des tâches à l’exécution et que chacune doit devenir un workflow de premier niveau.
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 ] );
Dans ce modèle, PlanResearchTasksStep écrit les éléments découverts à l’exécution dans $state['agent_tasks'], start_agents() lance un workflow durable par tâche et wait_for_agent_group() met le parent en attente jusqu’à ce que la condition d’achèvement choisie soit satisfaite. SynthesizeBriefStep reçoit ensuite les états des enfants terminés sous $state['agent_results'].
C’est le meilleur point de départ pour les systèmes planificateur/exécuteur, car chaque exécution d’agent reste inspectable et peut être relancée indépendamment.
Modèle 2 : validation humaine avant la reprise de l’exécution
Utilisez wait_for_decision() lorsque le workflow doit s’arrêter pour une décision explicite par oui ou non, et wait_for_input() lorsque l’opérateur doit renvoyer des commentaires structurés à l’exécution.
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 ] );
Si la personne chargée de la validation approuve :
Queuety::approve_workflow(
$workflow_id,
[
'reviewer' => 'editor@example.com',
'notes' => 'Looks good, publish after legal check',
],
'approved'
);
Si la personne chargée de la validation rejette :
Queuety::reject_workflow(
$workflow_id,
[
'reviewer' => 'editor@example.com',
'reason' => 'Needs citations and a stronger conclusion',
],
'rejected'
);
Après wait_for_decision(), le workflow reçoit une charge utile structurée contenant le résultat final, le signal qui a repris l’exécution et les éventuelles données de validation transmises. Vous disposez ainsi d’un véritable point de contrôle avec intervention humaine, sans garder un processus PHP ouvert pendant l’attente.
Modèle 3 : un workflow de premier niveau en attend un autre
Parfois, le modèle le plus simple ne consiste pas à créer un workflow géant. Un workflow peut terminer la recherche, tandis qu’un autre attend son achèvement avant de lancer l’étape suivante.
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 ] );
Cela crée une frontière durable entre l’étape de recherche et celle de publication. Chaque exécution a son propre cycle de vie opérationnel, mais le second workflow reprend automatiquement lorsque la dépendance est satisfaite.
Choisir la bonne primitive
for_each() est le bon outil lorsque le travail doit s’effectuer dans une seule exécution de workflow et que les branches ne sont que des étapes parallèles partageant le même état.
start_agents() convient mieux lorsque chaque tâche découverte doit devenir sa propre exécution durable de premier niveau, que vous souhaitez inspecter, relancer ou exporter séparément.
wait_for_workflow() et wait_for_workflows() conviennent lorsqu’un workflow de premier niveau dépend d’un autre et que vous souhaitez une coordination asynchrone durable entre ces couches d’orchestration.
wait_for_decision() et wait_for_input() s’utilisent aux étapes où une personne doit approuver, rejeter ou orienter l’exécution pendant que le workflow reste en pause sans mobiliser de capacité de travailleur.
Conventions d’état suggérées
Les systèmes d’agents sont plus faciles à déboguer lorsque les clés d’état sont prévisibles. En pratique, agent_tasks convient bien aux résultats du planificateur, agent_workflow_ids aux exécutions de premier niveau démarrées, agent_results à l’état des workflows enfants terminés, et review ou decision aux charges utiles d’approbation ou de rejet. Les résultats volumineux, comme les brouillons, les citations ou les manifestes de recherche, sont généralement à placer dans le stockage d’artefacts plutôt que dans l’état principal du workflow.
Garde-fous recommandés pour les exécutions d’agents
Les workflows d’agents ont besoin de garde-fous plus que presque tout autre cas d’usage, car ils sont dynamiques par nature.
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 );
Ces contrôles répondent aux questions concrètes qui comptent en production : quelle version de la définition a produit une exécution, si des requêtes externes en double peuvent la lancer deux fois, si un planificateur peut créer trop de branches et si l’état du workflow peut croître sans limite. Pour la plupart des systèmes d’agents, commencez par ces garde-fous avant d’ajuster le nombre de travailleurs ou la topologie des files d’attente.