← Back to Blog

Building Multi-Agent Pipelines on ThetaZero

A single agent is good at following instructions. A pipeline of agents — each specialized, each doing one thing well — is genuinely useful for production workloads.

This article covers the architecture we use for multi-agent pipelines on ThetaZero: how to design agent roles, how to pass context between agents, how to handle failures, and when to use a coordinator vs. a sequential chain.

🏗️
What you'll build: A 3-agent pipeline — Researcher → Analyst → Writer — that takes a topic, gathers data, synthesizes insights, and produces a polished report. Fully automated.

Why Multi-Agent?

The core insight is specialization reduces context contamination. When you ask a single agent to research, analyze, and write — all in one prompt — it compromises on each. The research phase pollutes the writing phase with raw noise. The writing phase rushes the analysis.

With separate agents:

  • Each agent has a focused system prompt tuned for its role
  • Each agent's context window is used only for its specific task
  • You can retry individual stages without rerunning the whole pipeline
  • You can swap in a cheaper model for simpler stages (e.g., use claude-haiku-4 for the Writer)

The tradeoff: more orchestration complexity and higher latency. For scheduled, async workloads — this is almost always worth it.

Pipeline Architecture

Here's the pipeline we'll build:

1
Coordinator
Receives goal → decomposes into subtasks → dispatches to agents
orchestrator
↓
2
Researcher
Web search + scraping → saves raw findings to shared context
web tools
↓
3
Analyst
Reads raw findings → extracts patterns → produces structured insights
analysis
↓
4
Writer
Takes structured insights → formats final report → saves + notifies
output

The Shared Context Store

Agents in a pipeline communicate via a shared context store — a key-value store scoped to the pipeline execution. Each agent reads the outputs of previous agents and writes its own output.

ThetaZero's Swarm Context API provides this out of the box:

// Researcher agent writes its findings
await ThetaZero.context.write('research/raw_findings', {
  sources: [...],
  quotes: [...],
  data_points: [...],
  gaps: [...]  // What couldn't be found
});

// Analyst agent reads researcher output
const research = await ThetaZero.context.read('research/raw_findings');
// ... processes ...
await ThetaZero.context.write('analysis/insights', {
  key_findings: [...],
  confidence_scores: {...},
  recommended_angles: [...]
});

// Writer reads analyst output
const insights = await ThetaZero.context.read('analysis/insights');
// ... writes report ...

The namespace structure (research/, analysis/) keeps outputs organized and avoids collisions.

The Coordinator Pattern

The Coordinator is an agent that doesn't do the work — it decides how to decompose the goal and dispatches subtasks to the right agents. This is the most important agent in a complex pipeline.

// Coordinator system prompt
const COORDINATOR_PROMPT = `You are a pipeline coordinator.
Your job is to break down the user's goal into specific subtasks
and dispatch them to the right agents.

Available agents:
- researcher: Gathers raw information from the web
- analyst: Extracts patterns and insights from raw data
- writer: Produces polished, formatted reports

Rules:
1. Always start with the researcher
2. Pass specific search queries to the researcher, not vague goals
3. Tell the analyst what to look for — don't just dump raw data
4. Tell the writer the format, audience, and tone

Output a JSON task plan with agent, instruction, and dependencies.`;

// Example coordinator output
const taskPlan = {
  tasks: [
    {
      id: "t1",
      agent: "researcher",
      instruction: "Search for and scrape these 5 competitor pricing pages. Extract: tier names, monthly prices, feature limits per tier, any recent pricing changes (check Wayback Machine for last 90 days).",
      dependencies: []
    },
    {
      id: "t2",
      agent: "analyst",
      instruction: "Analyze the competitor pricing data. Find: price clustering points, feature differentiation patterns, which features are always in highest tier. Rate competitive positioning for each competitor 1-10.",
      dependencies: ["t1"]
    },
    {
      id: "t3",
      agent: "writer",
      instruction: "Write a pricing strategy briefing for our product team. Audience: B2B SaaS product managers. Tone: direct and data-driven. Include a comparison table and 3 concrete recommendations.",
      dependencies: ["t2"]
    }
  ]
};

Error Handling and Retries

In production pipelines, individual agents will fail. The pattern we use:

