Neuron 规划器 / 执行器
此示例使用 Queuety 进行编排,使用 Neuron 执行实际的代理任务。
这个模式很简单。Queuety 规划器步骤决定要执行哪些工作,start_agents() 将这些任务转换为彼此独立的顶层工作流;每个子工作流运行一个 Neuron 代理,而 wait_for_agents() 则将结果汇总回父工作流。
为什么这种职责划分效果很好
Neuron 适合以最少的代码改动切换提供商,并封装专业代理所需的提示、工具和记忆。Queuety 则擅长持久化的 for-each 和完成模式、重试、恢复,以及围绕运行过程提供检查或人工审核界面。
第 1 步:创建可切换提供商的 Neuron 代理
PHP
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.',
],
);
}
}
这里的实用之处在于,工作流可以通过在工作流状态中传入 provider,在运行时选择提供商。
第 2 步:在 Queuety 步骤中运行 Neuron 代理
PHP
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 [];
}
}
这是关键的集成点:Neuron 处理 LLM 调用,而 Queuety 仍负责步骤边界和持久化的工作流状态。
第 3 步:让规划器启动代理运行
PHP
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',
]);
如果 PlanResearchTasksStep 返回:
PHP
[
'agent_tasks' => [
['topic' => 'pricing'],
['topic' => 'customer reviews'],
['topic' => 'recent launches'],
],
]
Queuety 会为每个任务创建一个顶层工作流,等待它们全部完成,然后将已完成的子工作流状态放在 $state['agent_results'] 下传递。
为什么不直接在循环中调用 Neuron?
你可以这样做,但会失去编排方面的优势:
每次代理运行都无法再单独检查;发生局部崩溃时,很可能需要重启整个批次;后续阶段也不会有明确的完成节点。
这种模式让代理代码保持简单,同时由 Queuety 负责持久化编排。
如果规划器属于一个持续时间较长的代理会话,就让工作流模式负责执行层,并由 状态机 管理外层生命周期。