| name | deepagents-subagents |
| description | Using SubAgentMiddleware to spawn subagents for task delegation, context isolation, and specialized work in Deep Agents. |
| language | python |
deepagents-subagents (Python)
Overview
SubAgentMiddleware enables agents to delegate work to specialized subagents via the task tool. Subagents provide:
- Context isolation: Subagent work doesn't clutter main agent's context
- Specialization: Different tools/prompts for specific tasks
- Token efficiency: Large subtask context compressed into single result
- Parallel execution: Multiple subagents can run concurrently
When to Use Subagents
| Use Subagents When | Use Main Agent When |
|---|
| Task needs specialized tools | General-purpose tools sufficient |
| Want to isolate complex multi-step work | Single-step operation |
| Need clean context for main agent | Context bloat acceptable |
| Task benefits from different model/prompt | Same config works |
How It Works
Main agent has task tool → creates fresh subagent → subagent executes autonomously → returns final report to main agent.
Default subagent: "general-purpose" - automatically available with same tools/config as main agent.
Defining Subagents
Dictionary-based Subagent
from deepagents import create_deep_agent
from langchain.tools import tool
@tool
def search_papers(query: str) -> str:
"""Search academic papers."""
return f"Found 10 papers about {query}"
@tool
def summarize_paper(paper_id: str) -> str:
"""Summarize a research paper."""
return f"Summary of paper {paper_id}"
agent = create_deep_agent(
subagents=[
{
"name": "research",
"description": "Research academic papers and provide summaries",
"system_prompt": "You are a research assistant. Search papers and provide concise summaries.",
"tools": [search_papers, summarize_paper],
"model": "claude-sonnet-4-5-20250929",
}
]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Research recent papers on transformers"}]
})
CompiledSubAgent (Custom LangGraph)
from deepagents import create_deep_agent, CompiledSubAgent
from langgraph.graph import StateGraph
def create_weather_graph():
workflow = StateGraph(...)
return workflow.compile()
weather_graph = create_weather_graph()
weather_subagent = CompiledSubAgent(
name="weather",
description="Get weather forecasts for cities",
runnable=weather_graph
)
agent = create_deep_agent(
subagents=[weather_subagent]
)
Decision Table: Subagent Patterns
| Pattern | When to Use | Example |
|---|
| Specialized tools | Task needs unique tools | code-reviewer with linting tools |
| Different model | Cost/capability tradeoff | GPT-4 main, GPT-3.5 for simple subagents |
| Context isolation | Keep main context clean | web-research dumps to files, returns summary |
| Parallel work | Independent subtasks | analyze-data + generate-report simultaneously |
Code Examples
Example 1: Research Subagent
from deepagents import create_deep_agent
from langchain.tools import tool
@tool
def web_search(query: str) -> str:
"""Search the web."""
return f"Search results for: {query}"
@tool
def analyze_data(data: str) -> str:
"""Analyze data and extract insights."""
return f"Analysis: {data[:100]}..."
agent = create_deep_agent(
subagents=[
{
"name": "researcher",
"description": "Conduct web research and compile findings",
"system_prompt": "Search thoroughly, save results to /research/ directory, return concise summary",
"tools": [web_search],
},
{
"name": "analyst",
"description": "Analyze data and provide insights",
"system_prompt": "Provide data-driven insights with specific numbers",
"tools": [analyze_data],
}
]
)
result = agent.invoke({
"messages": [{
"role": "user",
"content": "Research market trends for EVs, then analyze the data"
}]
})
Example 2: Subagent with Human-in-the-Loop
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(
subagents=[
{
"name": "code-deployer",
"description": "Deploy code to production",
"system_prompt": "Deploy code safely with all checks",
"tools": [run_tests, deploy_to_prod],
"interrupt_on": {"deploy_to_prod": True},
}
],
checkpointer=MemorySaver()
)
Example 3: Subagent with Custom Skills
from deepagents import create_deep_agent
agent = create_deep_agent(
skills=["/main-skills/"],
subagents=[
{
"name": "python-expert",
"description": "Python code review and refactoring",
"system_prompt": "Review Python code for best practices",
"tools": [read_code, suggest_improvements],
"skills": ["/python-skills/"],
}
]
)
Example 4: Default General-Purpose Subagent
from deepagents import create_deep_agent
agent = create_deep_agent()
result = agent.invoke({
"messages": [{
"role": "user",
"content": "Analyze this large dataset and summarize the key findings"
}]
})
Boundaries
What Agents CAN Configure
✅ Subagent name and description
✅ Custom tools for subagents
✅ Different models per subagent
✅ Subagent-specific system prompts
✅ Subagent middleware and skills
✅ Human-in-the-loop for subagent tools
What Agents CANNOT Configure
❌ Change the task tool name
❌ Make subagents stateful (they're ephemeral)
❌ Share state directly between subagents
❌ Remove the default general-purpose subagent
❌ Have subagents call back to main agent
Gotchas
1. Subagents Are Stateless
agent.invoke({"messages": [{"role": "user", "content": "task(agent='research', instruction='Find data')"}]})
agent.invoke({"messages": [{"role": "user", "content": "task(agent='research', instruction='What did you find?')"}]})
2. Custom Subagents Don't Inherit Skills
agent = create_deep_agent(
skills=["/main-skills/"],
subagents=[{"name": "helper", ...}]
)
agent = create_deep_agent(
skills=["/main-skills/"],
subagents=[{
"name": "helper",
"skills": ["/helper-skills/"],
...
}]
)
3. Subagent Results Are Final
4. Subagent Interrupts Require Main Checkpointer
agent = create_deep_agent(
subagents=[{
"name": "deployer",
"interrupt_on": {"deploy": True}
}]
)
agent = create_deep_agent(
subagents=[{
"name": "deployer",
"interrupt_on": {"deploy": True}
}],
checkpointer=MemorySaver()
)
Full Documentation