Orkiestracja agentów
Queuety dobrze sprawdza się w systemach agentów, gdy potrzebujesz adaptacyjnej pracy bez rezygnowania z trwałego stanu, ponawiania prób, inspekcji i jawnej obsługi oczekiwania.
W większości przepływów agentów nie potrzebujesz silnika DAG, który można edytować w czasie wykonywania. W praktyce większość systemów można modelować za pomocą niewielkiego zestawu trwałych operacji orkiestracji. for_each() rozwija pracę w ramach jednego uruchomienia przepływu pracy. start_agents() i wait_for_agents() przekazują pracę wykrytą w czasie wykonywania do niezależnych przepływów pracy najwyższego poziomu. wait_for_decision() i wait_for_input() wstrzymują działanie, aby umożliwić człowiekowi podjęcie decyzji. wait_for_workflow(), wait_for_workflows() i wait_for_agent_group() pozwalają jednemu uruchomieniu najwyższego poziomu czekać na inne lub na uruchomioną grupę spełniającą określone kworum.
Przydatny model myślowy
Orkiestrację agentów najłatwiej zrozumieć, rozpatrując ją warstwami. Planista określa, jakie zadania należy wykonać. Queuety zamienia je w trwałe zadania lub przepływy pracy. Uruchomienia wyspecjalizowanych agentów generują wyniki i zapisują artefakty. Etap nadzorujący zbiera te wyniki i decyduje o dalszych działaniach. W dowolnym momencie człowiek może zatwierdzić, odrzucić lub skorygować uruchomienie, zanim będzie kontynuowane.
Ważna różnica polega na tym, że agent decyduje, jaką pracę wykonać, ale Queuety nadal decyduje, jak ta praca jest zapisywana, ponawiana, wznawiana i agregowana. Gdy celem orkiestracji jest długotrwała sesja, a nie ograniczone czasowo uruchomienie, połącz to z Maszynami stanów.
Wzorzec 1: planista i wykonawca z niezależnymi uruchomieniami agentów
Użyj start_agents(), gdy etap planowania wykrywa zadania w czasie wykonywania i każde z nich powinno stać się osobnym przepływem pracy najwyższego poziomu.
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 ] );
W tym wzorcu PlanResearchTasksStep zapisuje elementy wykryte w czasie wykonywania w $state['agent_tasks'], start_agents() uruchamia osobny trwały przepływ pracy dla każdego zadania, a wait_for_agent_group() wstrzymuje przepływ nadrzędny do spełnienia wybranego warunku zakończenia. Następnie SynthesizeBriefStep otrzymuje ukończone stany przepływów podrzędnych w $state['agent_results'].
To najprostszy punkt wyjścia dla systemów z planistą i wykonawcą, ponieważ każde uruchomienie agenta można osobno sprawdzić i ponowić.
Wzorzec 2: weryfikacja przez człowieka przed kontynuowaniem uruchomienia
Użyj wait_for_decision(), gdy przepływ pracy powinien zatrzymać się, aby umożliwić podjęcie decyzji „tak” lub „nie”, a wait_for_input(), gdy operator musi przekazać do uruchomienia uporządkowaną informację zwrotną.
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 ] );
Jeśli osoba weryfikująca zatwierdzi:
Queuety::approve_workflow(
$workflow_id,
[
'reviewer' => 'editor@example.com',
'notes' => 'Looks good, publish after legal check',
],
'approved'
);
Jeśli osoba weryfikująca odrzuci:
Queuety::reject_workflow(
$workflow_id,
[
'reviewer' => 'editor@example.com',
'reason' => 'Needs citations and a stronger conclusion',
],
'rejected'
);
Po wait_for_decision() przepływ pracy otrzymuje uporządkowany ładunek zawierający ostateczny wynik, sygnał, który wznowił uruchomienie, oraz wszelkie dane przekazane przez osobę weryfikującą. Dzięki temu uzyskujesz rzeczywisty punkt kontrolny z udziałem człowieka, nie pozostawiając otwartego procesu PHP, gdy uruchomienie czeka.
Wzorzec 3: jeden przepływ pracy najwyższego poziomu czeka na inny
Czasami najprostszy model to nie jeden ogromny przepływ pracy. Jeden przepływ może zakończyć etap badań, a inny może na niego czekać przed rozpoczęciem kolejnego etapu.
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 ] );
Zapewnia to trwałą granicę między etapem badań a etapem publikacji. Każde uruchomienie ma własny cykl operacyjny, ale drugi przepływ pracy i tak wznawia się automatycznie po zakończeniu zależności.
Wybór odpowiedniej podstawowej operacji
for_each() to właściwe narzędzie, gdy praca należy do jednego uruchomienia przepływu pracy, a gałęzie są po prostu równoległym wykonywaniem kroków operujących na jednym wspólnym stanie.
start_agents() sprawdza się lepiej, gdy każde wykryte zadanie powinno być osobnym, trwałym uruchomieniem najwyższego poziomu, które można osobno sprawdzać, ponawiać lub eksportować.
wait_for_workflow() i wait_for_workflows() sprawdzają się, gdy jeden przepływ pracy najwyższego poziomu zależy od innego i potrzebujesz trwałej, asynchronicznej koordynacji między tymi warstwami orkiestracji.
wait_for_decision() i wait_for_input() należą do miejsc, w których człowiek musi zatwierdzić, odrzucić lub pokierować uruchomieniem, a przepływ pracy pozostaje wstrzymany bez zużywania zasobów roboczych.
Zalecane konwencje nazewnictwa stanu
Systemy agentów łatwiej debugować, gdy klucze stanu są przewidywalne. W praktyce agent_tasks dobrze sprawdza się w przypadku danych wyjściowych planisty, agent_workflow_ids — uruchomionych przepływów najwyższego poziomu, agent_results — ukończonego stanu przepływu podrzędnego, a review lub decision — ładunków zatwierdzenia lub odrzucenia. Większe wyniki, takie jak wersje robocze, cytowania czy manifesty badań, zwykle lepiej przechowywać w magazynie artefaktów niż w głównym stanie przepływu pracy.
Zalecane zabezpieczenia dla uruchomień agentów
Przepływy pracy agentów szczególnie korzystają z zabezpieczeń, ponieważ z natury są dynamiczne.
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 );
Te mechanizmy odpowiadają na praktyczne pytania istotne w środowisku produkcyjnym: która wersja definicji utworzyła dane uruchomienie, czy powielone żądania zewnętrzne mogą uruchomić je dwukrotnie, czy planista może utworzyć zbyt wiele gałęzi oraz czy stan przepływu pracy może rosnąć bez ograniczeń. W przypadku większości systemów agentów zacznij od tych zabezpieczeń, zanim dostroisz liczbę procesów roboczych lub topologię kolejki.