Skip to content

Commit 32db1cf

Browse files
authored
Merge pull request #2187 from dgageot/fix-docker-agent-issue-2184
docs: document the handoffs routing mechanism
2 parents b31e226 + 3959ec7 commit 32db1cf

3 files changed

Lines changed: 114 additions & 17 deletions

File tree

docs/concepts/multi-agent/index.md

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,33 @@ Complex tasks benefit from specialization. Instead of one monolithic agent tryin
1919

2020
Each agent has its own model, tools, and instructions — optimized for its specific role.
2121

22-
## How Delegation Works
22+
## Two Patterns: Delegation vs. Handoffs
2323

24-
Agents delegate tasks using the built-in `transfer_task` tool, which is automatically available to any agent with sub-agents. This smart delegation means agents can automatically route tasks to the most suitable specialist.
24+
docker-agent supports two multi-agent patterns:
25+
26+
| | **Delegation** (`sub_agents`) | **Handoffs** (`handoffs`) |
27+
|---|---|---|
28+
| **Topology** | Hierarchical (parent → child → parent) | Peer-to-peer graph (A → B → C → A) |
29+
| **Session** | Child runs in a **sub-session** | Conversation stays in the **same session** |
30+
| **Context** | Child gets a clean task description | Next agent sees the **full conversation history** |
31+
| **Control flow** | Parent blocks until child finishes, then continues | Active agent switches — previous agent is no longer in the loop |
32+
| **Tool** | `transfer_task` | `handoff` |
33+
| **Best for** | Task delegation to specialists | Pipeline workflows, conversational routing |
34+
35+
You can combine both patterns in the same configuration — an agent can have both `sub_agents` and `handoffs`.
36+
37+
<div class="callout callout-tip">
38+
<div class="callout-title">💡 When to use which
39+
</div>
40+
<p><strong><code>sub_agents</code></strong> — Use when a coordinator needs to send tasks to specialists and synthesize their results.</p>
41+
<p><strong><code>handoffs</code></strong> — Use when agents should take turns processing the same conversation (pipelines, routing).</p>
42+
<p><strong><code>background_agents</code></strong> — Use when multiple independent tasks can run simultaneously.</p>
43+
44+
</div>
45+
46+
## Delegation with `sub_agents`
47+
48+
Agents delegate tasks using the built-in `transfer_task` tool, which is automatically available to any agent with `sub_agents`. The parent agent sends a task to a child agent, waits for the result, and then continues.
2549

