Multi-Agent Systems¶
Building complex multi-agent systems with handoffs, routing, and collaboration using Flux.
Overview¶
Flux lets you compose multiple specialized agents into a system where a router agent delegates tasks to the right specialist. This guide covers the core multi-agent patterns:
- Router pattern -- a coordinator agent that hands off to specialists
- Specialist agents -- agents with focused instructions and tools
- Conditional handoffs -- routing decisions based on context
- Agent communication -- how agents pass information via handoffs
flowchart TD
U[User] --> R[Router Agent]
R -->|research task| RE[Researcher Agent]
R -->|coding task| CO[Coder Agent]
R -->|math task| MA[Math Agent]
RE -->|result| R
CO -->|result| R
MA -->|result| R
R -->|final answer| U
Prerequisites¶
- Python 3.10+
- Flux installed (
pip install flux-agents) - An Ollama instance running locally (or swap in
OpenAIModel/AnthropicModel)
1 -- Define Specialist Agents¶
Each specialist has a focused system prompt, optional tools, and a clear scope of responsibility.
from flux import Agent, tool
from flux.models.ollama import OllamaModel
@tool
def search_web(query: str) -> str:
"""Search the web for information on a topic.
Args:
query: The search query.
"""
return f"Search results for '{query}': Found relevant articles and data."
@tool
def write_code(description: str) -> str:
"""Write code based on a description.
Args:
description: What the code should do.
"""
return f"# Generated code\n# {description}\nprint('Hello from generated code')"
@tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression.
Args:
expression: The math expression to evaluate.
"""
try:
result = eval(expression) # noqa: S307 -- demo only
return str(result)
except Exception as e:
return f"Error: {e}"
# --- Specialists -----------------------------------------------------
researcher = Agent(
name="researcher",
instructions=(
"You are a research specialist. Use the search_web tool to find "
"information. Provide well-sourced, factual answers."
),
model=OllamaModel(model="llama3.2"),
tools=[search_web],
)
coder = Agent(
name="coder",
instructions=(
"You are a coding specialist. Use the write_code tool to generate "
"code. Explain your approach clearly."
),
model=OllamaModel(model="llama3.2"),
tools=[write_code],
)
math_agent = Agent(
name="math_agent",
instructions=(
"You are a math specialist. Use the calculate tool to evaluate "
"expressions. Show your work step by step."
),
model=OllamaModel(model="llama3.2"),
tools=[calculate],
)
2 -- Set Up Handoffs¶
A Handoff connects a source agent to a target agent. The router uses handoffs to delegate.
from flux.handoffs.handoff import Handoff
router = Agent(
name="router",
instructions=(
"You are a router agent. Analyze the user's request and delegate "
"it to the right specialist:\n"
"- Use the researcher for factual questions or information lookups\n"
"- Use the coder for programming or code generation tasks\n"
"- Use the math_agent for mathematical calculations\n"
"After receiving the specialist's response, relay it to the user."
),
model=OllamaModel(model="llama3.2"),
handoffs=(
Handoff(source=router, target=researcher),
Handoff(source=router, target=coder),
Handoff(source=router, target=math_agent),
),
)
3 -- Run the Multi-Agent System¶
import asyncio
from flux import Runner
async def main():
# Research task
result = await Runner.run(router, "What is retrieval-augmented generation?")
print("Research:", result.final_output)
# Coding task
result = await Runner.run(router, "Write a Python function to reverse a string")
print("\nCoding:", result.final_output)
# Math task
result = await Runner.run(router, "What is 42 * 17 + 3?")
print("\nMath:", result.final_output)
asyncio.run(main())
4 -- Conditional Handoffs¶
You can make handoff decisions based on the content of the user's message by embedding logic in the router's instructions.
router = Agent(
name="router",
instructions=(
"You are an intelligent router. Analyze each request:\n\n"
"1. If the request asks about a person, place, or factual topic -> hand off to researcher\n"
"2. If the request asks to write, fix, or explain code -> hand off to coder\n"
"3. If the request involves numbers, equations, or math -> hand off to math_agent\n"
"4. If unsure, answer the question yourself.\n\n"
"Always relay the specialist's complete response to the user."
),
model=OllamaModel(model="llama3.2"),
handoffs=(
Handoff(source=router, target=researcher),
Handoff(source=router, target=coder),
Handoff(source=router, target=math_agent),
),
)
5 -- Streaming Multi-Agent Output¶
Stream responses even when agents hand off control.
async def stream_multi_agent(query: str):
result = await Runner.run_streamed(router, query)
async for event in result.stream_events():
if hasattr(event, "delta_text"):
print(event.delta_text, end="", flush=True)
print()
asyncio.run(stream_multi_agent("Calculate the factorial of 20"))
6 -- Full Working Example¶
"""Multi-agent system with routing and handoffs."""
import asyncio
from flux import Agent, Runner, tool
from flux.handoffs.handoff import Handoff
from flux.models.ollama import OllamaModel
# --- Tools -----------------------------------------------------------
@tool
def search_web(query: str) -> str:
"""Search the web for information.
Args:
query: The search query.
"""
return f"Search results for '{query}': Found relevant articles."
@tool
def write_code(description: str) -> str:
"""Write code based on a description.
Args:
description: What the code should do.
"""
return f"# Generated code\n# {description}\nprint('Hello')"
@tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression.
Args:
expression: The math expression to evaluate.
"""
try:
return str(eval(expression)) # noqa: S307
except Exception as e:
return f"Error: {e}"
# --- Specialists -----------------------------------------------------
researcher = Agent(
name="researcher",
instructions="You are a research specialist. Use search_web to find information.",
model=OllamaModel(model="llama3.2"),
tools=[search_web],
)
coder = Agent(
name="coder",
instructions="You are a coding specialist. Use write_code to generate code.",
model=OllamaModel(model="llama3.2"),
tools=[write_code],
)
math_agent = Agent(
name="math_agent",
instructions="You are a math specialist. Use calculate to evaluate expressions.",
model=OllamaModel(model="llama3.2"),
tools=[calculate],
)
# --- Router ----------------------------------------------------------
router = Agent(
name="router",
instructions=(
"You are a router. Analyze the request and delegate to the right "
"specialist: researcher for facts, coder for code, math_agent for "
"math. Relay the specialist's response to the user."
),
model=OllamaModel(model="llama3.2"),
handoffs=(
Handoff(source=router, target=researcher),
Handoff(source=router, target=coder),
Handoff(source=router, target=math_agent),
),
)
# --- Main ------------------------------------------------------------
async def main():
result = await Runner.run(router, "What is 42 * 17 + 3?")
print(result.final_output)
asyncio.run(main())
Mermaid: Multi-Agent Handoff Flow¶
sequenceDiagram
participant U as User
participant R as Router
participant RE as Researcher
participant CO as Coder
participant MA as Math Agent
U->>R: "What is 42 * 17 + 3?"
R->>R: Classify: math task
R->>MA: Handoff: "What is 42 * 17 + 3?"
MA->>MA: calculate("42 * 17 + 3")
MA-->>R: "42 * 17 + 3 = 717"
R-->>U: "The answer is 717."
Next Steps¶
- Add guardrails to validate inputs at the router level
- Use sessions to maintain conversation context across handoffs
- Apply middleware to log handoff decisions