Neuron Memoria e macchina a stati per la revisione
Questo schema è utile quando un agente deve mantenere il contesto della conversazione durante più cicli di revisione umana, mentre il ciclo di vita complessivo deve restare orchestrato da Queuety.
Queuety gestisce la macchina a stati della revisione, mentre Neuron gestisce la memoria dell'agente per la conversazione di stesura.
Perché qui è utile la memoria Neuron
Se un revisore rifiuta una bozza e chiede delle modifiche, la chiamata successiva dell'agente non dovrebbe dover ricostruire tutto il contesto da zero.
Neuron di SQLChatHistory è adatto a questo scopo perché l'agente può continuare a lavorare nella stessa conversazione, mentre Queuety gestisce le decisioni del revisore e i cicli di revisione.
L'agente Neuron con cronologia basata su SQL
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.',
],
);
}
}
Scrivi una bozza, poi rivedila mantenendo lo stesso contesto
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',
];
}
}
La macchina a stati Queuety
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' ]
);
Il primo passaggio entra in drafting, esegue l'azione accodata e passa a awaiting_review.
Se il revisore rifiuta la bozza, la macchina torna a drafting. Poiché il payload dell'evento reject viene passato a DraftBriefAction, la bozza successiva può includere le note del revisore senza perdere la cronologia originale della conversazione Neuron.
Perché è più semplice di ripetere un workflow
Questo problema riguarda il ciclo di vita. Una bozza attende la revisione umana; il revisore può approvarla o rifiutarla; in caso di rifiuto, la sessione torna alla stesura; con l'approvazione, la sessione termina. Questo schema si adatta più direttamente a una macchina a stati che a un workflow lineare con un collegamento all'indietro.
Lo stato del workflow è comunque ottimo per i dati di orchestrazione, come il numero di cicli di revisione, gli ID degli artefatti e dei workflow e le decisioni di instradamento. La memoria di Neuron è più adatta al contesto conversazionale, come i prompt precedenti, le revisioni iterative e le risposte del modello che devono restare parte della conversazione di stesura.
Usare entrambi assegna a ogni sistema il compito per cui è più adatto.
Quando mantenere questo approccio come workflow
Preferisci un workflow quando il percorso di revisione è ben circoscritto e orientato all'esecuzione, ad esempio:
Genera una bozza, attendi un'approvazione e pubblica.
Preferisci una macchina a stati quando la sessione può tornare più volte agli stessi stati e gli eventi esterni ne determinano il ciclo di vita.