Preskočiť na obsah

Neuron Stavový automat pamäte a kontroly

Tento vzor je užitočný, keď si má agent zachovať konverzačný kontext počas opakovaných kôl ľudskej kontroly, pričom celkový životný cyklus má naďalej riadiť Queuety.

Queuety spravuje stavový automat kontroly, zatiaľ čo Neuron spravuje pamäť agenta pre vlákno s návrhom.

Prečo tu pomáha pamäť Neuron

Ak kontrolór návrh odmietne a požiada o úpravy, ďalšie volanie agenta by nemalo musieť znova skladať celý kontext od začiatku.

Funkcia SQLChatHistory v Neuron sa na to hodí, pretože agent môže pokračovať v práci v tom istom konverzačnom vlákne, zatiaľ čo Queuety spracúva rozhodnutia kontrolóra a kolá úprav.

Agent Neuron s históriou založenou na SQL

PHP
namespace App\Neuron;

use NeuronAI\Agent\Agent;
use NeuronAI\Chat\History\ChatHistoryInterface;
use NeuronAI\Chat\History\SQLChatHistory;
use NeuronAI\Providers\AIProviderInterface;
use NeuronAI\Providers\Anthropic\Anthropic;
use NeuronAI\SystemPrompt;

final class EditorAgent extends Agent
{
    public function __construct(
        private readonly string $threadId,
        private readonly \PDO $pdo,
    ) {}

    protected function provider(): AIProviderInterface
    {
        return new Anthropic(
            key: $_ENV['ANTHROPIC_API_KEY'],
            model: $_ENV['ANTHROPIC_MODEL'],
        );
    }

    protected function chatHistory(): ChatHistoryInterface
    {
        return new SQLChatHistory(
            thread_id: $this->threadId,
            pdo: $this->pdo,
            table: 'neuron_chat_history',
            contextWindow: 50000,
        );
    }

    public function instructions(): string
    {
        return (string) new SystemPrompt(
            background: [
                'You are an editorial agent for long-form product briefs.',
                'Apply reviewer notes without losing the original intent.',
            ],
        );
    }
}

Najprv vytvorte návrh, potom ho upravujte v tom istom vlákne pamäte

PHP
namespace App\StateMachines\Actions;

use App\Neuron\EditorAgent;
use NeuronAI\Chat\Messages\UserMessage;
use Queuety\Contracts\StateAction;

final class DraftBriefAction implements StateAction
{
    public function handle(array $state, ?string $event = null, array $event_payload = [], array $payload = []): array|string
    {
        // Queuety creates actions with `new DraftBriefAction()`, so build dependencies here.
        $pdo = new \PDO($_ENV['NEURON_DB_DSN'], $_ENV['NEURON_DB_USER'], $_ENV['NEURON_DB_PASSWORD']);

        $threadId = $state['neuron_thread_id'] ?? sprintf(
            'brief:%d:editor',
            $state['brief_id'],
        );

        $prompt = "Write the first draft for brief {$state['brief_id']}.";

        if ('reject' === $event) {
            $prompt = sprintf(
                'Revise the draft using these review notes: %s',
                $event_payload['reason'] ?? 'Tighten the draft and address reviewer concerns.',
            );
        }

        $agent = new EditorAgent($threadId, $pdo);
        $message = $agent->chat(
            new UserMessage($prompt)
        )->getMessage();

        return [
            'neuron_thread_id' => $threadId,
            'draft_markdown' => $message->getContent(),
            'review_round' => (int) ($state['review_round'] ?? 0) + 1,
            '_event' => 'draft_ready',
        ];
    }
}

Stavový automat Queuety

PHP
use Queuety\Enums\StateMachineStatus;
use Queuety\Queuety;

$machine_id = Queuety::machine('brief_review_session')
    ->version('brief-review-session.v1')
    ->state('drafting')
    ->action(DraftBriefAction::class)
    ->on('draft_ready', 'awaiting_review')
    ->state('awaiting_review')
    ->on('approve', 'completed')
    ->on('reject', 'drafting')
    ->state('completed', StateMachineStatus::Completed)
    ->dispatch([
        'brief_id' => 42,
    ]);

// Later, once the draft action has finished and the machine waits in `awaiting_review`:
Queuety::machine_event(
    $machine_id,
    'reject',
    [ 'reason' => 'Tighten the introduction and add pricing context.' ]
);

Queuety::machine_event(
    $machine_id,
    'approve',
    [ 'reviewer' => 'editor@example.com' ]
);

Prvé kolo prejde do stavu drafting, vykoná zaradenú akciu a prejde do stavu awaiting_review.

Ak kontrolór návrh odmietne, automat sa vráti do stavu drafting. Keďže obsah udalosti reject sa odovzdá do DraftBriefAction, ďalší návrh môže využiť poznámky kontrolóra bez straty pôvodnej histórie vlákna Neuron.

Prečo je to prehľadnejšie než opakovanie workflowu

Tento problém sa týka životného cyklu. Návrh čaká na ľudskú kontrolu, kontrolór ho môže schváliť alebo odmietnuť, po odmietnutí sa relácia vráti k tvorbe návrhu a po schválení sa ukončí. To sa dá prirodzenejšie vyjadriť stavovým automatom než lineárnym workflowom so spätnou väzbou.

Stav workflowu sa stále výborne hodí na fakty súvisiace s orchestráciou, ako sú počet kôl kontroly, ID artefaktov, ID workflowov a rozhodnutia o smerovaní. Pamäť Neuron je vhodnejšia na konverzačný kontext, napríklad predchádzajúce pokyny, postupné úpravy a odpovede modelu, ktoré majú zostať súčasťou vlákna s návrhom.

Kombináciou oboch systémov priradíte každému úlohu, na ktorú sa najlepšie hodí.

Kedy namiesto toho ponechať workflow

Workflow uprednostnite, keď je proces kontroly jasne ohraničený a zameraný na vykonávanie, napríklad:

Vytvorte jeden návrh, počkajte na jedno schválenie a zverejnite ho.

Stavový automat uprednostnite, keď sa relácia môže opakovane vracať do tých istých stavov a jej životný cyklus riadia vonkajšie udalosti.