Subagents¶
Subagents allow the main agent to delegate specialized tasks to focused, context-isolated agents.
Why Subagents?¶
- Focused context - Each subagent has a clear, specific purpose
- Isolation - Fresh todo list, no nested delegation
- Specialization - Expert instructions for specific tasks
- Reduced confusion - Less context = better performance
Defining Subagents¶
from pydantic_deep import create_deep_agent, SubAgentConfig
subagents = [
SubAgentConfig(
name="code-reviewer",
description="Reviews code for quality, security, and best practices",
instructions="""
You are an expert code reviewer. When reviewing code:
1. Check for security vulnerabilities
2. Look for performance issues
3. Verify proper error handling
4. Assess code readability
Provide specific, actionable feedback.
""",
),
SubAgentConfig(
name="test-writer",
description="Generates pytest test cases for Python code",
instructions="""
You are a testing expert. Generate comprehensive tests:
- Unit tests for individual functions
- Edge cases and error conditions
- Use pytest fixtures and parametrize
- Include docstrings explaining each test
""",
),
SubAgentConfig(
name="doc-writer",
description="Writes documentation and docstrings",
instructions="""
You are a technical writer. Create clear documentation:
- Use Google-style docstrings
- Include examples in docstrings
- Write clear README sections
- Document edge cases and gotchas
""",
),
]
agent = create_deep_agent(subagents=subagents)
How the Task Tool Works¶
The main agent can call the task tool:
task(
description="Review the authentication module for security issues",
subagent_type="code-reviewer",
)
This:
- Creates a new agent with the subagent's instructions
- Clones dependencies with:
- Same backend (shared files)
- Empty todo list (isolated planning)
- No nested subagents
- Runs the subagent with the description as prompt
- Returns the subagent's output to the main agent
Context Isolation¶
Subagents receive isolated context:
def clone_for_subagent(self) -> DeepAgentDeps:
"""Create deps for a subagent."""
return DeepAgentDeps(
backend=self.backend, # Shared - can read/write same files
files=self.files, # Shared reference
todos=[], # Fresh - subagent plans independently
subagents={}, # Empty - no nested delegation
)
This prevents:
- Context bloat from accumulated todos
- Infinite recursion from nested delegation
- Confusion from mixed responsibilities
General-Purpose Subagent¶
By default, a general-purpose subagent is included:
This allows delegation for tasks without a specialized subagent:
Disable if you only want specific subagents:
Custom Model per Subagent¶
Use different models for different subagents:
subagents = [
SubAgentConfig(
name="code-reviewer",
description="Reviews code (uses powerful model)",
instructions="...",
model="openai:gpt-4.1",
),
SubAgentConfig(
name="simple-formatter",
description="Formats code (uses fast model)",
instructions="...",
model="anthropic:claude-3-haiku-20240307",
),
]
Custom Tools per Subagent¶
Subagents can have custom tools:
async def run_tests(ctx, path: str) -> str:
"""Run pytest on the given path."""
...
subagents = [
SubAgentConfig(
name="test-writer",
description="Writes and runs tests",
instructions="...",
tools=[run_tests],
),
]
Example: Code Review Pipeline¶
import asyncio
from pydantic_deep import create_deep_agent, DeepAgentDeps, StateBackend, SubAgentConfig
async def main():
subagents = [
SubAgentConfig(
name="code-reviewer",
description="Reviews code for issues",
instructions="""
Review code thoroughly. Check for:
- Security issues
- Performance problems
- Error handling
- Code style
Format your review as markdown with sections.
""",
),
SubAgentConfig(
name="test-writer",
description="Generates pytest tests",
instructions="""
Write comprehensive pytest tests.
Cover happy paths, edge cases, and error conditions.
Use fixtures and parametrize decorators.
""",
),
]
agent = create_deep_agent(subagents=subagents)
deps = DeepAgentDeps(backend=StateBackend())
# Create some code to review
deps.backend.write("/src/auth.py", '''
def authenticate(username, password):
query = f"SELECT * FROM users WHERE username = '{username}'"
user = db.execute(query)
if user and user.password == password:
return True
return False
''')
result = await agent.run(
"""
1. Review /src/auth.py for security issues
2. Generate tests for the authenticate function
3. Report findings
""",
deps=deps,
)
print(result.output)
asyncio.run(main())
Best Practices¶
1. Clear Descriptions¶
The description helps the main agent choose:
# Good - clear when to use
SubAgentConfig(
name="security-reviewer",
description="Reviews code specifically for security vulnerabilities like SQL injection, XSS, and authentication issues",
...
)
# Bad - too vague
SubAgentConfig(
name="reviewer",
description="Reviews code",
...
)
2. Focused Instructions¶
Keep subagent instructions focused:
# Good - specific focus
instructions="""
You are a security expert. Focus ONLY on:
- SQL injection
- XSS vulnerabilities
- Authentication issues
- Authorization flaws
Do NOT comment on code style or performance.
"""
# Bad - too broad
instructions="Review the code and check everything."
3. Output Format¶
Specify expected output format:
instructions="""
...
Output your review in this format:
## Summary
[1-2 sentence overview]
## Critical Issues
- [Issue 1]
- [Issue 2]
## Recommendations
- [Recommendation 1]
"""
4. Limited Subagents¶
Use 3-5 focused subagents, not many generic ones:
# Good - focused experts
subagents = [
SubAgentConfig(name="security-reviewer", ...),
SubAgentConfig(name="test-writer", ...),
SubAgentConfig(name="doc-writer", ...),
]
# Bad - too many similar agents
subagents = [
SubAgentConfig(name="python-reviewer", ...),
SubAgentConfig(name="javascript-reviewer", ...),
SubAgentConfig(name="typescript-reviewer", ...),
SubAgentConfig(name="go-reviewer", ...),
# ... 10 more language-specific reviewers
]
Next Steps¶
- Streaming - Monitor subagent progress
- Examples - More examples
- API Reference - SubAgentToolset API