674 lines
18 KiB
Markdown
674 lines
18 KiB
Markdown
# The Orchestrator Pattern
|
|
|
|
> "The rate at which you can create and command your agents becomes the constraint of your engineering output. When your agents are slow, you're slow."
|
|
|
|
The orchestrator pattern is **Level 5** of agentic engineering: managing fleets of agents through a single interface.
|
|
|
|
## The Journey to Orchestration
|
|
|
|
```text
|
|
Level 1: Base agents → Use agents out of the box
|
|
Level 2: Better agents → Customize prompts and workflows
|
|
Level 3: More agents → Run multiple agents
|
|
Level 4: Custom agents → Build specialized solutions
|
|
Level 5: Orchestration → Manage fleets of agents ← You are here
|
|
```
|
|
|
|
**Key realization:** Single agents hit context window limits. You need orchestration to scale beyond one agent.
|
|
|
|
## The Three Pillars
|
|
|
|
Multi-agent orchestration requires three components working together:
|
|
|
|
```text
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 1. ORCHESTRATOR AGENT │
|
|
│ (Single interface to your fleet) │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 2. CRUD FOR AGENTS │
|
|
│ (Create, Read, Update, Delete agents at scale) │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 3. OBSERVABILITY │
|
|
│ (Monitor performance, costs, and results) │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
Without all three, orchestration fails. You need:
|
|
|
|
- **Orchestrator** to command agents
|
|
- **CRUD** to manage agent lifecycle
|
|
- **Observability** to understand what agents are doing
|
|
|
|
## Core Principle: The Orchestrator Sleeps
|
|
|
|
> "Our orchestrator has stopped doing work. Its orchestration tasks are completed. It has created and commanded our agents. Now, our agents are doing the work."
|
|
|
|
**The pattern:**
|
|
|
|
```text
|
|
1. User prompts Orchestrator
|
|
2. Orchestrator creates specialized agents
|
|
3. Orchestrator commands agents with detailed prompts
|
|
4. Orchestrator SLEEPS (stops consuming context)
|
|
5. Agents work autonomously
|
|
6. Orchestrator wakes periodically to check status
|
|
7. Orchestrator reports results to user
|
|
8. Agents are deleted
|
|
```
|
|
|
|
**Why orchestrator sleeps:**
|
|
|
|
- Protects its context window
|
|
- Avoids observing all agent work (too much information)
|
|
- Only wakes when needed to check status or command agents
|
|
|
|
**Example orchestrator sleep pattern:**
|
|
|
|
```python
|
|
# Orchestrator commands agents
|
|
orchestrator.create_agent("scout", task="Find relevant files")
|
|
orchestrator.create_agent("builder", task="Implement changes")
|
|
|
|
# Orchestrator sleeps, checking status every 15s
|
|
while not all_agents_complete():
|
|
orchestrator.sleep(15) # Not consuming context
|
|
status = orchestrator.check_agent_status()
|
|
orchestrator.log(status)
|
|
|
|
# Wake up to collect results
|
|
results = orchestrator.get_agent_results()
|
|
orchestrator.summarize_to_user(results)
|
|
```
|
|
|
|
## Orchestration Patterns
|
|
|
|
### Pattern 1: Scout-Plan-Build (Sequential Chaining)
|
|
|
|
**Use case:** Complex tasks requiring multiple specialized steps
|
|
|
|
**Flow:**
|
|
|
|
```text
|
|
User: "Migrate codebase to new SDK"
|
|
↓
|
|
Orchestrator creates Scout agents (4 parallel)
|
|
├→ Scout 1: Search with Gemini
|
|
├→ Scout 2: Search with CodeX
|
|
├→ Scout 3: Search with Haiku
|
|
└→ Scout 4: Search with Flash
|
|
↓
|
|
Scouts output: relevant-files.md with exact locations
|
|
↓
|
|
Orchestrator creates Planner agent
|
|
├→ Reads relevant-files.md
|
|
├→ Scrapes documentation
|
|
└→ Outputs: detailed-plan.md
|
|
↓
|
|
Orchestrator creates Builder agent
|
|
├→ Reads detailed-plan.md
|
|
├→ Executes implementation
|
|
└→ Tests and validates
|
|
```
|
|
|
|
**Why this works:**
|
|
|
|
- **Scout step offloads searching from Planner** (R&D framework: Reduce + Delegate)
|
|
- **Multiple scout models** provide diverse perspectives
|
|
- **Planner only sees relevant files**, not entire codebase
|
|
- **Builder focused on execution**, not planning
|
|
|
|
**Implementation:**
|
|
|
|
```bash
|
|
# Composable slash commands
|
|
/scout-plan-build "Migrate to new Claude Agent SDK"
|
|
|
|
# Internally runs:
|
|
/scout "Find files needing SDK migration"
|
|
/plan-with-docs docs=https://agent-sdk-docs.com
|
|
/build plan=agents/plans/sdk-migration.md
|
|
```
|
|
|
|
**Context savings:**
|
|
|
|
```text
|
|
Without scouts:
|
|
├── Planner searches entire codebase: 50k tokens
|
|
├── Planner reads irrelevant files: 30k tokens
|
|
└── Total wasted: 80k tokens
|
|
|
|
With scouts:
|
|
├── 4 scouts search in parallel (isolated contexts)
|
|
├── Planner reads only relevant-files.md: 5k tokens
|
|
└── Savings: 75k tokens (94% reduction)
|
|
```
|
|
|
|
### Pattern 2: Plan-Build-Review-Ship (Task Board)
|
|
|
|
**Use case:** Structured development lifecycle with quality gates
|
|
|
|
**Flow:**
|
|
|
|
```text
|
|
User: "Update HTML titles across application"
|
|
↓
|
|
Task created → PLAN column
|
|
↓
|
|
Orchestrator creates Planner agent
|
|
├→ Analyzes requirements
|
|
├→ Creates implementation plan
|
|
└→ Moves task to BUILD
|
|
↓
|
|
Orchestrator creates Builder agent
|
|
├→ Reads plan
|
|
├→ Implements changes
|
|
├→ Runs tests
|
|
└→ Moves task to REVIEW
|
|
↓
|
|
Orchestrator creates Reviewer agent
|
|
├→ Checks implementation against plan
|
|
├→ Validates tests pass
|
|
└→ Moves task to SHIP
|
|
↓
|
|
Orchestrator creates Shipper agent
|
|
├→ Creates git commit
|
|
├→ Pushes to remote
|
|
└→ Task complete
|
|
```
|
|
|
|
**Why this works:**
|
|
|
|
- **Clear phases** with distinct responsibilities
|
|
- **Each agent focused** on single phase
|
|
- **Quality gates** between phases
|
|
- **Failure isolation** - if builder fails, planner work preserved
|
|
|
|
**Visual representation:**
|
|
|
|
```text
|
|
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
│ PLAN │→ │ BUILD │→ │ REVIEW │→ │ SHIP │
|
|
├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤
|
|
│ Task A │ │ │ │ │ │ │
|
|
│ │ │ │ │ │ │ │
|
|
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
|
```
|
|
|
|
**Agent handoff:**
|
|
|
|
```python
|
|
# Orchestrator manages task board state
|
|
task = {
|
|
"id": "update-titles",
|
|
"status": "planning",
|
|
"assigned_agent": "planner-001",
|
|
"artifacts": []
|
|
}
|
|
|
|
# Planner completes
|
|
task["status"] = "building"
|
|
task["artifacts"].append("plan.md")
|
|
task["assigned_agent"] = "builder-001"
|
|
|
|
# Orchestrator hands off to builder
|
|
orchestrator.command_agent(
|
|
"builder-001",
|
|
f"Implement plan from {task['artifacts'][0]}"
|
|
)
|
|
```
|
|
|
|
### Pattern 3: Scout-Builder (Two-Stage)
|
|
|
|
**Use case:** UI changes, targeted modifications
|
|
|
|
**Flow:**
|
|
|
|
```text
|
|
User: "Create gray pills for app header information"
|
|
↓
|
|
Orchestrator creates Scout
|
|
├→ Locates exact files and line numbers
|
|
├→ Identifies patterns and conventions
|
|
└→ Outputs: scout-report.md
|
|
↓
|
|
Orchestrator creates Builder
|
|
├→ Reads scout-report.md
|
|
├→ Implements precise changes
|
|
└→ Outputs: modified files
|
|
↓
|
|
Orchestrator wakes, verifies, reports
|
|
```
|
|
|
|
**Orchestrator sleep pattern:**
|
|
|
|
```python
|
|
# Orchestrator creates scout
|
|
orchestrator.create_agent("scout-header", task="Find header UI components")
|
|
|
|
# Orchestrator sleeps, checking every 15s
|
|
orchestrator.sleep_with_status_checks(interval=15)
|
|
|
|
# Scout completes, orchestrator wakes
|
|
scout_output = orchestrator.get_agent_output("scout-header")
|
|
|
|
# Orchestrator creates builder with scout's output
|
|
orchestrator.create_agent(
|
|
"builder-ui",
|
|
task=f"Create gray pills based on scout findings: {scout_output}"
|
|
)
|
|
|
|
# Orchestrator sleeps again
|
|
orchestrator.sleep_with_status_checks(interval=15)
|
|
```
|
|
|
|
## Context Window Protection
|
|
|
|
> "200k context window is plenty. You're just stuffing a single agent with too much work. Don't force your agent to context switch."
|
|
|
|
**The problem:** Single agent doing everything explodes context window
|
|
|
|
```text
|
|
Single Agent Approach:
|
|
├── Search codebase: 40k tokens
|
|
├── Read files: 60k tokens
|
|
├── Plan changes: 20k tokens
|
|
├── Implement: 30k tokens
|
|
├── Test: 15k tokens
|
|
└── Total: 165k tokens (83% used!)
|
|
```
|
|
|
|
**The solution:** Specialized agents with focused context
|
|
|
|
```text
|
|
Orchestrator Approach:
|
|
├── Orchestrator: 10k tokens (coordinates)
|
|
├── Scout 1: 15k tokens (searches)
|
|
├── Scout 2: 15k tokens (searches)
|
|
├── Planner: 25k tokens (plans using scout output)
|
|
├── Builder: 35k tokens (implements)
|
|
└── Total per agent: <35k tokens (max 18% per agent)
|
|
```
|
|
|
|
**Key principle:** Agents are deletable temporary resources
|
|
|
|
```text
|
|
1. Create agent for specific task
|
|
2. Agent completes task
|
|
3. DELETE agent (free memory)
|
|
4. Create new agent for next task
|
|
5. Repeat
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```bash
|
|
# User: "Build documentation for frontend and backend"
|
|
|
|
# Orchestrator creates 3 agents
|
|
/create-agent frontend-docs "Document frontend components"
|
|
/create-agent backend-docs "Document backend APIs"
|
|
/create-agent qa-docs "Combine and QA both docs"
|
|
|
|
# Work completes...
|
|
|
|
# Delete all agents when done
|
|
/delete-all-agents
|
|
|
|
# Result: All agents gone, context freed
|
|
```
|
|
|
|
**Why delete agents:**
|
|
|
|
- Frees context windows for new work
|
|
- Prevents context accumulation
|
|
- Enforces single-purpose design
|
|
- Matches engineering principle: "The best code is no code at all"
|
|
|
|
## CRUD for Agents
|
|
|
|
Orchestrator needs full agent lifecycle control:
|
|
|
|
**Create:**
|
|
|
|
```python
|
|
agent_id = orchestrator.create_agent(
|
|
name="scout-api",
|
|
task="Find all API endpoints",
|
|
model="haiku", # Fast, cheap for search
|
|
max_tokens=100000
|
|
)
|
|
```
|
|
|
|
**Read:**
|
|
|
|
```python
|
|
# Check agent status
|
|
status = orchestrator.get_agent_status(agent_id)
|
|
# => {"status": "working", "progress": "60%", "context_used": "15k tokens"}
|
|
|
|
# Read agent output
|
|
output = orchestrator.get_agent_output(agent_id)
|
|
# => {"files_consumed": [...], "files_produced": [...]}
|
|
```
|
|
|
|
**Update:**
|
|
|
|
```python
|
|
# Command existing agent with new task
|
|
orchestrator.command_agent(
|
|
agent_id,
|
|
"Now implement the changes based on your findings"
|
|
)
|
|
```
|
|
|
|
**Delete:**
|
|
|
|
```python
|
|
# Single agent
|
|
orchestrator.delete_agent(agent_id)
|
|
|
|
# All agents
|
|
orchestrator.delete_all_agents()
|
|
```
|
|
|
|
## Observability Requirements
|
|
|
|
Without observability, orchestration is blind. You need:
|
|
|
|
### 1. Agent-Level Visibility
|
|
|
|
```text
|
|
For each agent, track:
|
|
├── Name and ID
|
|
├── Status (creating, working, complete, failed)
|
|
├── Context window usage
|
|
├── Model and cost
|
|
├── Files consumed
|
|
├── Files produced
|
|
└── Tool calls executed
|
|
```
|
|
|
|
### 2. Cross-Agent Visibility
|
|
|
|
```text
|
|
Fleet overview:
|
|
├── Total agents active
|
|
├── Total context consumed
|
|
├── Total cost
|
|
├── Agent dependencies (who's waiting on whom)
|
|
└── Bottlenecks (slow agents blocking others)
|
|
```
|
|
|
|
### 3. Real-Time Streaming
|
|
|
|
```text
|
|
User sees:
|
|
├── Agent creation events
|
|
├── Tool calls as they happen
|
|
├── Progress updates
|
|
├── Completion notifications
|
|
└── Error alerts
|
|
```
|
|
|
|
**Implementation:** See [Hooks for Observability](hooks-observability.md) for complete architecture
|
|
|
|
## Information Flow in Orchestrated Systems
|
|
|
|
```text
|
|
User
|
|
↓ (prompts)
|
|
Orchestrator
|
|
↓ (creates & commands)
|
|
Agent 1 → Agent 2 → Agent 3
|
|
↓ ↓ ↓
|
|
(results flow back up)
|
|
↓
|
|
Orchestrator (summarizes)
|
|
↓
|
|
User
|
|
```
|
|
|
|
**Critical understanding:** Agents never talk directly to user. They report to orchestrator.
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
# User prompts orchestrator
|
|
user: "Summarize codebase"
|
|
|
|
# Orchestrator creates agent with detailed instructions
|
|
orchestrator → agent: """
|
|
Read all files in src/
|
|
Create markdown summary with:
|
|
- Architecture overview
|
|
- Key components
|
|
- File structure
|
|
- Tech stack
|
|
|
|
Report results back to orchestrator (not user!)
|
|
"""
|
|
|
|
# Agent completes, reports to orchestrator
|
|
agent → orchestrator: "Summary complete at docs/summary.md"
|
|
|
|
# Orchestrator reports to user
|
|
orchestrator → user: "Codebase summary created with 3 main sections: architecture, components, and tech stack"
|
|
```
|
|
|
|
## When to Use Orchestration
|
|
|
|
### Use orchestration when
|
|
|
|
✅ **Task requires 3+ specialized agents**
|
|
|
|
- Example: Scout + Plan + Build
|
|
|
|
✅ **Context window exploding in single agent**
|
|
|
|
- Single agent using >150k tokens
|
|
|
|
✅ **Need parallel execution**
|
|
|
|
- Multiple independent subtasks
|
|
|
|
✅ **Quality gates required**
|
|
|
|
- Plan → Build → Review → Ship
|
|
|
|
✅ **Long-running autonomous work**
|
|
|
|
- Agents work while you're AFK
|
|
|
|
### Don't use orchestration when
|
|
|
|
❌ **Simple one-off task**
|
|
|
|
- Single agent sufficient
|
|
|
|
❌ **Learning/prototyping**
|
|
|
|
- Orchestration adds complexity
|
|
|
|
❌ **No observability infrastructure**
|
|
|
|
- You'll be blind to agent behavior
|
|
|
|
❌ **Haven't mastered custom agents**
|
|
|
|
- Level 5 requires Level 4 foundation
|
|
|
|
## Practical Implementation
|
|
|
|
### Minimal Orchestrator Agent
|
|
|
|
```python
|
|
# orchestrator-agent.md (sub-agent definition)
|
|
|
|
---
|
|
name: orchestrator
|
|
description: Manages fleet of agents for complex multi-step tasks
|
|
---
|
|
|
|
# Orchestrator Agent
|
|
|
|
You are an orchestrator agent managing a fleet of specialized agents.
|
|
|
|
## Your Tools
|
|
|
|
- create_agent(name, task, model): Create new agent
|
|
- command_agent(agent_id, task): Send task to existing agent
|
|
- get_agent_status(agent_id): Check agent progress
|
|
- get_agent_output(agent_id): Retrieve agent results
|
|
- delete_agent(agent_id): Remove completed agent
|
|
- delete_all_agents(): Clean up all agents
|
|
|
|
## Your Responsibilities
|
|
|
|
1. **Break down user requests** into specialized subtasks
|
|
2. **Create focused agents** for each subtask
|
|
3. **Command agents** with detailed instructions
|
|
4. **Monitor progress** without micromanaging
|
|
5. **Collect results** and synthesize for user
|
|
6. **Delete agents** when work is complete
|
|
|
|
## Orchestrator Sleep Pattern
|
|
|
|
After creating and commanding agents:
|
|
1. **SLEEP** - Stop consuming context
|
|
2. **Wake every 15-30s** to check agent status
|
|
3. **SLEEP again** if agents still working
|
|
4. **Wake when all complete** to collect results
|
|
|
|
DO NOT observe all agent work. This explodes your context window.
|
|
|
|
## Example Workflow
|
|
|
|
```
|
|
|
|
User: "Migrate codebase to new SDK"
|
|
|
|
You:
|
|
|
|
1. Create scout agents (parallel search)
|
|
2. Command scouts to find SDK usage
|
|
3. SLEEP (check status every 15s)
|
|
4. Wake when scouts complete
|
|
5. Create planner agent
|
|
6. Command planner with scout results
|
|
7. SLEEP (check status every 15s)
|
|
8. Wake when planner completes
|
|
9. Create builder agent
|
|
10. Command builder with plan
|
|
11. SLEEP (check status every 15s)
|
|
12. Wake when builder completes
|
|
13. Summarize results for user
|
|
14. Delete all agents
|
|
|
|
```bash
|
|
|
|
## Key Principles
|
|
|
|
- **One agent, one task** - Don't overload agents
|
|
- **Sleep between phases** - Protect your context
|
|
- **Delete when done** - Treat agents as temporary
|
|
- **Detailed commands** - Don't assume agents know context
|
|
- **Results-oriented** - Every agent must produce concrete output
|
|
```
|
|
|
|
### Orchestrator Tools (SDK)
|
|
|
|
```python
|
|
# create_agent tool
|
|
@mcptool(
|
|
name="create_agent",
|
|
description="Create a new specialized agent"
|
|
)
|
|
def create_agent(params: dict) -> dict:
|
|
name = params["name"]
|
|
task = params["task"]
|
|
model = params.get("model", "sonnet")
|
|
|
|
agent_id = agent_manager.create(
|
|
name=name,
|
|
system_prompt=task,
|
|
model=model
|
|
)
|
|
|
|
return {
|
|
"agent_id": agent_id,
|
|
"status": "created",
|
|
"message": f"Agent {name} created"
|
|
}
|
|
|
|
# command_agent tool
|
|
@mcptool(
|
|
name="command_agent",
|
|
description="Send task to existing agent"
|
|
)
|
|
def command_agent(params: dict) -> dict:
|
|
agent_id = params["agent_id"]
|
|
task = params["task"]
|
|
|
|
result = agent_manager.prompt(agent_id, task)
|
|
|
|
return {
|
|
"agent_id": agent_id,
|
|
"status": "commanded",
|
|
"message": f"Agent received task"
|
|
}
|
|
```
|
|
|
|
## Trade-offs
|
|
|
|
### Benefits
|
|
|
|
- ✅ Scales beyond single agent limits
|
|
- ✅ Parallel execution (3x-10x speedup)
|
|
- ✅ Context window protection
|
|
- ✅ Specialized agent focus
|
|
- ✅ Quality gates between phases
|
|
- ✅ Autonomous out-of-loop work
|
|
|
|
### Costs
|
|
|
|
- ❌ Upfront investment to build
|
|
- ❌ Infrastructure complexity (database, WebSocket)
|
|
- ❌ More moving parts to manage
|
|
- ❌ Requires observability
|
|
- ❌ Orchestrator agent needs careful prompting
|
|
- ❌ Not worth it for simple tasks
|
|
|
|
## Key Quotes
|
|
|
|
> "The orchestrator agent is the first pattern where I felt the perfect combination of observability, customizability, and agents at scale."
|
|
>
|
|
> "Treat your agents as deletable temporary resources that serve a single purpose."
|
|
>
|
|
> "Our orchestrator has stopped doing work. Its orchestration tasks are completed. Now, our agents are doing the work."
|
|
>
|
|
> "200k context window is plenty. You're just stuffing a single agent with too much work."
|
|
|
|
## Source Attribution
|
|
|
|
**Primary source:** One Agent to Rule Them All (orchestrator architecture, three pillars, sleep pattern, CRUD)
|
|
|
|
**Supporting sources:**
|
|
|
|
- Claude 2.0 (scout-plan-build workflow, composable prompts)
|
|
- Custom Agents (plan-build-review-ship task board)
|
|
- Sub-Agents (information flow, delegation patterns)
|
|
|
|
## Related Documentation
|
|
|
|
- [Hooks for Observability](hooks-observability.md) - Required for orchestration
|
|
- [Context Window Protection](context-window-protection.md) - Why orchestration matters
|
|
- [Multi-Agent Case Studies](../examples/multi-agent-case-studies.md) - Real orchestration systems
|
|
|
|
---
|
|
|
|
**Remember:** Orchestration is Level 5. Master Levels 1-4 first. Then build your fleet.
|