Skip to content

How DeerFlow Sub-Agents Orchestrate Parallel Task Execution

Purpose

I’ve struggled with a fundamental limitation in AI agents: they can only do one thing at a time. When I need to research multiple angles of a problem, analyze code while generating tests, or explore different solutions in parallel, a single agent becomes a bottleneck.

DeerFlow solves this with sub-agents. The lead agent can spawn specialized child agents that run in parallel, each with its own isolated context. This post explains how the sub-agent system works and when to use it.

The Problem: Single-Agent Limitations

Complex tasks often require multiple perspectives. Here’s what happens when I ask a single agent to handle a complex research task:

Single-Agent Bottleneck
User: "Analyze the competitor landscape for our product"
|
v
Agent: "Let me research competitor A..." [5 minutes]
Agent: "Now competitor B..." [5 minutes]
Agent: "Now competitor C..." [5 minutes]
Agent: "Let me synthesize..." [2 minutes]
|
v
Total: 17+ minutes, sequential

The problem compounds when tasks are independent:

  1. Linear context window: The agent can only think about one thing at a time
  2. Sequential execution: No parallelism, even when tasks don’t depend on each other
  3. Context pollution: Previous task outputs can bias later tasks

How DeerFlow Sub-Agents Work

DeerFlow introduces a hierarchical agent architecture:

Sub-Agent Architecture
┌─────────────────┐
│ Lead Agent │
│ (Orchestrator) │
└────────┬────────┘
│ task() tool
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│Sub-Agent │ │Sub-Agent │ │Sub-Agent │
│ #1 │ │ #2 │ │ #3 │
│(Research)│ │ (Code) │ │(Analysis)│
└──────────┘ └──────────┘ └──────────┘
│ │ │
└──────────────┴──────────────┘
Synthesized Result

The lead agent has a task tool for delegation. When invoked, it creates a child agent that runs independently.

Exploring the Task Tool

I examined the task tool implementation:

tools/builtins/task.py
@tool
def task(
description: str,
prompt: str,
subagent_type: str = "general-purpose",
max_turns: int = 5
) -> str:
"""
Delegate a task to a sub-agent.
Args:
description: Brief task description
prompt: Detailed instructions for sub-agent
subagent_type: Type of agent (general-purpose, bash)
max_turns: Maximum turns for sub-agent
Returns:
Result from sub-agent execution
"""

The key parameters:

  • description: What the task is about (shown in logs)
  • prompt: Detailed instructions for the sub-agent
  • subagent_type: Which built-in agent to use
  • max_turns: How many conversation turns the sub-agent can take

Built-in Agent Types

DeerFlow ships with two built-in sub-agent types:

subagents/registry.py
BUILTIN_AGENTS = {
"general-purpose": AgentConfig(
name="general-purpose",
tools="all_except_task", # Cannot spawn more sub-agents
system_prompt="You are a specialized agent..."
),
"bash": AgentConfig(
name="bash",
tools=["bash", "read_file", "write_file"],
system_prompt="You are a bash specialist..."
)
}

The general-purpose agent has access to most tools but cannot spawn its own sub-agents (preventing infinite recursion). The bash agent is specialized for command execution.

Testing Parallel Execution

I wanted to see sub-agents in action. Here’s a test script:

test_subagents.py
from deerflow.client import DeerFlowClient
import time
client = DeerFlowClient()
# Request that benefits from parallel research
start = time.time()
response = client.chat(
"Research the following in parallel:\n"
"1. Latest React 19 features\n"
"2. Vue 3.4 improvements\n"
"3. Svelte 5 runes\n"
"Then synthesize a comparison.",
thread_id="parallel-test",
context={"subagent_enabled": True}
)
elapsed = time.time() - start
print(f"Total time: {elapsed:.1f}s")
print(response)

I watched the logs to confirm parallel execution:

