Aller au contenu

Neuron Workflows dépendants

Cet exemple répond à une question fréquente sur les agents :

Un workflow peut-il décider qu’un autre ne doit poursuivre qu’après la fin d’un workflow précédent ?

Oui. La nuance importante est que Queuety prend déjà cela en charge avec wait_for_workflow() et wait_for_workflows().

Cela signifie que :

  • le workflow X peut être lancé immédiatement
  • X peut rester en attente dans waiting_for_workflows
  • X ne reprend que lorsque le workflow Y est terminé

Exemple : commencer par la recherche, puis rédiger

Utilisez un workflow de premier niveau pour constituer un dossier de recherche, puis un second pour rédiger le texte final.

Workflow de recherche

PHP
use Queuety\Enums\WaitMode;
use Queuety\Queuety;

$research_agent = Queuety::workflow('research_agent')
    ->then(ResearchTopicStep::class);

$research_id = Queuety::workflow('research_packet')
    ->then(PlanResearchTasksStep::class)
    ->start_agents('agent_tasks', $research_agent)
    ->wait_for_agents(mode: WaitMode::All, result_key: 'agent_results')
    ->then(SynthesizeResearchPacketStep::class)
    ->dispatch([
        'brief_id' => 42,
        'provider' => 'anthropic',
    ]);

Workflow de rédaction

PHP
Queuety::workflow('write_brief')
    ->wait_for_workflow('research_workflow_id', 'research')
    ->then(WriteBriefWithNeuronStep::class)
    ->wait_for_decision(result_key: 'editor_review')
    ->then(PublishBriefStep::class)
    ->dispatch([
        'brief_id' => 42,
        'research_workflow_id' => $research_id,
        'provider' => 'openai',
    ]);

Au démarrage, le workflow de rédaction se met immédiatement en pause dans waiting_for_workflows jusqu’à ce que le workflow de recherche soit terminé avec succès.

L’étape de rédaction Neuron

PHP
namespace App\Workflow\Steps;

use App\Neuron\WriterAgent;
use NeuronAI\Chat\Messages\UserMessage;
use Queuety\Step;

final class WriteBriefWithNeuronStep implements Step
{
    public function handle(array $state): array
    {
        $agent = new WriterAgent(
            providerName: $state['provider'] ?? 'openai',
        );

        $message = $agent->chat(
            new UserMessage(sprintf(
                "Write the final brief for brief %d using this research packet:\n\n%s",
                $state['brief_id'],
                json_encode($state['research'], JSON_PRETTY_PRINT),
            ))
        )->getMessage();

        return [
            'draft_markdown' => $message->getContent(),
        ];
    }

    public function config(): array
    {
        return [];
    }
}

$state['research'] est disponible parce que wait_for_workflow() a copié l’état public terminé du workflow de dépendance dans le workflow actuel, sous la clé research.

Quand préférer cette approche à un workflow géant

Préférez des workflows de premier niveau séparés lorsque :

  • les étapes ont des responsables ou des cycles opérationnels différents
  • vous souhaitez les examiner et les relancer indépendamment
  • une étape ultérieure doit pouvoir être lancée avant la fin de l’étape précédente

Préférez un seul workflow lorsque :

  • les étapes sont étroitement liées
  • elles partagent un même cycle de vie et un même ensemble d’états

La place d’une machine à états

Si ce processus de rédaction s’inscrit dans une session éditoriale de longue durée, laissez une machine à états gérer le cycle de vie global et utilisez ces workflows pour les étapes d’exécution délimitées. Les états du cycle de vie comme awaiting_brief, researching, awaiting_review et completed restent ainsi explicites, tandis que chaque phase conserve la persistance du workflow.

Une distinction importante

Ce modèle signifie que :

  • X existe déjà, mais attend Y

Cela ne signifie pas que :

  • X n’est créé qu’une fois Y terminé

Si vous voulez obtenir le second comportement, faites attendre un workflow parent jusqu’à Y, puis appelez start_workflows() ou start_agents() pour X.