DEV Community

Khaled Hammrouni
Khaled Hammrouni

Posted on

08 - Multi-Agent Workflow in PHP - Chain a Researcher into a Writer

A single agent can do a lot, but some jobs are cleaner as a pipeline: one agent gathers, another refines. The pattern is "agent chain" - the output of agent A becomes the input of agent B. Each agent has a narrow role and a focused system prompt, which is more reliable than one overloaded prompt trying to do both.

This example: a Researcher pulls facts, a Writer turns them into a polished post.

Two agents, one data flow

A mock research tool stands in for a real data source - a lookup table keyed by topic, so the example runs with zero external dependencies.

use NanoAgent\Agent;
use NanoAgent\Tools\FunctionTool;

$researchTool = new FunctionTool(
    name: 'fetch_topic_facts',
    description: 'Retrieves interesting facts about a given topic.',
    parameters: [
        'type' => 'object',
        'properties' => [
            'topic' => ['type' => 'string', 'description' => 'The subject to research']
        ],
        'required' => ['topic']
    ],
    callable: function (array $args) {
        $knowledge = [
            'php' => ['Created by Rasmus Lerdorf in 1994.',
                      'Powers over 75% of websites with a known server-side language.',
                      'The latest version is 8.4.'],
            'ai'  => ['The term AI was coined in 1956.',
                      'Transformer architecture (2017) revolutionized NLP.']
        ];
        return $knowledge[strtolower($args['topic'])]
             ?? ["No specific facts found for '{$args['topic']}'."];
    }
);
Enter fullscreen mode Exit fullscreen mode

1. The Researcher - its only job is to gather

Its system prompt is narrow on purpose: fetch facts with the tool, return them as a list, nothing more.

$researcher = new Agent(
    llm: $llmConfig,
    systemPrompt: "You are a research specialist. Use the 'fetch_topic_facts' tool to "
                . "gather raw data. Return only the collected facts in a list.",
    tools: [$researchTool]
);
Enter fullscreen mode Exit fullscreen mode

2. The Writer - its only job is to polish, and NOT invent

The Writer gets no tools at all - it only ever sees text the Researcher already gathered, and its prompt explicitly forbids adding facts of its own.

$writer = new Agent(
    llm: $llmConfig,
    systemPrompt: "You are a creative content writer. Transform raw research facts into an "
                . "engaging social media post with hashtags. Do not invent facts that were "
                . "not provided."
);
Enter fullscreen mode Exit fullscreen mode

Run the chain

$topic = 'PHP';

$research = $researcher->chat("Research the topic: $topic");
// e.g. "1. Created by Rasmus Lerdorf in 1994. 2. Powers over 75% of websites..."

$post = $writer->chat("Write a post based on these facts:\n\n" . $research);
echo $post;
Enter fullscreen mode Exit fullscreen mode

The seam is trivial: $writer->chat(... $research ...) - the Researcher's string is just the Writer's prompt. There's no framework, no message bus, no orchestration library. A chain is literally one chat() result fed into the next chat().

Why split it instead of one big agent?

  • Focus beats scope. A prompt that says "research AND write well AND don't hallucinate" does all three poorly. Two prompts do each one well.
  • Different models per stage. The Researcher can be cheap and fast; the Writer can be your best model. You choose per agent because each is its own new Agent(llm: ...).
  • Isolated failure. If research returns junk, you see it before it pollutes the final output. You can validate between stages.
  • Composability. Add a third stage (a Critique agent, a translator) by appending one chat() call.

Where this goes next

  • Researcher → Writer → Critic - a third agent scores the post and the loop retries if it's weak.
  • Fan-out - several Researcher agents on sub-topics, then one Writer merges.
  • Each stage can carry its own tools - the Researcher with a search tool, the Writer with a brand-voice tool.

The mental model: an agent is a function; a workflow is a composition of functions. PHP makes that composition boring in the best way - just call them in order.


Part of the NanoAgent examples series. Landing + demos.

Top comments (0)