Agent Logs
[lead-agent] Analyzing request...
[lead-agent] Spawning 3 sub-agents via task tool
[subagent-1] Started: Research React 19 features
[subagent-2] Started: Research Vue 3.4 improvements
[subagent-3] Started: Research Svelte 5 runes
[subagent-1] Completed in 12.3s
[subagent-2] Completed in 14.1s
[subagent-3] Completed in 11.8s
[lead-agent] Synthesizing results...
[lead-agent] Response complete

All three research tasks ran in parallel. The total time was ~14 seconds (the longest task), not 38 seconds (the sum).

How Concurrency is Enforced

I was curious about how DeerFlow prevents resource exhaustion. Here’s what I found:

Concurrency Limits

SubagentLimitMiddleware enforces a hard limit:

Concurrency Rules
- Max 3 concurrent sub-agents per turn
- 15-minute timeout per sub-agent
- Excess task calls are truncated from model response

This prevents the lead agent from spawning hundreds of sub-agents.

Thread Pool Architecture

DeerFlow uses dual thread pools:

Thread Pool Configuration
_scheduler_pool = ThreadPoolExecutor(max_workers=3) # For scheduling
_execution_pool = ThreadPoolExecutor(max_workers=3) # For execution

The separation ensures scheduling doesn’t block execution.

Monitoring Sub-Agent Events

Sub-agent execution emits SSE events for real-time monitoring:

monitor_subagents.py
from deerflow.client import DeerFlowClient
client = DeerFlowClient()
for event in client.stream("Research AI trends"):
if event.type == "task_started":
print(f"Sub-agent started: {event.data['task_id']}")
print(f" Description: {event.data['description']}")
elif event.type == "task_running":
print(f"Sub-agent running: {event.data['status']}")
elif event.type == "task_completed":
print(f"Sub-agent completed: {event.data['task_id']}")
print(f" Result length: {len(event.data['result'])} chars")
elif event.type == "task_failed":
print(f"Sub-agent failed: {event.data['error']}")
elif event.type == "task_timed_out":
print(f"Sub-agent timed out after 15 minutes")

This produces output like:

Event Stream Output
Sub-agent started: subagent-a1b2c3
Description: Research AI trends
Sub-agent running: searching web
Sub-agent running: analyzing results
Sub-agent completed: subagent-a1b2c3
Result length: 4521 chars

Sub-Agent Context Isolation

One of the most important aspects of sub-agents is context isolation:

Context Isolation
Lead Agent Context:
- Full conversation history
- All user messages
- Previous sub-agent results
Sub-Agent Context:
- Only the prompt passed to it
- Cannot see lead agent's conversation
- Cannot see other sub-agents' contexts

This isolation prevents:

  1. Context contamination: Sub-agent doesn’t get biased by lead agent’s thinking
  2. Information leakage: Sub-agent can’t access unrelated context
  3. Token waste: Sub-agent only sees what’s relevant to its task

When to Use Sub-Agents

Based on my testing, sub-agents excel at:

Good Use Cases

Multi-angle research

Example: Parallel Research
client.chat(
"Analyze our competitor from three angles:\n"
"1. Technical: API design, architecture\n"
"2. Business: Pricing, market position\n"
"3. UX: User reviews, feature requests",
context={"subagent_enabled": True}
)

Parallel code generation

Example: Generate Multiple Test Files
client.chat(
"Generate tests for all services in src/services/:\n"
"- auth.service.ts\n"
"- user.service.ts\n"
"- payment.service.ts",
context={"subagent_enabled": True}
)

Breaking down complex workflows

Example: Feature Implementation
client.chat(
"Implement the new dashboard feature:\n"
"1. Research best practices (sub-agent)\n"
"2. Design the data model (sub-agent)\n"
"3. Create API endpoints (sub-agent)\n"
"4. Build frontend components (sub-agent)\n"
"5. Write integration tests (sub-agent)",
context={"subagent_enabled": True}
)

Simple single-step queries

Skip Sub-Agents
User: "What's 2 + 2?"
# Sub-agent overhead is wasteful

Tasks requiring shared context

Skip Sub-Agents
User: "Refactor the function you just wrote"
# Sub-agent wouldn't have the context of what was written

Quick follow-up questions

