
# 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 负责持久化编排。

如果规划器属于一个持续时间较长的代理会话，就让工作流模式负责执行层，并由 [状态机](https://queuety.inline0.dev/zh/docs/state-machines) 管理外层生命周期。

## 相关文档

- [异步交接](https://queuety.inline0.dev/zh/docs/workflows/async-handoffs)
- [代理编排](https://queuety.inline0.dev/zh/docs/workflows/agent-orchestration)
- [状态机](https://queuety.inline0.dev/zh/docs/state-machines)