2650
1. **User** sends a message to the root agent
2751
2. **Root agent** analyzes the request and decides which sub-agent should handle it
@@ -45,11 +69,89 @@ transfer_task(
4569

4670
</div>
4771

72+
## Handoffs Routing
73+
74+
Handoffs are a peer-to-peer routing pattern where agents **hand off the entire conversation** to another agent. Unlike delegation, there is no sub-session — the conversation stays in a single session and the active agent simply switches.
75+
76+
This pattern is ideal for:
77+
78+
- **Pipeline workflows** — data flows through a chain of specialized agents
79+
- **Conversational routing** — a coordinator routes the user to the right specialist, who can route back when done
80+
- **Graph topologies** — agents can form cycles (A → B → C → A), enabling iterative workflows
81+
82+
### How It Works
83+
84+
1. **User** sends a message to the starting agent
85+
2. **Agent A** processes the message, then calls `handoff` to route to **Agent B**
86+
3. **Agent B** becomes the active agent and sees the **full conversation history**
87+
4. **Agent B** can respond, use its own tools, or hand off to another agent
88+
5. This continues until an agent responds directly without handing off
89+
90+
```bash
91+
# The handoff tool call looks like:
92+
handoff(
93+
agent="summarizer"
94+
)
95+
```
96+
97+
<div class="callout callout-info">
98+
<div class="callout-title">ℹ️ Scoped Handoff Targets
99+
</div>
100+
<p>Each agent can only hand off to agents listed in its own <code>handoffs</code> array. The <code>handoff</code> tool is automatically injected — you don't need to add it manually.</p>
101+
102+
</div>
103+
104+
### Example
105+
106+
A coordinator routes to a researcher, who hands off to a summarizer, who returns to the coordinator:
107+
108+
```
109+
Root ──→ Researcher ──→ Summarizer ──→ Root
110+
```
111+
112+
```yaml
113+
agents:
114+
root:
115+
model: anthropic/claude-sonnet-4-5
116+
description: Coordinator that routes queries
117+
instruction: |
118+
Route research queries to the researcher.
119+
handoffs:
120+
- researcher
121+
122+
researcher:
123+
model: openai/gpt-4o
124+
description: Web researcher
125+
instruction: |
126+
Search the web, then hand off to the summarizer.
127+
toolsets:
128+
- type: mcp
129+
ref: docker:duckduckgo
130+
handoffs:
131+
- summarizer
132+
133+
summarizer:
134+
model: openai/gpt-4o-mini
135+
description: Summarizes findings
136+
instruction: |
137+
Summarize the research results, then hand off
138+
back to root.
139+
handoffs:
140+
- root
141+
```
142+
143+
<div class="callout callout-tip">
144+
<div class="callout-title">💡 Full pipeline example
145+
</div>
146+
<p>For a more complex handoff graph with branching and multiple processing stages, see <a href="https://github.com/docker/docker-agent/blob/main/examples/handoff.yaml"><code>examples/handoff.yaml</code></a>.</p>
147+
148+
</div>
149+
48150
## Parallel Delegation with Background Agents
49151
50152
`transfer_task` is **sequential** — the coordinator waits for the sub-agent to finish before continuing. When you need to fan out work to multiple agents at the same time, use the `background_agents` toolset instead.
51153

52-
Add it to your coordinators toolsets:
154+
Add it to your coordinator's toolsets:
53155

54156
```yaml
55157
agents:
@@ -81,14 +183,6 @@ list_background_agents()
81183
view_background_agent(task_id="agent_task_abc123")
82184
```
83185

84-
<div class="callout callout-tip">
85-
<div class="callout-title">💡 When to use which
86-
</div>
87-
<p><strong><code>transfer_task</code></strong> — simple, sequential delegation. Best when the coordinator needs the result before deciding what to do next.</p>
88-
<p><strong><code>background_agents</code></strong> — parallel, async delegation. Best when multiple independent tasks can run simultaneously.</p>
89-
90-
</div>
91-
92186
## Example: Development Team
93187

94188
```yaml
@@ -213,6 +307,7 @@ toolsets:
213307
- **Give minimal tools** — Only give each agent the tools it needs for its specific role
214308
- **Use the think tool** — Give coordinators the think tool so they reason about delegation
215309
- **Use the right model** — Use capable models for complex reasoning, cheap models for simple tasks
310+
- **Choose the right pattern** — Use `sub_agents` for hierarchical task delegation, `handoffs` for pipeline workflows and conversational routing
216311

217312
<div class="callout callout-info">
218313
<div class="callout-title">ℹ️ Beyond docker-agent

docs/configuration/agents/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ agents:
3535
commands: # Optional: named prompts
3636
name: "prompt text"
3737
welcome_message: string # Optional: message shown at session start
38-
handoffs: [list] # Optional: list of A2A handoff agents
38+
handoffs: [list] # Optional: agent names this agent can hand off to
3939
hooks: # Optional: lifecycle hooks
4040
pre_tool_use: [list]
4141
post_tool_use: [list]
@@ -77,7 +77,7 @@ agents:
7777
| `skills` | boolean | ✗ | Enable automatic skill discovery from standard directories. |
7878
| `commands` | object | ✗ | Named prompts that can be run with `docker agent run config.yaml /command_name`. |
7979
| `welcome_message` | string | ✗ | Message displayed to the user when a session starts. Useful for providing context or instructions. |
80-
| `handoffs` | array | ✗ | List of A2A agent configurations this agent can delegate to. See [A2A Protocol]({{ '/features/a2a/' | relative_url }}). |
80+
| `handoffs` | array | ✗ | List of agent names this agent can hand off the conversation to. Enables the `handoff` tool. See [Handoffs Routing]({{ '/concepts/multi-agent/#handoffs-routing' | relative_url }}). |
8181
| `hooks` | object | ✗ | Lifecycle hooks for running commands at various points. See [Hooks]({{ '/configuration/hooks/' | relative_url }}). |
8282
| `structured_output` | object | ✗ | Constrain agent output to match a JSON schema. See [Structured Output]({{ '/configuration/structured-output/' | relative_url }}). |
8383

docs/guides/tips/index.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,18 +259,20 @@ Understand the difference between `sub_agents` and `handoffs`:
259259
<div class="cards">
260260
<div class="card" style="cursor:default;">
261261
<h3>sub_agents (transfer_task)</h3>
262-
<p>Delegates task to a child, waits for result, then continues. The parent remains in control.</p>
262+
<p>Delegates task to a child in a sub-session, waits for result, then continues. Hierarchical — the parent remains in control.</p>
263263
<pre style="margin-top:12px"><code class="language-yaml">sub_agents: [researcher, writer]</code></pre>
264264
</div>
265265
<div class="card" style="cursor:default;">
266-
<h3>handoffs (A2A)</h3>
267-
<p>Transfers control entirely to another agent (possibly remote). One-way handoff.</p>
266+
<h3>handoffs (peer-to-peer)</h3>
267+
<p>Hands off the entire conversation to another agent in the same session. The active agent switches and sees the full history. Agents can form cycles.</p>
268268
<pre style="margin-top:12px"><code class="language-yaml">handoffs:
269269
- specialist
270-
- namespace/remote-agent</code></pre>
270+
- summarizer</code></pre>
271271
</div>
272272
</div>
273273

274+
See <a href="{{ '/concepts/multi-agent/' | relative_url }}">Multi-Agent Systems</a> for a detailed comparison.
275+
274276
### Give Sub-Agents Clear Descriptions
275277

276278
The root agent uses descriptions to decide which sub-agent to delegate to:

0 commit comments

Comments
 (0)