Deep Agent Chaining
On this page
Unlimited Agent Chains
The Mistral Agents API imposes no depth limit on agent chaining. One agent can hand off to a second, which hands off to a third, and so on. This freedom enables complex, modular workflows, but it also places the responsibility for topology on you: you decide who can call whom. This map determines system behavior just as much as the instructions for each individual agent.
Three Topologies and Their Implications
The linear chain is the simplest pattern: each agent passes to the next without branching.
Agent A → Agent B → Agent C → Response
This suits processes where the order is known in advance and never changes. A typical example is search, then analysis, then writing: you don’t write before analyzing, and you don’t analyze before searching.
# Research agent
research = client.beta.agents.create(
model="mistral-large-latest",
name="research",
description="Search for factual information.",
tools=[{"type": "web_search"}]
)
# Analysis agent
analyst = client.beta.agents.create(
model="mistral-large-latest",
name="analyst",
description="Analyze data and extract insights.",
tools=[{"type": "code_interpreter"}]
)
# Writing agent
writer = client.beta.agents.create(
model="mistral-large-latest",
name="writer",
description="Draft professional reports.",
instructions="Write a structured report based on the analyzed data."
)
# Chain: research → analyst → writer
research = client.beta.agents.update(
agent_id=research.id,
handoffs=[analyst.id]
)
analyst = client.beta.agents.update(
agent_id=analyst.id,
handoffs=[writer.id]
)
Each agent knows only its immediate successor: research is unaware that writer even exists. The chain exists only in the update calls, nowhere else.
The star chain addresses the opposite need: a central router distributes tasks to specialists who do not talk to each other.
┌→ Web Search Agent
Router ──┼→ Calculator Agent
└→ Writer Agent
router = client.beta.agents.create(
model="mistral-large-latest",
name="router",
description="Orchestrate requests.",
handoffs=[research.id, analyst.id, writer.id]
)
Here, the order isn’t predetermined—the request itself decides the destination. This form fits versatile assistants where each request falls under one specific competency.
The hybrid topology combines both: the router distributes, and specialists can also hand off to one another.
┌→ Research Agent ──→ Analyst Agent
Router ──┤ │
└→ Writer Agent ←───────────┘
# Research can hand off to Analyst
research = client.beta.agents.update(
agent_id=research.id,
handoffs=[analyst.id]
)
# Analyst can hand off to Writer
analyst = client.beta.agents.update(
agent_id=analyst.id,
handoffs=[writer.id]
)
# Router can access all
router = client.beta.agents.update(
agent_id=router.id,
handoffs=[research.id, analyst.id, writer.id]
)
This is the most powerful form, but also the hardest to debug. The same request can follow different paths from one execution to the next, making handoff logging essential once you leave the sandbox.
Two Production Pipelines
Data processing illustrates the linear chain in its most natural use case: collect, clean, visualize. The last two steps use the same tool, but separating them keeps each instruction set clean—cleaning and representing are distinct jobs.
# Step 1: Collection
collector = client.beta.agents.create(
model="mistral-large-latest",
name="data-collector",
description="Collect data from the internet.",
tools=[{"type": "web_search"}]
)
# Step 2: Cleaning and transformation
transformer = client.beta.agents.create(
model="mistral-large-latest",
name="data-transformer",
description="Clean and transform raw data.",
tools=[{"type": "code_interpreter"}]
)
# Step 3: Analysis and visualization
visualizer = client.beta.agents.create(
model="mistral-large-latest",
name="data-visualizer",
description="Create visualizations and charts.",
tools=[{"type": "code_interpreter"}]
)
# Chain
collector = client.beta.agents.update(agent_id=collector.id, handoffs=[transformer.id])
transformer = client.beta.agents.update(agent_id=transformer.id, handoffs=[visualizer.id])
An academic research assistant follows the same structure but with a different kind of intermediate link. The synthesizer has no tools: its value lies entirely in its instructions, which ask it to confront sources—common points, divergences, gaps—rather than just stacking them.
# Searcher
searcher = client.beta.agents.create(
model="mistral-large-latest",
name="academic-searcher",
description="Search for academic articles and publications.",
tools=[{"type": "web_search"}]
)
# Synthesizer
synthesizer = client.beta.agents.create(
model="mistral-large-latest",
name="synthesizer",
description="Synthesize and compare multiple sources.",
instructions="Identify common points, divergences, and gaps."
)
# Writer
academic_writer = client.beta.agents.create(
model="mistral-large-latest",
name="academic-writer",
description="Structured academic writing with citations.",
instructions="Write in academic format with introduction, methodology, results, discussion."
)
# Pipeline: searcher → synthesizer → writer
searcher = client.beta.agents.update(agent_id=searcher.id, handoffs=[synthesizer.id])
synthesizer = client.beta.agents.update(agent_id=synthesizer.id, handoffs=[academic_writer.id])
Keeping Depth Reasonable
The lack of a technical limit isn’t an invitation to go wild. In practice, chaining two to four agents covers the vast majority of needs. Beyond five, both latency and cost rise sharply. The reason is mechanical: each agent adds its own context tokens, including instructions, on top of a conversation history that has only grown since the first handoff. A fifth agent doesn’t work on the initial request but on everything the previous four produced.
Before lengthening a chain, ask yourself whether the extra step deserves a dedicated agent or if it fits within an existing agent’s instructions. A formatting directive, for example, almost never justifies an extra link.
Also note that an agent isn’t restricted to a single target. It can declare multiple targets and choose based on context.
analyst = client.beta.agents.update(
agent_id=analyst.id,
handoffs=[writer.id, visualizer.id, calculator.id]
)
This analyst will route to the writer if the result is ready to be told, to the visualizer if the data calls for a chart, or to the calculator if a figure is still missing. The choice relies, as always, on the descriptions of the three targets—the only information available to make the call.
Key Takeaways
- No depth limit for agent chaining
- Three patterns: linear (A→B→C), star (router→specialists), hybrid (graph)
- Each agent can have multiple handoff targets
- In production, limit chains to 2–4 agents to control latency and costs
- Agent descriptions are crucial for effective routing