Multi-Agent Patterns
Coordinate multiple agents for complex workflows
Overview
Aegeantic provides built-in patterns for coordinating multiple agents. These patterns handle common multi-agent workflows while leveraging the existing Agent/AgentRunner infrastructure.
Agent Chain
Sequential execution where each agent's output becomes the next agent's input:
from agentic import AgentChain, AgentChainConfig
# Create specialized agents
researcher = Agent(research_config, context, patterns, tools, llm)
analyzer = Agent(analysis_config, context, patterns, tools, llm)
summarizer = Agent(summary_config, context, patterns, tools, llm)
# Build chain
chain = AgentChain(
agents=[
("researcher", researcher),
("analyzer", analyzer),
("summarizer", summarizer)
],
config=AgentChainConfig(
pass_mode="response", # Pass response text to next
prepend_context=True # Include context about previous agent
)
)
# Execute chain
async for event in chain.execute("Research quantum computing"):
if event.type == "step_complete":
print(f"Agent completed: {event.result.segments.response}")
Chain Configuration
pass_mode: "response" | "full_context" | "tool_results" | "custom"prepend_context: Include context about previous agentcontext_template: Template for context formattingtransform_fn: Custom function to transform output between agents
Supervisor-Worker Pattern
One supervisor delegates tasks to specialized workers:
from agentic import SupervisorPattern, SupervisorConfig
# Create supervisor and workers
supervisor = Agent(supervisor_config, context, patterns, tools, llm)
workers = {
"search_agent": Agent(search_config, context, patterns, tools, llm),
"data_agent": Agent(data_config, context, patterns, tools, llm),
"code_agent": Agent(code_config, context, patterns, tools, llm)
}
pattern = SupervisorPattern(
supervisor=supervisor,
workers=workers,
config=SupervisorConfig(
delegation_pattern_name="delegate", # Pattern for delegation
worker_key="to", # Key to extract worker name
task_key="task", # Key to extract task
max_delegation_rounds=10 # Prevent infinite loops
)
)
# Execute
async for event in pattern.execute("Build a web scraper"):
if event.type == "status":
print(event.message)
Delegation Format
Supervisor uses the delegation pattern in its output:
<delegate>
{
"to": "search_agent",
"task": "Search for Python web scraping libraries"
}
</delegate>
Parallel Pattern
Multiple agents analyze the same input in parallel, results merged:
from agentic import ParallelPattern, ParallelConfig
# Create agents with different perspectives
agents = {
"technical": Agent(tech_config, context, patterns, tools, llm),
"business": Agent(biz_config, context, patterns, tools, llm),
"security": Agent(sec_config, context, patterns, tools, llm)
}
# Optional merger agent
merger = Agent(merger_config, context, patterns, tools, llm)
parallel = ParallelPattern(
agents=agents,
merger=merger,
config=ParallelConfig(
merge_strategy="agent", # Use merger agent
timeout_seconds=60.0
)
)
async for event in parallel.execute_and_merge("Analyze this API design"):
if event.type == "step_complete":
print(event.result.segments.response)
Merge Strategies
"agent"- Use merger agent to synthesize results"concat"- Concatenate all results"voting"- Simple voting on common elements
Debate Pattern
Agents debate a topic until consensus:
from agentic import DebatePattern, DebateConfig
# Create debating agents
agents = {
"advocate": Agent(advocate_config, context, patterns, tools, llm),
"critic": Agent(critic_config, context, patterns, tools, llm),
"mediator": Agent(mediator_config, context, patterns, tools, llm)
}
# Optional moderator for final summary
moderator = Agent(mod_config, context, patterns, tools, llm)
debate = DebatePattern(
agents=agents,
moderator=moderator,
config=DebateConfig(
max_rounds=5,
consensus_detector=lambda responses: check_consensus(responses)
)
)
async for event in debate.converge("Should we use microservices?"):
if event.type == "status":
print(event.message)
Shared Context
All agents in a pattern can share the same context manager:
# Shared context for all agents
shared_context = ContextManager(storage, iteration_mgr)
# Create agents with shared context
agent1 = Agent(config1, shared_context, patterns1, tools1, llm)
agent2 = Agent(config2, shared_context, patterns2, tools2, llm)
# Agents can read each other's outputs
# via context keys
Custom Multi-Agent Patterns
Build your own coordination patterns:
class CustomPattern:
def __init__(self, agents):
self._runners = {
name: AgentRunner(agent)
for name, agent in agents.items()
}
async def execute(self, input_text):
# Custom coordination logic
for name, runner in self._runners.items():
async for event in runner.step_stream(input_text):
yield event
# Custom decision logic
if event.type == "step_complete":
if event.result.status == AgentStatus.DONE:
return # Stop on first completion
Best Practices
- Use shared context for agent communication
- Set appropriate timeouts to prevent hanging
- Handle errors gracefully in coordination logic
- Monitor iteration counts to prevent infinite loops
- Use clear agent IDs for debugging
- Test patterns with smaller agent counts first
- Consider costs when running many agents in parallel
Performance: Parallel patterns execute agents concurrently but still require LLM API calls for each agent. Monitor costs and latency carefully.
Next Steps
- Agent System - Configure specialized agents
- Logic Flows - Add conditional logic to multi-agent systems
- Events - Monitor multi-agent execution