Neuron Maszyna stanów sesji
Ten wzorzec sprawdza się, gdy tworzony system bardziej przypomina sesję niż jednorazowe uruchomienie.
Maszyny stanów Queuety zarządzają cyklem życia sesji, przepływy pracy Queuety wykonują zadania w tle, które korzystają z ponawiania prób, trybów zakończenia for-each i agregacji, a Neuron obsługuje właściwe wywołania agenta i pamięć konwersacji.
Ten podział sprawdza się w przypadku asystentów wsparcia, wewnętrznych asystentów badawczych, agentów redakcyjnych, którzy mogą czekać na weryfikację przez człowieka, oraz wątków czatu przechodzących między etapami planowania, oczekiwania i odpowiedzi.
Przebieg cyklu życia
W tym przykładzie sesja wsparcia przechodzi przez stany awaiting_user, planning, waiting_on_research i responding. Maszyna jawnie zarządza tym cyklem życia, a przepływ pracy w tle gromadzi materiały badawcze i sygnalizuje sesji zakończenie zadania.
Maszyna stanów
use Queuety\Queuety;
$session_id = Queuety::machine( 'support_session' )
->version( 'support-session.v1' )
->state( 'awaiting_user' )
->on( 'user_message', 'planning' )
->state( 'planning' )
->action( DispatchResearchWorkflowAction::class )
->on( 'research_dispatched', 'waiting_on_research' )
->state( 'waiting_on_research' )
->on( 'research_completed', 'responding' )
->state( 'responding' )
->action( RespondWithNeuronAction::class )
->on( 'response_ready', 'awaiting_user' )
->dispatch( [
'thread_id' => 'support:customer-42',
] );
Gdy użytkownik wyśle wiadomość:
Queuety::machine_event(
$session_id,
'user_message',
[
'session_machine_id' => $session_id,
'message' => 'Can you compare our pricing to the main competitors?',
]
);
Maszyna przechodzi do planning, kolejkuje swoją akcję i uruchamia przepływ badawczy.
Akcja planowania: uruchom przepływ pracy
namespace App\StateMachines\Actions;
use Queuety\Contracts\StateAction;
use Queuety\Enums\WaitMode;
use Queuety\Queuety;
final class DispatchResearchWorkflowAction implements StateAction
{
public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string
{
$message = trim( (string) ( $event_payload['message'] ?? '' ) );
$agent_workflow = Queuety::workflow( 'support_research_agent' )
->then( ResearchTopicStep::class );
$research_workflow = Queuety::workflow( 'support_research_packet' )
->then( PlanResearchTasksStep::class )
->start_agents( 'agent_tasks', $agent_workflow )
->wait_for_agents( mode: WaitMode::All, result_key: 'agent_results' )
->then( SynthesizeResearchPacketStep::class )
->then( NotifySessionResearchReadyStep::class );
$workflow_id = $research_workflow->dispatch( [
'machine_id' => $state['session_machine_id'],
'thread_id' => $state['thread_id'],
'customer_prompt' => $message,
] );
return [
'latest_user_message' => $message,
'research_workflow_id' => $workflow_id,
'_event' => 'research_dispatched',
];
}
}
Ta akcja stanu nie próbuje samodzielnie przeprowadzać badań. Uruchamia przepływ pracy i zapisuje jego ID w stanie maszyny.
Krok przepływu pracy: powiadom maszynę, gdy badania będą gotowe
namespace App\Workflow\Steps;
use Queuety\Queuety;
use Queuety\Step;
final class NotifySessionResearchReadyStep implements Step
{
public function handle( array $state ): array
{
Queuety::machine_event(
$state['machine_id'],
'research_completed',
[
'research_packet' => $state['research_packet'],
]
);
return [];
}
public function config(): array
{
return [];
}
}
Po zakończeniu przepływ pracy wysyła research_completed z powrotem do maszyny i dołącza przygotowany pakiet jako dane zdarzenia.
Akcja odpowiadania: wywołaj Neuron z pamięcią sesji
namespace App\StateMachines\Actions;
use App\Neuron\SupportAgent;
use NeuronAI\Chat\Messages\UserMessage;
use Queuety\Contracts\StateAction;
final class RespondWithNeuronAction implements StateAction
{
public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string
{
// Queuety creates actions with `new RespondWithNeuronAction()`, so build dependencies here.
$pdo = new \PDO( $_ENV['NEURON_DB_DSN'], $_ENV['NEURON_DB_USER'], $_ENV['NEURON_DB_PASSWORD'] );
$agent = new SupportAgent(
threadId: $state['thread_id'],
pdo: $pdo,
);
$message = $agent->chat(
new UserMessage(
sprintf(
"Answer the user message '%s' using this research packet:\n\n%s",
$state['latest_user_message'],
json_encode( $state['research_packet'] ?? [], JSON_PRETTY_PRINT )
)
)
)->getMessage();
return [
'assistant_reply' => $message->getContent(),
'_event' => 'response_ready',
];
}
}
Po wygenerowaniu odpowiedzi maszyna przechodzi z powrotem do awaiting_user, zapisując zaktualizowaną odpowiedź w stanie publicznym. Ta sama sesja może wtedy przyjąć kolejne zdarzenie user_message i kontynuować.
Dlaczego to rozwiązanie jest lepsze niż jeden duży przepływ pracy
Złożone zadania nadal realizuje przepływ pracy, ponieważ część badawcza wymaga planowania, uruchamiania wyspecjalizowanych agentów, agregacji i syntezy. Długotrwałą rozmowę wsparcia lepiej obsługuje maszyna stanów, ponieważ sesja musi śledzić, czy czeka na wiadomość użytkownika, wyniki badań, czy może już wysłać odpowiedź.
Ten podział ułatwia zrozumienie działania środowiska uruchomieniowego i jawnie określa model sesji.