Building Multi-Agent Applications with Deep Agents

Building Multi-Agent Applications with Deep Agents

Splitting a complex task across specialized agents is one of the most reliable ways to build a capable system. Deep Agents gives you two primitives to do it: subagents delegate work to isolated agents, and skills disclose capabilities only when they’re needed. Used together, they solve the two problems that break long-running agents — a cluttered context window and an overloaded tool set.

Subagents: isolated, specialized workers

The problem subagents solve is context bloat — an agent’s context window filling up as it works. Models degrade as that window fills; a task drowning in intermediate results gets noticeably worse answers.

A subagent runs in its own context window and returns only its final result. When the main agent needs twenty web searches or file reads, it delegates them; the twenty tool calls and their raw output stay in the subagent’s context, and only the summary comes back. The main agent’s context stays clean.

Basic subagents architecture

Reach for a subagent when you want:

  • Context preservation — a multi-step subtask (like codebase exploration) that would otherwise clutter the main context.
  • Specialization — domain-specific instructions or tools, or verticals owned by different teams.
  • Multi-model routing — a smaller, faster model for a narrow job while the main agent stays on a stronger one.
  • Parallelism — several subagents running at once and reporting back, cutting latency.

Defining a subagent

Subagents are dictionaries passed to create_deep_agent():

from deepagents import create_deep_agent

research_subagent = {
    "name": "research-agent",
    "description": "Used to research more in depth questions",
    "system_prompt": "You are a great researcher",
    "tools": [internet_search],
    "model": "openai:gpt-4o",  # Optional: override main agent model
}

agent = create_deep_agent(
    model="claude-sonnet-4-5-20250929",
    subagents=[research_subagent]
)

Deep Agents also ships a built-in general-purpose subagent that mirrors the main agent’s prompt, tools, and model. It’s the simplest way to get context isolation with no specialization — delegate a research burst to it with task(name="general-purpose", task="Research quantum computing trends") and it runs every search internally, returning just the summary.

Subagent practices

Write descriptions the main agent can route on. The main agent picks a subagent from its description alone.

  • Good: “Analyzes financial data and generates investment insights with confidence scores”
  • Bad: “Does finance stuff”

Keep system prompts detailed — include tool guidance and an output format:

research_subagent = {
    "name": "research-agent",
    "description": "Conducts in-depth research using web search and synthesizes findings",
    "system_prompt": """You are a thorough researcher. Your job is to:

    1. Break down the research question into searchable queries
    2. Use internet_search to find relevant information
    3. Synthesize findings into a comprehensive but concise summary
    4. Cite sources when making claims

    Output format:
    - Summary (2-3 paragraphs)
    - Key findings (bullet points)
    - Sources (with URLs)

    Keep your response under 500 words to maintain clean context.""",
    "tools": [internet_search],
}

Give each subagent only the tools it needs:

# Good: focused tool set
email_agent = {
    "name": "email-sender",
    "tools": [send_email, validate_email],
}

# Bad: unfocused
email_agent = {
    "name": "email-sender",
    "tools": [send_email, web_search, database_query, file_upload],
}

Skills: progressive disclosure

Skills attack a different problem: too many tools loaded at once. Instead of arming the agent with dozens of tools upfront, you define capabilities in SKILL.md files. The agent sees only the skill names and descriptions, and reads a skill’s full instructions when — and only when — it decides the skill applies.

Skill disclosure flow
Skill descriptions are pre-loaded; each skill’s body loads only when the agent decides it’s needed.

Skills follow the agentskills.io spec:

.deepagents/skills/
├── deploy/SKILL.md
└── review-pr/SKILL.md

Each file is YAML frontmatter plus a body:

---
name: deploy
description: Deploy to production
version: 1.0.0  # Optional
tags: [deployment, production]  # Optional
---

# Deploy to Production

When the user asks to deploy, follow these steps:

1. Run tests: `npm test`
2. Build the application: `npm run build`
3. Deploy to production: `npm run deploy:prod`
4. Verify deployment: Check the health endpoint

Always confirm with the user before deploying to production.

Load them from the filesystem with the skills argument:

from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend

agent = create_deep_agent(
    model="claude-sonnet-4-5-20250929",
    backend=FilesystemBackend(root_dir="/"),
    skills=[".deepagents/skills"],
)

Which one — and when to use both

When you need to… Use
Delegate complex, multi-step work Subagents (context isolation)
Reuse a procedure or set of instructions Skills (progressive disclosure)
Provide specialized tools for a specific task Subagents with focused tools
Share capabilities across several agents Skills — they’re just files
Work with a large tool set Skills, to avoid token bloat

Most real systems use both: skills define the procedures, subagents execute the multi-step work, and a subagent can itself load skills to keep its own context lean. Start with subagents for context management, add skills for disclosure, and compose from there.

Long-running tasks

For extended tasks, the finite context window becomes the binding constraint. Deep Agents includes a built-in context compression system — filesystem offloading plus summarization — to hold off context rot over long sessions. The mechanics and how to evaluate them are covered in Context Management for Deep Agents.

This entry was posted in . Bookmark the permalink.