Skip Sub-Agents
User: "Can you elaborate on point 3?"
# Direct response is faster

Configuration

Enable sub-agents via the context parameter:

API Request
{
"message": "Research competitor pricing",
"thread_id": "research-123",
"context": {
"thinking_enabled": true,
"is_plan_mode": false,
"subagent_enabled": true
}
}

The subagent_enabled flag must be explicitly set to true.

Issues I Encountered

During testing, I ran into a few issues:

Issue 1: Sub-Agent Timeout

When a sub-agent took too long:

Timeout Error
Error: Sub-agent timed out after 15 minutes
Task ID: subagent-xyz789
Description: Research enterprise AI solutions

The fix was to reduce task scope:

Fix: Smaller Tasks
# WRONG: Too broad
client.chat("Research all AI frameworks")
# CORRECT: Focused scope
client.chat("Research Python AI frameworks for web apps")

Issue 2: Context Not Shared

I expected sub-agents to see the lead agent’s context:

Confusion
Lead Agent: "I mentioned React earlier"
Sub-Agent: "I don't know what React is"

This is by design. Sub-agents only receive the prompt you give them:

Fix: Explicit Context
client.chat(
"Task 1: Research React 19 features\n"
"Context: React is a JavaScript UI library by Meta\n"
"Focus on the new compiler and server components."
)

Issue 3: Concurrency Limit Hit

When I tried to spawn 5 sub-agents:

Truncation Warning
[lead-agent] Warning: Only 3 sub-agents allowed per turn
[lead-agent] Tasks 4 and 5 were truncated

The middleware silently drops excess tasks. The fix is to batch:

Fix: Batch Large Tasks
# First batch
client.chat("Research frameworks A, B, and C")
# Second batch (in new turn)
client.chat("Now research frameworks D and E")

Performance Comparison

I ran benchmarks comparing single-agent vs sub-agent execution:

Benchmark Results
Task: Research 3 topics and synthesize
Single Agent:
- Sequential execution
- Total time: 47.3 seconds
- Context used: ~12,000 tokens
Sub-Agents (3 parallel):
- Parallel execution
- Total time: 18.7 seconds (longest task)
- Context per sub-agent: ~4,000 tokens
- Lead agent context: ~2,000 tokens
- Total tokens: ~14,000 (some overhead)

The speedup was 2.5x for parallelizable tasks. Token usage was similar due to coordination overhead.

Why This Matters

AspectSingle AgentDeerFlow Sub-Agents
ParallelismNoneUp to 3 concurrent
Context isolationSharedPer-agent isolation
SpecializationGenericTask-specific tools
Task complexityLimitedMulti-hour workflows
Result qualitySingle perspectiveSynthesized from multiple
Timeout handlingN/A15-minute limit per sub-agent

For complex AI applications, sub-agents provide a way to decompose problems while maintaining isolation and enabling parallelism.

My Recommendation

Sub-agents are powerful but shouldn’t be the default. I recommend:

Use sub-agents when:

  • Tasks are independent and parallelizable
  • You need multiple perspectives on a problem
  • Each sub-task has a clear, bounded scope
  • You want to avoid context contamination

Stick with single agent when:

  • Tasks are quick and simple
  • Context sharing is important
  • Sequential execution makes sense
  • You’re doing conversational follow-ups

For teams building AI workflows in DeerFlow, start with the single agent. Add sub-agents only when you identify bottlenecks that parallelization can solve.

Summary

DeerFlow’s sub-agent system enables true parallel task execution through hierarchical agent delegation. The lead agent spawns child agents with isolated contexts, runs up to 3 concurrently, and synthesizes results.

I tested the system with parallel research tasks and observed 2.5x speedup for independent operations. The key limitations are: 3 concurrent sub-agents maximum, 15-minute timeout per sub-agent, and no context sharing between agents.

For developers building complex AI workflows, sub-agents provide a pattern for decomposing large tasks while maintaining isolation and enabling parallelism. The tradeoff is coordination overhead, so reserve sub-agents for tasks that genuinely benefit from parallel execution.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments