Build an orchestrator that coordinates specialized sub-agents. This mirrors Tenzai's Moses/Bonzai architecture.
Tenzai's architecture uses a Master Agent (Moses) that orchestrates specialized Sub-Agents (Bonzai for exploitation, Morty for context, Rico for code analysis). Understanding this pattern is crucial.
Build a simplified multi-agent system where a coordinator delegates to specialists. Experience the challenges of message passing, context sharing, and result aggregation.
βββββββββββββββββββ
β ORCHESTRATOR β
β (Moses) β
ββββββββββ¬βββββββββ
β
ββββββββββββββββββΌβββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ
β BONZAI β β MORTY β β RICO β
β (Exploiter) β β (Context) β β (Code Expert) β
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ
Build a multi-agent system for content creation with these specialists:
Gathers information from the web, finds relevant sources, extracts key facts. Has access to web_search and read_url tools.
Takes research and produces polished content. Focuses on structure, clarity, and engagement. No external toolsβjust writing.
Reviews and improves content. Checks for accuracy, tone, and completeness. Can request revisions from the Writer.
Receives user requests, breaks them into tasks, delegates to specialists, aggregates results, and returns final output.
async def run_pipeline(user_request: str):
# 1. Coordinator plans the work
plan = await coordinator.run(f"Plan research for: {user_request}")
# 2. Researcher gathers info
research = await researcher.run(plan.research_queries)
# 3. Writer creates draft
draft = await writer.run(f"Write based on: {research}")
# 4. Editor reviews
final = await editor.run(f"Review and improve: {draft}")
return final
class AgentMessage(BaseModel):
from_agent: str
to_agent: str
content: str
message_type: str # "request", "response", "revision"
class Coordinator:
def __init__(self):
self.agents = {
"researcher": ResearcherAgent(),
"writer": WriterAgent(),
"editor": EditorAgent(),
}
self.message_history: list[AgentMessage] = []
async def run(self, user_request: str):
# Coordinator decides which agent to call
while not self.is_complete():
next_action = await self.decide_next_action()
result = await self.agents[next_action.agent].run(
next_action.input,
context=self.message_history
)
self.message_history.append(result)
from langgraph.graph import StateGraph
class MultiAgentState(BaseModel):
messages: list[BaseMessage]
research: str | None = None
draft: str | None = None
final: str | None = None
revision_count: int = 0
def create_multi_agent_graph():
workflow = StateGraph(MultiAgentState)
workflow.add_node("coordinator", coordinator_node)
workflow.add_node("researcher", researcher_node)
workflow.add_node("writer", writer_node)
workflow.add_node("editor", editor_node)
# Coordinator routes to specialists
workflow.add_conditional_edges(
"coordinator",
route_to_specialist,
{
"research": "researcher",
"write": "writer",
"edit": "editor",
"done": END
}
)
# Specialists return to coordinator
for agent in ["researcher", "writer", "editor"]:
workflow.add_edge(agent, "coordinator")
return workflow.compile()
How Anthropic built their deep research agent
Tutorial on building collaborative agents
Open source multi-agent research system
LangGraph supervisor/worker pattern