Design and implement multi-agent LLM architectures using the orchestrator-subagent pattern. Use when: (1) Deciding whether to use multi-agent vs single-agent systems, (2) Implementing context isolation for high-volume operations, (3) Parallelizing independent research tasks, (4) Creating specialized agents with focused tool sets, (5) Building verification subagents for quality assurance, or (6) Analyzing context-centric decomposition boundaries.
Multi-agent systems introduce overhead. Every additional agent represents another potential point of failure, another set of prompts to maintain, and another source of unexpected behavior.
Multi-agent systems use 3-10x more tokens than single-agent approaches due to:
A well-designed single agent with appropriate tools can accomplish far more than expected. Use single agent when:
Use when subtasks generate large context but only summary is needed for main task.
Example: Customer Support
class OrderLookupAgent:
def lookup_order(self, order_id: str) -> dict:
messages = [{"role": "user", "content": f"Get essential details for order {order_id}"}]
response = client.messages.create(
model="claude-sonnet-4-5", max_tokens=1024,
messages=messages, tools=[get_order_details_tool]
)
return extract_summary(response) # Returns 50-100 tokens, not 2000+
class SupportAgent:
def handle_issue(self, user_message: str):
if needs_order_info(user_message):
order_id = extract_order_id(user_message)
order_summary = OrderLookupAgent().lookup_order(order_id)
context = f"Order {order_id}: {order_summary['status']}, purchased {order_summary['date']}"
# Main agent gets clean context
Best when:
Use when exploring larger search space or independent research facets.
import asyncio
from anthropic import AsyncAnthropic
client = AsyncAnthropic()
async def research_topic(query: str) -> dict:
facets = await lead_agent.decompose_query(query)
tasks = [research_subagent(facet) for facet in facets]
results = await asyncio.gather(*tasks)
return await lead_agent.synthesize(results)
async def research_subagent(facet: str) -> dict:
messages = [{"role": "user", "content": f"Research: {facet}"}]
response = await client.messages.create(
model="claude-sonnet-4-5", max_tokens=4096,
messages=messages, tools=[web_search, read_document]
)
return extract_findings(response)
Benefit: Thoroughness, not speed. Covers more ground at higher token cost.
Split by domain when agent has 20+ tools, shows domain confusion, or degraded performance.
Signs you need specialization:
Different tasks require conflicting behavioral modes:
Deep domain context that would overwhelm a generalist:
class CRMAgent:
system_prompt = """You are a CRM specialist. You manage contacts,
opportunities, and account records. Always verify record ownership
before updates and maintain data integrity across related records."""
tools = [crm_get_contacts, crm_create_opportunity] # 8-10 CRM tools
class MarketingAgent:
system_prompt = """You are a marketing automation specialist. You
manage campaigns, lead scoring, and email sequences."""
tools = [marketing_get_campaigns, marketing_create_lead] # 8-10 tools
class OrchestratorAgent:
def execute(self, user_request: str):
response = client.messages.create(
model="claude-sonnet-4-5", max_tokens=1024,
system="""Route to appropriate specialist:
- CRM: Contacts, opportunities, accounts, sales pipeline
- Marketing: Campaigns, lead nurturing, email sequences""",
messages=[{"role": "user", "content": user_request}],
tools=[delegate_to_crm, delegate_to_marketing]
)
return response
Problem-centric (counterproductive): Split by work type (writer, tester, reviewer) - creates coordination overhead, context loss at handoffs.
Context-centric (effective): Agent handling a feature also handles its tests - already has necessary context.
Dedicated agent for testing/validating main agent's work. Succeeds because verification requires minimal context transfer.
class CodingAgent:
def implement_feature(self, requirements: str) -> dict:
response = client.messages.create(
model="claude-sonnet-4-5", max_tokens=4096,
messages=[{"role": "user", "content": f"Implement: {requirements}"}],
tools=[read_file, write_file, list_directory]
)
return {"code": response.content, "files_changed": extract_files(response)}
class VerificationAgent:
def verify_implementation(self, requirements: str, files_changed: list) -> dict:
messages = [{"role": "user", "content": f"""
Requirements: {requirements}
Files changed: {files_changed}
Run the complete test suite and verify:
1. All existing tests pass
2. New functionality works as specified
3. No obvious errors or security issues
You MUST run: pytest --verbose
Only mark as PASSED if ALL tests pass with no failures.
"""}]
response = client.messages.create(
model="claude-sonnet-4-5", max_tokens=4096,
messages=messages, tools=[run_tests, execute_code, read_file]
)
return {"passed": extract_pass_fail(response), "issues": extract_issues(response)}
Verifier marks passing without thorough testing. Prevention:
Before adding multi-agent complexity:
Start with simplest approach that works. Add complexity only when evidence supports it.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer