Neuron Planlægger / Executor
Dette eksempel bruger Queuety til orkestrering og Neuron til selve agentkørslen.
Mønstret er enkelt. Et Queuety-planlæggertrin beslutter, hvilket arbejde der skal udføres, start_agents() omsætter opgaverne til selvstændige workflows på øverste niveau, hvert underordnet workflow kører en Neuron-agent, og wait_for_agents() samler resultaterne i det overordnede workflow.
Hvorfor denne opdeling fungerer godt
Neuron er velegnet til at skifte udbyder med minimale kodeændringer og samle prompt, værktøjer og hukommelse for en specialistagent. Queuety er velegnet til holdbar for-each- og færdiggørelsestilstand, nye forsøg, genoptagelse samt overblik og menneskelig gennemgang af kørslen.
Trin 1: Opret en Neuron-agent, hvor udbyderen kan skiftes
namespace App\Neuron;
use NeuronAI\Agent\Agent;
use NeuronAI\Providers\AIProviderInterface;
use NeuronAI\Providers\Anthropic\Anthropic;
use NeuronAI\Providers\Gemini\Gemini;
use NeuronAI\Providers\OpenAI\Responses\OpenAIResponses;
use NeuronAI\SystemPrompt;
final class ResearchAgent extends Agent
{
public function __construct(
private readonly string $providerName = 'openai',
) {}
protected function provider(): AIProviderInterface
{
return match ($this->providerName) {
'anthropic' => new Anthropic(
key: $_ENV['ANTHROPIC_API_KEY'],
model: $_ENV['ANTHROPIC_MODEL'],
),
'gemini' => new Gemini(
key: $_ENV['GEMINI_API_KEY'],
model: $_ENV['GEMINI_MODEL'],
),
default => new OpenAIResponses(
key: $_ENV['OPENAI_API_KEY'],
model: $_ENV['OPENAI_MODEL'],
),
};
}
public function instructions(): string
{
return (string) new SystemPrompt(
background: [
'You are a research agent.',
'Return concise, source-aware summaries for the assigned topic.',
],
);
}
}
Det nyttige her er, at workflowet kan vælge udbyder ved kørsel ved at videregive provider i workflowtilstanden.
Trin 2: Kør Neuron-agenten i et Queuety-trin
namespace App\Workflow\Steps;
use App\Neuron\ResearchAgent;
use NeuronAI\Chat\Messages\UserMessage;
use Queuety\Step;
final class ResearchTopicStep implements Step
{
public function handle(array $state): array
{
$agent = new ResearchAgent(
providerName: $state['provider'] ?? 'openai',
);
$message = $agent->chat(
new UserMessage(sprintf(
"Research the topic '%s' for brief %d. Return a compact bullet summary.",
$state['topic'],
$state['brief_id'],
))
)->getMessage();
return [
'summary' => $message->getContent(),
];
}
public function config(): array
{
return [];
}
}
Dette er det centrale integrationspunkt: Neuron håndterer LLM-kaldet, men Queuety ejer stadig trinets grænse og den gemte workflowtilstand.
Trin 3: Lad planlæggeren starte agentkørsler
use Queuety\Enums\WaitMode;
use Queuety\Queuety;
$agent_workflow = Queuety::workflow('research_agent_run')
->then(ResearchTopicStep::class);
Queuety::workflow('brief_research')
->version('brief-research.v1')
->then(PlanResearchTasksStep::class) // writes $state['agent_tasks']
->start_agents('agent_tasks', $agent_workflow)
->wait_for_agents(mode: WaitMode::All, result_key: 'agent_results')
->then(SynthesizeBriefStep::class)
->dispatch([
'brief_id' => 42,
'provider' => 'anthropic',
]);
Hvis PlanResearchTasksStep returnerer:
[
'agent_tasks' => [
['topic' => 'pricing'],
['topic' => 'customer reviews'],
['topic' => 'recent launches'],
],
]
Queuety opretter ét workflow på øverste niveau pr. opgave, venter, indtil de alle er færdige, og videregiver derefter tilstanden for de færdige underordnede workflows under $state['agent_results'].
Hvorfor ikke bare kalde Neuron i en løkke?
Det kan du godt, men så mister du fordelene ved orkestrering:
Hver agentkørsel kan ikke længere inspiceres individuelt, et delvist nedbrud vil sandsynligvis genstarte hele kørslen, og der vil ikke være et klart afslutningspunkt for senere trin.
Dette mønster holder agentkoden enkel, mens Queuety står for den holdbare orkestrering.
Hvis planlæggeren hører til en langvarig agentsession, så brug dette workflowmønster til udførelseslaget, og lad en tilstandsmaskine styre den overordnede livscyklus.