Multi-Agent Design Patterns

Multiple agents collaborating: Group Chat, Hand-off, Round Robin, and when to use them

When Do You Need Multi-Agent?

A single agent is enough for most tasks. But some scenarios need multiple agents:

  • Specialization: Each agent excels in one area (code, design, research…)
  • Scale: Tasks too large for one agent
  • Natural interaction: Agents discuss to reach better outcomes
  • Checks & balances: Agent A reviews Agent B’s output

Key Patterns

1. Sequential (Hand-off)

Agents pass results to each other in a chain:

Agent A → Agent B → Agent C → Final Output
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";

async function researcher(topic: string) {
  const result = await generateText({
    model: openai("gpt-4o"),
    system: "You are a researcher. Find detailed information on the topic.",
    tools: { searchWeb },
    maxSteps: 5,
    prompt: `Research: ${topic}`
  });
  return result.text;
}

async function writer(research: string) {
  const result = await generateText({
    model: openai("gpt-4o"),
    system: "You are a tech writer. Write articles from research data.",
    prompt: `Write a blog from this research:\n${research}`
  });
  return result.text;
}

async function editor(draft: string) {
  const result = await generateText({
    model: openai("gpt-4o"),
    system: "You are an editor. Review and improve the article.",
    prompt: `Review and edit:\n${draft}`
  });
  return result.text;
}

async function contentPipeline(topic: string) {
  const research = await researcher(topic);
  const draft = await writer(research);
  const finalArticle = await editor(draft);
  return finalArticle;
}

2. Parallel (Concurrent)

Agents work simultaneously, results are aggregated:

async function parallelAnalysis(codebase: string) {
  const [security, performance, accessibility] = await Promise.all([
    generateText({
      model: openai("gpt-4o"),
      system: "You are a security auditor. Find vulnerabilities.",
      prompt: `Audit security:\n${codebase}`
    }),
    generateText({
      model: openai("gpt-4o"),
      system: "You are a performance engineer. Find bottlenecks.",
      prompt: `Audit performance:\n${codebase}`
    }),
    generateText({
      model: openai("gpt-4o"),
      system: "You are an accessibility expert. Check WCAG compliance.",
      prompt: `Audit accessibility:\n${codebase}`
    })
  ]);

  return {
    security: security.text,
    performance: performance.text,
    accessibility: accessibility.text
  };
}

3. Group Chat

Multiple agents discuss with each other, like a meeting:

interface AgentConfig {
  name: string;
  role: string;
  system: string;
}

async function groupChat(
  agents: AgentConfig[],
  topic: string,
  maxRounds: number = 5
) {
  const messages: { agent: string; content: string }[] = [];

  for (let round = 0; round < maxRounds; round++) {
    for (const agent of agents) {
      const context = messages
        .map(m => `[${m.agent}]: ${m.content}`)
        .join("\n");

      const response = await generateText({
        model: openai("gpt-4o-mini"),
        system: `${agent.system}
You are in a group discussion.
Keep responses concise, focused on your role's perspective.
If consensus is reached, say "CONSENSUS".`,
        prompt: `Topic: ${topic}\n\nDiscussion history:\n${context}\n\nYour response:`
      });

      messages.push({ agent: agent.name, content: response.text });

      if (response.text.includes("CONSENSUS")) {
        return { messages, consensus: true };
      }
    }
  }

  return { messages, consensus: false };
}

const result = await groupChat(
  [
    { name: "Frontend Dev", role: "frontend", system: "You are a React frontend developer." },
    { name: "Backend Dev", role: "backend", system: "You are a Node.js backend developer." },
    { name: "DevOps", role: "devops", system: "You are a DevOps engineer." }
  ],
  "Should we use SSR or CSR for an e-commerce app?"
);

4. Supervisor Pattern

One agent orchestrates the others:

async function supervisor(task: string) {
  const { object: plan } = await generateObject({
    model: openai("gpt-4o"),
    schema: z.object({
      subtasks: z.array(z.object({
        description: z.string(),
        assignTo: z.enum(["researcher", "coder", "reviewer"]),
        priority: z.number()
      }))
    }),
    prompt: `Analyze and assign to appropriate agents: ${task}`
  });

  const results = [];
  for (const subtask of plan.subtasks.sort((a, b) => a.priority - b.priority)) {
    const agentFn = getAgent(subtask.assignTo);
    const result = await agentFn(subtask.description);
    results.push({ subtask: subtask.description, result });
  }

  return results;
}

Multi-Agent With CrewAI (Python)

from crewai import Agent, Task, Crew, Process

pm = Agent(
    role="Product Manager",
    goal="Define requirements and prioritize features",
    llm="gpt-4o-mini"
)

dev = Agent(
    role="Senior Developer",
    goal="Implement features according to requirements",
    llm="gpt-4o-mini"
)

qa = Agent(
    role="QA Engineer",
    goal="Test and find bugs in implementation",
    llm="gpt-4o-mini"
)

crew = Crew(
    agents=[pm, dev, qa],
    tasks=[
        Task(description="Analyze requirements", agent=pm),
        Task(description="Implement solution", agent=dev),
        Task(description="Test and review", agent=qa)
    ],
    process=Process.sequential  # or Process.hierarchical
)

Which Pattern to Choose?

ScenarioPattern
Content pipeline (research → write → edit)Sequential
Code audit (security + performance + a11y)Parallel
Design review needing multiple perspectivesGroup Chat
Complex task requiring coordinationSupervisor
Simple automation chainSequential

Summary

  • Sequential: Pass results through a chain of agents
  • Parallel: Agents work simultaneously, results aggregated
  • Group Chat: Agents discuss to reach consensus
  • Supervisor: One agent orchestrates the others
  • Start with a single agent, only use multi-agent when truly needed