본문으로 건너뛰기

Neuron 스트리밍 단계

이 예제는 깔끔한 역할 분담을 보여줍니다. Neuron은 에이전트 응답을 청크 단위로 스트리밍하고, Queuety은 각 청크를 StreamingStep를 통해 지속적으로 저장합니다. 따라서 워크플로가 작업자 충돌이나 재시도에도 계속 실행되는 동안 UI은 실시간 초안을 받을 수 있습니다.

이 패턴이 유용한 경우

초안이나 응답이 길어 실시간 스트리밍이 필요하고, 작업자가 종료되어도 일부 출력을 잃지 않으려 하며, 스트리밍이 끝난 뒤 최종 결과물도 워크플로 상태에 남아야 할 때 사용하세요.

Neuron 에이전트

PHP
namespace App\Neuron;

use NeuronAI\Agent\Agent;
use NeuronAI\Providers\AIProviderInterface;
use NeuronAI\Providers\OpenAI\Responses\OpenAIResponses;
use NeuronAI\SystemPrompt;

final class DraftMemoAgent extends Agent
{
    protected function provider(): AIProviderInterface
    {
        return new OpenAIResponses(
            key: $_ENV['OPENAI_API_KEY'],
            model: $_ENV['OPENAI_MODEL'],
        );
    }

    public function instructions(): string
    {
        return (string) new SystemPrompt(
            background: [
                'You write crisp internal strategy memos.',
                'Prefer short sections and operationally useful language.',
            ],
        );
    }
}

Queuety 스트리밍 단계

PHP
namespace App\Workflow\Steps;

use App\Neuron\DraftMemoAgent;
use NeuronAI\Chat\Messages\UserMessage;
use Queuety\Contracts\StreamingStep;
use Queuety\Heartbeat;

final class StreamMemoDraftStep implements StreamingStep
{
    public function stream(array $state, array $existing_chunks = []): \Generator
    {
        if (! empty($existing_chunks)) {
            return;
        }

        $handler = (new DraftMemoAgent())->stream(
            new UserMessage(sprintf(
                "Write a strategy memo about %s for account %d.",
                $state['topic'],
                $state['account_id'],
            ))
        );

        foreach ($handler->events() as $i => $chunk) {
            Heartbeat::beat(['chunks' => $i + 1]);

            // This example assumes the agent has no tools attached, so
            // Neuron will stream text/reasoning chunks only.
            yield $chunk->content;
        }
    }

    public function on_complete(array $chunks, array $state): array
    {
        return [
            'draft_markdown' => implode('', $chunks),
        ];
    }

    public function config(): array
    {
        return [
            'max_attempts' => 3,
        ];
    }
}

워크플로에서 사용하기

PHP
use Queuety\Queuety;

Queuety::workflow('memo_drafting')
    ->then(BuildDraftBriefStep::class)
    ->then(StreamMemoDraftStep::class)
    ->then(StoreMemoStep::class)
    ->dispatch([
        'account_id' => 10,
        'topic' => 'pricing changes for enterprise accounts',
    ]);

Queuety만의 스트림 어댑터 대신 Neuron을 사용하는 이유

Neuron의 스트림 어댑터는 프런트엔드 프로토콜과 전송에 유용합니다. Queuety은 다른 기능을 제공합니다. 생성된 각 청크를 저장하고, 재시도 시 이전에 저장한 청크부터 재개하며, 완료된 초안을 워크플로 상태에 병합하고, 스트림을 더 큰 오케스트레이션에서 지속 가능한 하나의 단계로 만듭니다.

따라서 스트림이 단순한 요청/응답 UI이 아니라 여러 단계의 비즈니스 프로세스에 포함될 때 이 패턴이 적합합니다.

한 가지 유의 사항

Neuron 에이전트가 스트리밍 중 도구를 사용한다면 스트리밍 청크 유형을 명시적으로 처리하세요. Neuron의 현재 스트리밍 문서에서는 TextChunk, ReasoningChunk, ToolCallChunk 및 ToolResultChunk를 설명합니다. 백그라운드 초안 작성 워크플로에서는 보통 스트리밍 에이전트가 텍스트만 처리하도록 하는 것이 가장 간단합니다.