에이전트 오케스트레이션
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은 여전히 해당 작업을 어떻게 저장하고, 재시도하고, 재개하고, 취합할지 결정한다는 것입니다. 오케스트레이션 대상이 범위가 정해진 실행이 아니라 오래 지속되는 세션이라면 상태 머신과 함께 사용하세요.
패턴 1: 독립적인 에이전트 실행을 사용하는 플래너/실행기
플래너 단계에서 런타임에 작업을 발견하고 각 작업을 별도의 최상위 워크플로로 실행해야 할 때 start_agents()을 사용하세요.
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()을 사용하세요.
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 ] );
검토자가 승인하면:
Queuety::approve_workflow(
$workflow_id,
[
'reviewer' => 'editor@example.com',
'notes' => 'Looks good, publish after legal check',
],
'approved'
);
검토자가 거부하면:
Queuety::reject_workflow(
$workflow_id,
[
'reviewer' => 'editor@example.com',
'reason' => 'Needs citations and a stronger conclusion',
],
'rejected'
);
wait_for_decision() 이후 워크플로는 최종 결과, 실행을 재개한 신호, 함께 전달된 검토자 데이터를 포함한 구조화된 페이로드를 받습니다. 실행이 대기하는 동안 PHP 프로세스를 열어 두지 않고도 실제 사람 개입 지점을 마련할 수 있습니다.
패턴 3: 하나의 최상위 워크플로가 다른 워크플로를 기다리는 경우
때로는 거대한 워크플로 하나로 구성하지 않는 편이 가장 깔끔합니다. 한 워크플로가 조사를 완료하고, 다른 워크플로가 다음 단계를 시작하기 전에 이를 기다릴 수 있습니다.
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가 적합합니다. 초안, 인용, 조사 매니페스트 같은 큰 출력은 보통 기본 워크플로 상태 묶음 대신 아티팩트 저장소에 두는 것이 좋습니다.
에이전트 실행에 권장되는 가드레일
에이전트 워크플로는 본질적으로 동적이므로 거의 모든 다른 사용 사례보다 가드레일의 이점을 크게 얻습니다.
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 );
이러한 제어 기능은 프로덕션에서 중요한 실무 질문에 답해 줍니다. 어떤 정의 버전이 실행을 생성했는지, 중복된 외부 요청으로 같은 실행이 두 번 시작될 수 있는지, 플래너가 분기를 너무 많이 만들 수 있는지, 워크플로 상태가 무제한으로 커질 수 있는지를 확인할 수 있습니다. 대부분의 에이전트 시스템에서는 작업자 수나 큐 토폴로지를 조정하기 전에 이러한 가드레일부터 마련하세요.