Перейти до вмісту

Neuron Автомат станів сесії

Цей шаблон стане в пригоді, якщо те, що ви створюєте, більше нагадує сесію, ніж одноразовий запуск.

Queuety автомати станів керують життєвим циклом сесії, Queuety робочі процеси виконують фонову роботу, для якої корисні повторні спроби, режими завершення for-each і агрегування, а Neuron виконує самі виклики агента й керує пам’яттю розмови.

Такий поділ добре підходить для помічників служби підтримки, внутрішніх дослідницьких помічників, редакційних агентів, які можуть призупинятися для перевірки людиною, і чатів, що переходять між етапами планування, очікування та відповіді.

Структура життєвого циклу

У цьому прикладі одна сесія підтримки проходить через awaiting_user, planning, waiting_on_research і responding. Автомат чітко визначає цей життєвий цикл, а фоновий робочий процес збирає дані для дослідження й повідомляє сесію про завершення.

Автомат станів

PHP
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',
    ] );

Коли користувач надсилає повідомлення:

PHP
Queuety::machine_event(
    $session_id,
    'user_message',
    [
        'session_machine_id' => $session_id,
        'message' => 'Can you compare our pricing to the main competitors?',
    ]
);

Автомат переходить у стан planning, ставить свою дію в чергу й запускає дослідницький робочий процес.

Дія планування: запустити робочий процес

PHP
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',
        ];
    }
}

Ця дія стану не виконує дослідження самостійно. Вона запускає робочий процес і записує його ID у стан автомата.

Крок робочого процесу: повідомити автомат про готовність дослідження

PHP
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 [];
    }
}

Коли робочий процес завершується, він надсилає research_completed назад до автомата й передає зведений пакет у даних події.

Дія відповіді: викликати Neuron із пам’яттю сесії

PHP
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',
        ];
    }
}

Після створення відповіді автомат повертається до awaiting_user з оновленою відповіддю у відкритому стані. Ця сама сесія може прийняти наступну подію user_message і продовжити роботу.

Чому це краще за один великий робочий процес

Основна робота і далі виконується у формі робочого процесу, оскільки дослідницька частина потребує планування, запуску спеціалізованих агентів, агрегування й синтезу. Тривала розмова зі службою підтримки натомість має бути побудована на автоматі станів, оскільки сесія повинна відстежувати, чи очікує вона на повідомлення користувача, результати дослідження або вже може надіслати відповідь.

Такий поділ робить середовище виконання зрозумілим, а модель сесії — явною.