A single agent can accomplish a lot, but complex real-world tasks often exceed what any one specialist can handle. Just as organizations divide work among departments, multi-agent systems distribute responsibilities across specialized agents that collaborate toward shared goals. In this post, I’ll explore how to design architectures where multiple AI agents work together effectively.
Why Multiple Agents?
Consider a restaurant. One person doesn’t do everything - hosts greet customers, waiters take orders, chefs cook, and managers oversee operations. Each role has clear responsibilities and communicates with others to deliver a complete experience.
Multi-agent systems work the same way:
Specialization: Each agent focuses on what it does best
Scalability: Add more agents as complexity grows
Modularity: Change one agent without rewriting the whole system
Parallel processing: Multiple agents can work simultaneously
flowchart TD
U[Customer Request] --> O[Orchestrator]
O --> A1[Policy Agent]
O --> A2[Inventory Agent]
O --> A3[Refund Agent]
A1 --> O
A2 --> O
A3 --> O
O --> R[Response]
style O fill:#fff3e0
style A1 fill:#e3f2fd
style A2 fill:#e8f5e9
style A3 fill:#fce4ec
Two Primary Architecture Patterns
The Orchestrator Pattern (Hub-and-Spoke)
A central coordinator directs specialized workers, similar to a project manager delegating tasks:
flowchart TD
T[Task] --> O[Orchestrator]
O --> W1[Worker 1]
O --> W2[Worker 2]
O --> W3[Worker 3]
W1 --> O
W2 --> O
W3 --> O
O --> R[Result]
style O fill:#fff3e0
Characteristics:
All communication flows through the central orchestrator
Orchestrator decides task breakdown and delegation
Workers report back to orchestrator
Clear, predictable workflow
Best for:
Order fulfillment systems
Support ticket routing
Complex report generation
Structured multi-step workflows
Advantages:
Easy to debug (clear flow)
Enforces correct execution order
Manages state of entire process
Clear mapping of business functions
The Peer-to-Peer Pattern
Agents communicate directly with each other without central coordination:
Before writing code, sketch your design. Even simple boxes and arrows force you to answer critical questions:
Who talks to whom?
What information does each agent need?
How does the overall job get done?
Defining Agent Roles
Each agent needs a clear, bounded responsibility:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Bad: Vague role research_agent = "You help with research tasks"
# Good: Specific role with boundaries research_agent = """ You are a Research Specialist. Your responsibilities: - Search for factual information on requested topics - Summarize findings with source citations - Flag uncertainty when information is incomplete You do NOT: - Make recommendations or decisions - Access external APIs or databases - Perform calculations or analysis """
Communication Protocols
Define how agents exchange information:
1 2 3 4 5 6 7 8 9 10 11 12
from dataclasses import dataclass from typing importOptional, Dict, Any
@dataclass classAgentMessage: """Standard message format between agents""" sender: str receiver: str task: str payload: Dict[str, Any] priority: int = 1 requires_response: bool = True
self.fulfillment_agent = BaseAgent( name="FulfillmentProcessor", system_prompt="""You process order fulfillment. Return confirmation with delivery estimate.""" )
defhandle_order(self, order: dict) -> str: # Step 1: Check policy compliance policy_result = self.policy_agent.run( f"Check if this order is allowed: {order}", context={"order_type": order.get("type")} )
@tool defcheck_inventory(product_id: str) -> dict: """ Check current inventory stock level for a product. Args: product_id: The unique product identifier or SKU Returns: Stock level and availability status """ try: # Query inventory system stock = inventory_db.get_stock(product_id) return { "product_id": product_id, "quantity": stock, "available": stock > 0 } except Exception as e: return {"error": f"Failed to check inventory: {str(e)}"}
@tool defprocess_refund(order_id: str, amount: float, reason: str) -> dict: """ Process a refund for an order. Args: order_id: The order to refund amount: Refund amount in dollars reason: Reason for the refund Returns: Refund confirmation with transaction ID """ try: result = payment_system.refund(order_id, amount, reason) return { "success": True, "transaction_id": result.id, "amount_refunded": amount } except Exception as e: return {"success": False, "error": str(e)}
Tool Design Principles:
Clear names: check_inventory not ci
Detailed docstrings: LLMs rely on descriptions to choose tools
Type annotations: Required for proper schema generation
Plan for failure: Every agent call can fail - design graceful degradation
Start with diagrams: Sketch architecture before coding to catch design issues early
Multi-agent architecture transforms complex problems into manageable, specialized tasks. In the next post, I’ll explore how to route requests, manage data flow, and coordinate state across multiple agents.
This is Part 12 of my series on building intelligent AI systems. Next: multi-agent routing, data flow, and state coordination.
Comments