Neuronのメモリとレビュー用ステートマシン
エージェントが人によるレビューを繰り返す間も会話の文脈を保持しつつ、全体のライフサイクルをQueuetyでオーケストレーションする場合に、このパターンが役立ちます。
レビュー用ステートマシンはQueuetyが管理し、Neuronは下書きスレッドのエージェントメモリを管理します。
Neuronのメモリが役立つ理由
レビュー担当者が下書きを却下して修正を求めた場合、次のエージェント呼び出しで文脈全体を一から再構築する必要はありません。
NeuronのSQLChatHistoryが適しているのは、エージェントが同じ会話スレッド内で作業を続けられ、Queuetyがレビュー担当者の判断と修正ラウンドを振り分けられるためです。
SQLを使った履歴を持つNeuronエージェント
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.',
],
);
}
}
同じメモリスレッドで下書きし、修正する
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',
];
}
}
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' ]
);
最初の処理はdraftingに入り、キューに入ったアクションを実行してからawaiting_reviewへ遷移します。
レビュー担当者が下書きを却下すると、ステートマシンはdraftingに戻ります。rejectイベントのペイロードがDraftBriefActionに渡されるため、次の下書きでは元のNeuronスレッド履歴を失わずにレビュー担当者のメモを利用できます。
ワークフローを繰り返すより適切な理由
この課題はライフサイクルに関するものです。下書きは人によるレビューを待ち、レビュー担当者は承認または却下でき、却下されるとセッションは執筆に戻り、承認されるとセッションは終了します。この流れは、後戻りのある直線的なワークフローよりも、ステートマシンで直接表現できます。
レビューラウンド数、成果物ID、ワークフローID、振り分けの判断など、オーケストレーションに関する情報にはワークフロー状態が適しています。Neuronのメモリは、以前のプロンプト、反復的な修正、執筆スレッドに残すべきモデルの応答など、会話の文脈に適しています。
両方を使うことで、それぞれのシステムに最適な役割を割り当てられます。
代わりにワークフローを使う場面
レビューの流れが明確に限定され、実行を中心とする場合は、ワークフローが適しています。たとえば、次のようなケースです。
下書きを1つ生成し、1回の承認を待って公開する。
セッションが同じ状態を何度も繰り返す可能性があり、外部イベントがライフサイクルを動かす場合は、ステートマシンが適しています。