async function runPipelineStage(agentId, taskInstruction, maxRetries = 2) {
  let attempt = 0;

  while (attempt <= maxRetries) {
    try {
      const result = await ThetaZero.agents.run(agentId, {
        task: taskInstruction,
        timeout_ms: 120_000,  // 2 minute timeout per stage
      });

      if (result.status === 'completed') {
        return result;
      }

      // Partial success — log and retry with modified instruction
      if (result.status === 'partial' && attempt < maxRetries) {
        taskInstruction = `Previous attempt was incomplete: ${result.partial_output}.
        Retry and fill in what's missing. Don't repeat what was already done.`;
      }

    } catch (err) {
      console.error(`Stage ${agentId} failed (attempt ${attempt + 1}):`, err.message);
    }

    attempt++;
    if (attempt <= maxRetries) {
      await sleep(2000 * attempt);  // Exponential backoff
    }
  }

  throw new Error(`Pipeline stage ${agentId} failed after ${maxRetries + 1} attempts`);
}
⚠️
Important: Always set explicit timeouts per stage. An agent stuck in a web fetch loop can block an entire pipeline indefinitely without one.

Model Selection by Stage

Not every stage needs the most powerful model. Here's our production selection:

Stage Model Reason
Coordinator claude-opus-4 High-stakes reasoning — decomposing the goal correctly
Researcher claude-sonnet-4 Tool use + judgment on source quality
Analyst claude-opus-4 Pattern recognition + nuanced insight extraction
Writer claude-haiku-4 Formatting structured data — speed over depth

This saves roughly 40% on model costs vs. using Opus for every stage.

Putting It Together

Here's the full orchestration code for a research → analysis → report pipeline:

const ThetaZero = require('@thetazero/sdk');
const tz = new ThetaZero({ apiKey: process.env.TZ_API_KEY });

async function runResearchPipeline(topic) {
  const pipelineId = `research-${Date.now()}`;
  console.log(`Starting pipeline: ${pipelineId}`);

  // Stage 1: Research
  console.log('[1/3] Researcher running...');
  await tz.agents.run('researcher', {
    pipelineId,
    task: `Research the following topic thoroughly: "${topic}".
    Search for recent developments (last 6 months), key statistics,
    expert opinions, and contrarian views. Save findings to context.`,
    model: 'claude-sonnet-4',
    tools: ['web_search', 'web_fetch', 'save_context'],
  });

  // Stage 2: Analysis
  console.log('[2/3] Analyst running...');
  const research = await tz.context.read(pipelineId, 'research/raw_findings');
  await tz.agents.run('analyst', {
    pipelineId,
    task: `Analyze the research findings and extract the 5 most important
    insights. For each insight, provide: supporting evidence, confidence
    level (1-10), and business implications. Input: ${JSON.stringify(research)}`,
    model: 'claude-opus-4',
    tools: ['save_context'],
  });

  // Stage 3: Write
  console.log('[3/3] Writer running...');
  const insights = await tz.context.read(pipelineId, 'analysis/insights');
  const report = await tz.agents.run('writer', {
    pipelineId,
    task: `Write a concise executive briefing on "${topic}" based on these
    insights: ${JSON.stringify(insights)}. Format: markdown.
    Include: TL;DR (3 bullets), Key Findings section, Implications,
    Recommended Actions. Max 600 words.`,
    model: 'claude-haiku-4',
    tools: ['save_report'],
  });

  console.log(`Pipeline complete. Report saved.`);
  return report;
}

// Run it
runResearchPipeline('AI agent compute costs in 2026')
  .then(report => console.log('Done:', report.reportId))
  .catch(err => console.error('Pipeline failed:', err));

When NOT to Use a Pipeline

Pipelines add latency and complexity. Use a single agent when:

  • The task is under 5 minutes and fits in one context window
  • You need interactive, low-latency output (user is watching)
  • The task doesn't benefit from specialization — e.g., "summarize this text"

Upgrade to a pipeline when:

  • The task has distinct phases with different skill requirements
  • You're hitting context window limits in a single agent
  • You want to parallelize independent research tasks (run multiple researchers simultaneously)
  • You need quality checkpoints between stages

Next Steps

The pipeline in this tutorial runs sequentially. The next level is parallel orchestration — running multiple Researcher agents simultaneously on different subtopics, then merging their outputs in the Analyst stage. That reduces latency by 60–70% for research-heavy workloads.

We'll cover that pattern, plus circuit breakers and dead letter queues, in a follow-up post.

Ready to build your first multi-agent pipeline?

The Swarm Coordinator, context store, and all the tools in this tutorial are live on ThetaZero. Start for free.

Try ThetaZero free →