37.2 Single-agent vs multi-agent designs

Overview and links for this section of the guide.

Single vs Multi-Agent

Aspect Single Agent Multi-Agent
Complexity Simple to implement Complex orchestration
Context One context window Separate contexts per agent
Specialization Jack of all trades Expert at one thing
Parallelism Sequential only Parallel execution possible
Debugging Easier to trace Complex message passing

Single Agent Architecture

One model handles everything—planning, execution, and self-critique:

┌─────────────────────────────────────────────────────────────────┐
│                    SINGLE AGENT                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│                      ┌─────────────────┐                        │
│                      │   GEMINI PRO    │                        │
│                      │                 │                        │
│                      │  Plan + Execute │                        │
│                      │  + Self-Critique│                        │
│                      └────────┬────────┘                        │
│                               │                                  │
│         ┌─────────────────────┼─────────────────────┐           │
│         ▼                     ▼                     ▼           │
│   ┌───────────┐        ┌───────────┐        ┌───────────┐      │
│   │  file_io  │        │  search   │        │   code    │      │
│   └───────────┘        └───────────┘        └───────────┘      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
// single-agent.ts
class SingleAgent {
  async run(task: string) {
    const systemPrompt = `You are a versatile agent. 
You can plan, execute, and self-critique. 
Before acting, always think step-by-step.`;
    
    return this.loop(systemPrompt, task);
  }
}

Multi-Agent Patterns

Pattern 1: Pipeline (Sequential)

┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│ PLANNER │───▶│ CODER   │───▶│REVIEWER │───▶│ TESTER  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘
// pipeline-agents.ts
async function pipeline(task: string) {
  const plan = await plannerAgent.createPlan(task);
  const code = await coderAgent.generateCode(plan);
  const review = await reviewerAgent.review(code);
  
  if (review.approved) {
    const testResult = await testerAgent.runTests(code);
    return { code, testResult };
  }
  return { code, review, needsRevision: true };
}

Pattern 2: Supervisor (Hierarchical)

                    ┌─────────────┐
                    │ SUPERVISOR  │
                    │  (routes)   │
                    └──────┬──────┘
           ┌───────────────┼───────────────┐
           ▼               ▼               ▼
      ┌─────────┐    ┌─────────┐    ┌─────────┐
      │ AGENT_A │    │ AGENT_B │    │ AGENT_C │
      │(coding) │    │(testing)│    │(docs)   │
      └─────────┘    └─────────┘    └─────────┘
// supervisor-agent.ts
class SupervisorAgent {
  private workers: Map;
  
  async run(task: string) {
    // Supervisor decides which worker to delegate to
    const routing = await this.decide(task);
    
    switch (routing.worker) {
      case 'coder':
        return this.workers.get('coder').run(routing.subtask);
      case 'researcher':
        return this.workers.get('researcher').run(routing.subtask);
      case 'reviewer':
        return this.workers.get('reviewer').run(routing.subtask);
    }
  }
}

Pattern 3: Debate (Adversarial)

      ┌─────────┐           ┌─────────┐
      │ AGENT_A │◀─────────▶│ AGENT_B │
      │(proposes)│  debate   │(critiques)
      └────┬────┘           └────┬────┘
           └─────────┬───────────┘
                     ▼
              ┌─────────────┐
              │    JUDGE    │
              │(synthesizes)│
              └─────────────┘
// debate-agents.ts
async function debate(question: string) {
  let proposerPosition = await proposerAgent.argue(question);
  let criticPosition = await criticAgent.counter(question, proposerPosition);
  
  // Multiple rounds of debate
  for (let round = 0; round < 3; round++) {
    proposerPosition = await proposerAgent.respond(criticPosition);
    criticPosition = await criticAgent.respond(proposerPosition);
  }
  
  // Judge synthesizes final answer
  return judgeAgent.synthesize([proposerPosition, criticPosition]);
}

When to Use Each

Pattern Best For Avoid When
Single Simple tasks, prototyping Task exceeds context limits
Pipeline Well-defined sequential workflows Steps have complex dependencies
Supervisor Varying task types requiring specialization All tasks are similar
Debate Decisions requiring robust reasoning Speed is critical
Start Single, Add Agents Sparingly

Multi-agent is not automatically better. Each agent adds latency, cost, and failure points. Start with one agent and only split when you hit clear limits.

Where to go next