Módulo 11: Deep Agents

Subagent Spawning y Delegación

Descripción de la cápsula

El agente puede crear subagentes especializados on-demand para manejar subtareas. A diferencia del Módulo 10 donde tú diseñaste el sistema multi-agente (quién hace qué, cómo se comunican, qué estado comparten), aquí el agente decide cuándo y qué delegar en runtime. Es multi-agente orquestado por el agente mismo. El valor es claro: para tareas complejas, un solo agente generalista produce resultados mediocres. Un equipo de especialistas — cada uno enfocado en un aspecto — produce resultados mejores. Con subagent spawning, ese equipo se forma dinámicamente según lo que la tarea requiere.


Cómo funciona el subagent spawning

El flujo completo

1. Agente principal recibe una tarea compleja
2. Planifica con write_todos (cápsula 02)
3. Encuentra una subtarea que requiere especialización
4. Crea un subagente con prompt específico y tools relevantes
5. El subagente ejecuta en contexto aislado
6. El subagente retorna su resultado al agente principal
7. El agente principal integra el resultado y continúa

Ejemplo conceptual

Imagina un agente de investigación que debe comparar tres tecnologías. En vez de investigar las tres secuencialmente (lento, contexto creciente), crea tres subagentes:

Agente principal: "Compara Redis, Memcached y DynamoDB para caching en producción"
  │
  ├─ spawn: redis_researcher
  │   └─ Prompt: "Investiga Redis como solución de caching en producción"
  │   └─ Tools: [web_search]
  │   └─ Retorna: "Redis ofrece persistencia, pub/sub, y tipos de datos ricos..."
  │
  ├─ spawn: memcached_researcher
  │   └─ Prompt: "Investiga Memcached como solución de caching en producción"
  │   └─ Tools: [web_search]
  │   └─ Retorna: "Memcached es simple, rápido, optimizado para key-value..."
  │
  └─ spawn: dynamodb_researcher
      └─ Prompt: "Investiga DynamoDB DAX como solución de caching en producción"
      └─ Tools: [web_search]
      └─ Retorna: "DynamoDB DAX ofrece caching integrado con DynamoDB..."

Agente principal: integra los 3 resultados → genera reporte comparativo

Cada subagente solo ve su tarea. No sabe de los otros subagentes. No tiene acceso al historial del agente principal. Esto es context isolation — y es la razón por la que los resultados son mejores: cada subagente tiene un context window dedicado 100% a su subtarea.


Subagent spawning en código

Ejemplo básico

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

web_search = TavilySearchResults(max_results=3)

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="Research Orchestrator",
    instructions=(
        "Eres un investigador senior que delega subtareas a subagentes.\n\n"
        "Para cada tema de investigación:\n"
        "1. Planifica con write_todos\n"
        "2. Para subtareas de búsqueda especializada, crea subagentes:\n"
        "   - Cada subagente recibe UN aspecto específico del tema\n"
        "   - Cada subagente tiene acceso a web_search\n"
        "3. Integra los resultados de los subagentes\n"
        "4. Genera el reporte final en output/report.md"
    ),
)

result = agent.run(
    "Compara las estrategias de seguridad de AWS, GCP y Azure para aplicaciones de IA"
)

print(f"=== Ejecución ===")
print(f"  Subagentes creados: {len(result.subagents_spawned)}")
print(f"  Archivos generados: {len(result.files)}")
print(f"  Todos completados: {sum(1 for t in result.todos if t['status'] == 'completed')}/{len(result.todos)}")

print(f"\n=== Subagentes ===")
for sa in result.subagents_spawned:
    print(f"  {sa['name']}: {sa['prompt'][:80]}...")

if "output/report.md" in result.files:
    print(f"\n=== Reporte: {len(result.files['output/report.md']):,} chars ===")
# Output esperado (varía):
# === Ejecución ===
#   Subagentes creados: 3
#   Archivos generados: 5
#   Todos completados: 5/5
#
# === Subagentes ===
#   aws_security_researcher: Investiga las prácticas de seguridad de AWS para aplicaciones de IA...
#   gcp_security_researcher: Investiga las prácticas de seguridad de GCP para aplicaciones de IA...
#   azure_security_researcher: Investiga las prácticas de seguridad de Azure para aplicaciones de...
#
# === Reporte: 4,523 chars ===

El agente principal decidió crear 3 subagentes — uno por proveedor de cloud. Cada subagente investigó de forma aislada. El agente principal integró los resultados.

La anatomía de un subagente

Cuando el agente principal crea un subagente, define:

# Lo que el agente principal genera internamente:
spawn_subagent(
    name="aws_researcher",                    # Nombre identificador
    prompt="Investiga las prácticas de "      # Instrucciones específicas
           "seguridad de AWS para IA. "
           "Enfócate en IAM, VPC, y "
           "encriptación de datos.",
    tools=["web_search"],                     # Herramientas disponibles
    model="openai:gpt-4.1-mini",             # Modelo (puede diferir del principal)
)

El subagente:

  • ✅ Recibe su prompt como system instructions
  • ✅ Tiene acceso solo a las tools especificadas
  • ✅ Ejecuta en un context window limpio
  • ✅ Retorna su resultado como string al agente principal
  • ❌ No ve el historial del agente principal
  • ❌ No puede acceder a los archivos del agente principal
  • ❌ No puede crear sus propios subagentes (por defecto)

Context isolation: por qué importa

El problema sin aislamiento

Sin context isolation, si el agente principal investigó AWS y luego pasa a GCP, toda la información de AWS está en el context window cuando investiga GCP:

Context del agente al investigar GCP:
  [System prompt]
  [Planning: 5 todos]
  [Resultado de AWS: 3,000 tokens]        ← irrelevante para GCP
  [Resultado de herramientas de AWS]       ← irrelevante para GCP
  [Ahora investigando GCP...]

Total: ~8,000 tokens de input, solo ~2,000 son relevantes

El modelo pierde atención por los datos irrelevantes. Además, pagas por procesar tokens de AWS cuando estás trabajando en GCP.

La solución: context aislado por subagente

Subagente AWS:
  [System prompt: "Investiga seguridad de AWS"]
  [Resultado de web_search sobre AWS]
  Total: ~3,000 tokens, 100% relevantes

Subagente GCP:
  [System prompt: "Investiga seguridad de GCP"]
  [Resultado de web_search sobre GCP]
  Total: ~3,000 tokens, 100% relevantes

Agente principal (al integrar):
  [System prompt]
  [Resultado del subagente AWS: resumen]
  [Resultado del subagente GCP: resumen]
  Total: ~4,000 tokens, todos relevantes

Cada subagente opera con un context window optimizado. El agente principal recibe solo los resúmenes — no los datos crudos.

Impacto medible

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

web_search = TavilySearchResults(max_results=3)

agent_with_spawning = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="With Subagents",
    instructions=(
        "Investiga cada tecnología usando un subagente dedicado. "
        "Cada subagente investiga UNA tecnología. "
        "Integra los resultados al final."
    ),
)

agent_without_spawning = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="Without Subagents",
    instructions=(
        "Investiga cada tecnología secuencialmente tú mismo. "
        "NO crees subagentes. Haz toda la investigación directamente."
    ),
)

task = "Compara PostgreSQL, MongoDB y Redis para un sistema de e-commerce"

result_spawn = agent_with_spawning.run(task)
result_solo = agent_without_spawning.run(task)

print("=== Con subagentes ===")
print(f"  Tokens: {result_spawn.usage.total_tokens:,}")
print(f"  Subagentes: {len(result_spawn.subagents_spawned)}")
print(f"  Output: {len(result_spawn.output):,} chars")

print("\n=== Sin subagentes ===")
print(f"  Tokens: {result_solo.usage.total_tokens:,}")
print(f"  Subagentes: {len(result_solo.subagents_spawned)}")
print(f"  Output: {len(result_solo.output):,} chars")
# Output esperado (varía):
# === Con subagentes ===
#   Tokens: 22,456
#   Subagentes: 3
#   Output: 5,234 chars
#
# === Sin subagentes ===
#   Tokens: 28,901
#   Subagentes: 0
#   Output: 3,891 chars

Menos tokens, mejor output. El context isolation mantiene cada investigación enfocada.


Ejemplo práctico: agente de investigación con delegación

Escenario completo

Un agente que investiga un tema complejo, usando las tres herramientas de este bloque: planning (write_todos), filesystem, y subagent spawning.

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

web_search = TavilySearchResults(max_results=5)

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="Full Research Agent",
    instructions=(
        "Eres un director de investigación. Tu proceso:\n\n"
        "1. PLANIFICA: Usa write_todos para definir los aspectos a investigar\n"
        "2. DELEGA: Para cada aspecto, crea un subagente especializado\n"
        "   - El subagente busca información y retorna un resumen\n"
        "3. ALMACENA: Escribe el resultado de cada subagente en research/[aspecto].md\n"
        "4. SINTETIZA: Lee los archivos de research/, genera analysis/synthesis.md\n"
        "5. REPORTA: Genera output/report.md integrando todo\n\n"
        "Cada subagente debe recibir instrucciones precisas sobre qué buscar. "
        "No delegues tareas vagas como 'investiga IA' — sé específico."
    ),
)

result = agent.run(
    "Analiza el estado del arte de AI agents en producción: "
    "frameworks disponibles, patterns de deployment, y casos de éxito"
)

print("=== Plan ===")
for todo in result.todos:
    icon = {"completed": "✅", "skipped": "⏭️"}.get(todo["status"], "⏳")
    print(f"  {icon} {todo['title']}")

print(f"\n=== Subagentes ({len(result.subagents_spawned)}) ===")
for sa in result.subagents_spawned:
    print(f"  → {sa['name']}")

print(f"\n=== Archivos ({len(result.files)}) ===")
for path in sorted(result.files.keys()):
    print(f"  {path} ({len(result.files[path]):,} chars)")

print(f"\n=== Tokens totales: {result.usage.total_tokens:,} ===")
# Output esperado (varía):
# === Plan ===
#   ✅ Definir dimensiones de análisis
#   ✅ Investigar frameworks de agentes (LangGraph, CrewAI, AutoGen)
#   ✅ Investigar patterns de deployment en producción
#   ✅ Investigar casos de éxito documentados
#   ✅ Sintetizar hallazgos
#   ✅ Generar reporte final
#
# === Subagentes (3) ===
#   → frameworks_researcher
#   → deployment_researcher
#   → case_studies_researcher
#
# === Archivos (5) ===
#   analysis/synthesis.md (3,456 chars)
#   output/report.md (6,789 chars)
#   research/case_studies.md (2,345 chars)
#   research/deployment_patterns.md (2,678 chars)
#   research/frameworks.md (2,890 chars)
#
# === Tokens totales: 35,678 ===

El flujo completo: planning → delegación → almacenamiento → síntesis → reporte. Las tres herramientas (write_todos, filesystem, subagent spawning) trabajan juntas.


Límites y controles

Sin límites, el subagent spawning puede explotar en costos y complejidad. Un agente entusiasta podría crear 20 subagentes para una tarea que necesita 3. Cada subagente consume tokens, y un agente sin restricciones puede multiplicar costos rápidamente.

Max subagentes

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    name="Limited Spawner",
    instructions="Investiga el tema delegando a subagentes.",
    agent_config={
        "max_subagents": 3,        # Máximo 3 subagentes por ejecución
    },
)

result = agent.run(
    "Investiga 6 lenguajes de programación: "
    "Python, Rust, Go, TypeScript, Kotlin, Swift"
)

print(f"Subagentes creados: {len(result.subagents_spawned)}")
for sa in result.subagents_spawned:
    print(f"  {sa['name']}: {sa['prompt'][:60]}...")
# Output esperado (varía):
# Subagentes creados: 3
#   systems_languages: Investiga Rust y Go como lenguajes de sistemas...
#   app_languages: Investiga TypeScript y Kotlin para desarrollo de app...
#   general_languages: Investiga Python y Swift como lenguajes de propósi...

Con un límite de 3 subagentes y 6 lenguajes, el agente agrupa: 2 lenguajes por subagente. El agente se adapta al límite en vez de fallar.

Timeout por subagente

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

web_search = TavilySearchResults(max_results=3)

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="Timeout Demo",
    instructions="Investiga el tema usando subagentes.",
    agent_config={
        "max_subagents": 5,
        "subagent_timeout_seconds": 60,  # Máximo 60 segundos por subagente
    },
)

result = agent.run("Investiga tendencias de cloud computing en 2025")

for sa in result.subagents_spawned:
    status = "✅" if sa.get("completed") else "⏰ timeout"
    print(f"  {sa['name']}: {status} ({sa.get('duration_seconds', 0):.1f}s)")
# Output esperado (varía):
# aws_trends: ✅ (12.3s)
# gcp_trends: ✅ (15.7s)
# azure_trends: ✅ (11.2s)

El timeout previene subagentes que se "atascan" en loops infinitos o búsquedas interminables. Si un subagente excede el timeout, su resultado parcial se retorna (si existe) o se marca como failed.

Validación de resultados

El agente principal puede validar los resultados de subagentes antes de integrarlos:

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    name="Validating Orchestrator",
    instructions=(
        "Cuando delegues a subagentes, valida cada resultado:\n"
        "1. ¿El resultado responde la pregunta que hiciste?\n"
        "2. ¿Tiene datos específicos (no solo generalidades)?\n"
        "3. ¿Es consistente con lo que ya sabes?\n\n"
        "Si un resultado no pasa la validación, re-intenta con "
        "instrucciones más específicas o investiga tú mismo."
    ),
)

result = agent.run("Compara los costos de hosting de 3 plataformas: Vercel, Railway, Fly.io")

print(f"Subagentes: {len(result.subagents_spawned)}")
print(f"Archivos: {list(result.files.keys())}")
# Output esperado (varía):
# Subagentes: 3
# Archivos: ['research/vercel.md', 'research/railway.md', 'research/flyio.md', 'output/comparison.md']

La validación es particularmente importante cuando los subagentes usan herramientas externas (web search, APIs) donde los resultados pueden ser incompletos o irrelevantes.


Comparación: M10 manual vs Deep Agents subagent spawning

Esta es la conexión directa con lo que construiste en el Módulo 10.

M10: tú diseñas el sistema multi-agente

# M10: Supervisor que TÚ diseñaste
from langgraph_supervisor import create_supervisor

search_agent = create_react_agent(
    model, tools=[web_search], name="search_agent",
    prompt="Busca información en la web."
)

analysis_agent = create_react_agent(
    model, tools=[], name="analysis_agent",
    prompt="Analiza datos y genera insights."
)

report_agent = create_react_agent(
    model, tools=[], name="report_agent",
    prompt="Escribe reportes profesionales."
)

supervisor = create_supervisor(
    model=model,
    agents=[search_agent, analysis_agent, report_agent],
    prompt="Coordina la investigación entre los agentes.",
)

app = supervisor.compile()

Aquí, tú decides:

  • ✅ Qué agentes existen (3 específicos)
  • ✅ Qué herramientas tiene cada uno
  • ✅ Cómo se coordinan (supervisor)
  • ✅ Cuándo se crea cada agente (build time)

Deep Agents: el agente diseña el sistema

# M11: El agente decide qué subagentes crear
from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[TavilySearchResults(max_results=3)],
    name="Self-Organizing Researcher",
    instructions=(
        "Investiga el tema. Crea subagentes especializados cuando "
        "una subtarea requiera enfoque dedicado."
    ),
)

result = agent.run("Investiga el estado de AI agents en producción")

Aquí, el agente decide:

  • ✅ Cuántos subagentes crear (runtime)
  • ✅ Qué tarea asignar a cada uno (runtime)
  • ✅ Cuándo delegar vs investigar directamente (runtime)

Tabla de trade-offs

CriterioM10 (Manual)M11 (Spawning)
Quién diseña el equipoTú, en build timeEl agente, en runtime
PredictibilidadAlta (sabes qué agentes existen)Baja (varía por ejecución)
AdaptabilidadBaja (equipo fijo)Alta (equipo dinámico)
ControlTotal (defines todo)Parcial (defines límites, no detalles)
DebuggingMás fácil (flujo conocido)Más difícil (equipo varía)
CostoPredecible (N agentes fijos)Variable (depende de cuántos crea)
CódigoMás (definir cada agente)Menos (instrucciones + límites)
Flexibilidad ante tareas diversasBaja (equipo diseñado para una tarea)Alta (equipo se adapta a la tarea)

Cuándo usar cada uno

Usa M10 manual cuando:

  • ✅ Sabes exactamente qué roles necesitas
  • ✅ Las tareas son predecibles y repetitivas
  • ✅ Necesitas garantías sobre qué agente hace qué
  • ✅ Debugging y reproducibilidad son prioridad

Usa subagent spawning cuando:

  • ✅ Las tareas son diversas y no puedes predecir los roles necesarios
  • ✅ La flexibilidad es más importante que la predictibilidad
  • ✅ Quieres un prototipo rápido sin diseñar la arquitectura multi-agente
  • ✅ El agente necesita adaptarse a lo que descubre durante la ejecución

Cuándo el spawning es overkill

No todas las subtareas necesitan un subagente. El overhead de crear un subagente incluye:

  1. Una llamada extra al LLM para que el subagente procese su tarea
  2. Latencia de setup del subagente
  3. Complejidad de integrar el resultado

Regla de decisión

¿La subtarea requiere más de 2-3 tool calls?
  └─ SÍ → subagente (le das context aislado para que trabaje enfocado)
  └─ NO → el agente principal la hace directamente

¿La subtarea es independiente del resto del contexto?
  └─ SÍ → subagente (no necesita ver el historial completo)
  └─ NO → agente principal (necesita el contexto acumulado)

¿Hay múltiples subtareas paralelas del mismo tipo?
  └─ SÍ → subagentes (uno por subtarea, paralelismo potencial)
  └─ NO → agente principal (más simple, menos overhead)

Ejemplo: no uses subagentes para esto

# OVERKILL: crear un subagente para una pregunta simple
agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    instructions="Para CADA pregunta, crea un subagente que la responda.",
)
result = agent.run("¿Cuál es la capital de Francia?")
# El agente crea un subagente para responder "París"
# Overhead: ~2x tokens, ~2x latencia, para un resultado trivial
# CORRECTO: el agente principal responde directamente
agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    instructions=(
        "Responde preguntas directamente cuando sean simples. "
        "Crea subagentes solo cuando la tarea requiera investigación "
        "especializada de múltiples pasos."
    ),
)
result = agent.run("¿Cuál es la capital de Francia?")
# Respuesta directa, sin overhead

La regla: si puedes responder en 1-2 pasos, no delegues. Delega cuando la subtarea requiere enfoque sostenido.


Subagentes recursivos: agentes que crean agentes

Por defecto, los subagentes no pueden crear sus propios subagentes. Esto es intencional — previene explosión de costos y complejidad.

Pero en casos avanzados, puedes habilitarlo con un límite de profundidad:

from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    name="Recursive Orchestrator",
    instructions=(
        "Investiga el tema. Puedes crear subagentes. "
        "Los subagentes pueden crear sub-subagentes si la tarea lo requiere."
    ),
    agent_config={
        "max_subagents": 5,
        "max_spawn_depth": 2,  # Principal → subagente → sub-subagente (máximo)
    },
)

result = agent.run(
    "Genera un análisis completo del ecosistema de AI engineering: "
    "frameworks, infraestructura, y prácticas de equipo"
)

print(f"Subagentes nivel 1: {len(result.subagents_spawned)}")
for sa in result.subagents_spawned:
    nested = sa.get("subagents_spawned", [])
    print(f"  {sa['name']}{len(nested)} sub-subagentes")
# Output esperado (varía):
# Subagentes nivel 1: 3
#   frameworks_researcher → 2 sub-subagentes
#   infra_researcher → 1 sub-subagentes
#   team_practices_researcher → 0 sub-subagentes

Usa max_spawn_depth con cautela. Cada nivel multiplica tokens y latencia. Para la mayoría de casos, profundidad 1 (solo el principal crea subagentes) es suficiente.


Troubleshooting

Problema 1: El agente crea demasiados subagentes

Síntoma: Para una tarea moderada, el agente crea 8-10 subagentes cuando 3 serían suficientes. Causa: Las instrucciones dicen "delega subtareas" sin definir cuándo es apropiado delegar. Solución: Define criterios de delegación:

instructions = (
    "Crea subagentes SOLO cuando:\n"
    "- La subtarea requiere más de 3 búsquedas\n"
    "- La subtarea es independiente del resto\n"
    "- Hay 2+ subtareas paralelas del mismo tipo\n\n"
    "Para todo lo demás, trabaja directamente tú."
)

Problema 2: Los resultados de subagentes son demasiado vagos

Síntoma: El subagente retorna "Investigué el tema y encontré información relevante" sin datos concretos. Causa: El prompt del subagente no especifica el formato de output esperado. Solución: Instruye al agente principal sobre cómo definir subagentes:

instructions = (
    "Cuando crees un subagente, incluye en su prompt:\n"
    "1. Qué buscar específicamente\n"
    "2. Formato de output esperado (datos, comparación, lista, etc.)\n"
    "3. Qué información es obligatoria en la respuesta\n\n"
    "Ejemplo: 'Busca el pricing de Vercel. Retorna: nombre del plan, precio mensual, "
    "límites principales. Formato: tabla markdown.'"
)

Problema 3: Subagentes duplican trabajo

Síntoma: Dos subagentes investigan el mismo tema porque sus prompts se solapan. Causa: El agente principal no definió boundaries claros entre subagentes. Solución:

instructions = (
    "Antes de crear subagentes, define explícitamente el SCOPE de cada uno:\n"
    "- ¿Qué aspectos cubre este subagente?\n"
    "- ¿Qué aspectos NO cubre (los cubre otro subagente)?\n"
    "Los scopes no deben solaparse."
)

Problema 4: El agente no integra bien los resultados

Síntoma: Los resultados de 3 subagentes se juntan como una concatenación, sin análisis cruzado ni síntesis real. Causa: Las instrucciones no distinguen entre "juntar resultados" y "sintetizar resultados." Solución:

instructions = (
    "Después de recibir los resultados de todos los subagentes:\n"
    "1. Lee cada resultado\n"
    "2. Identifica puntos en común y contradicciones\n"
    "3. Genera una síntesis que COMPARE y CONTRASTE, no solo concatene\n"
    "4. Incluye tu propia evaluación de los hallazgos"
)

Problema 5: Timeout en subagentes con muchas búsquedas

Síntoma: Un subagente falla por timeout porque intenta hacer 10 búsquedas web. Causa: El timeout es demasiado bajo para la cantidad de trabajo asignada, o la tarea asignada es demasiado amplia. Solución: Divide la tarea o ajusta el timeout:

agent_config = {
    "subagent_timeout_seconds": 120,  # Más tiempo si la tarea lo requiere
}

# O instruye al agente a dar tareas más específicas:
instructions = (
    "Asigna tareas ESPECÍFICAS a cada subagente. "
    "'Investiga IA' es demasiado amplio. "
    "'Busca los 3 papers más citados sobre RAG en 2025' es específico."
)

Ejercicios

Ejercicio 1: Subagente único (Fácil)

Crea un agente que delegue UNA subtarea a un subagente e integre el resultado. Verifica que el subagente se creó y que su resultado se usó.

Ver solución
from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent

agent = create_deep_agent(
    "openai:gpt-4.1-mini",
    tools=[],
    name="Single Delegation",
    instructions=(
        "Cuando recibas una tarea de análisis:\n"
        "1. Identifica el aspecto más técnico\n"
        "2. Delégalo a un subagente especializado\n"
        "3. Usa el resultado del subagente en tu respuesta final"
    ),
)

result = agent.run(
    "Analiza si Python es buena opción para backend: "
    "rendimiento, ecosistema, y facilidad de contratación"
)

print(f"Subagentes: {len(result.subagents_spawned)}")
if result.subagents_spawned:
    sa = result.subagents_spawned[0]
    print(f"  Nombre: {sa['name']}")
    print(f"  Prompt: {sa['prompt'][:100]}...")
print(f"\nOutput final: {len(result.output)} chars")
print(result.output[:200])
# Output esperado (varía):
# Subagentes: 1
#   Nombre: performance_analyst
#   Prompt: Analiza el rendimiento de Python para backend comparado con Go y Node.js...
#
# Output final: 2345 chars
# Python es una opción sólida para backend...

Explicación: El agente identificó que "rendimiento" es el aspecto más técnico y lo delegó a un subagente especializado. Los otros aspectos (ecosistema, contratación) los manejó directamente.

Ejercicio 2: Múltiples subagentes en paralelo (Fácil)

Crea un agente que investigue 3 tecnologías en paralelo, cada una con su propio subagente. Compara los tiempos.

Ver solución
from dotenv import load_dotenv
load_dotenv()

import time
from deep_agents import create_deep_agent

agent = create_deep_agent(
    "openai:gpt-4.1-mini",
    tools=[],
    name="Parallel Researcher",
    instructions=(
        "Investiga las 3 tecnologías mencionadas. "
        "Crea un subagente para CADA tecnología — investiga en paralelo. "
        "Integra los resultados en una comparación final."
    ),
    agent_config={"max_subagents": 3},
)

start = time.time()
result = agent.run("Compara FastAPI, Express.js y Gin para APIs REST")
elapsed = time.time() - start

print(f"Tiempo total: {elapsed:.1f}s")
print(f"Subagentes: {len(result.subagents_spawned)}")
for sa in result.subagents_spawned:
    duration = sa.get("duration_seconds", 0)
    print(f"  {sa['name']}: {duration:.1f}s")
print(f"\nOutput: {len(result.output):,} chars")
# Output esperado (varía):
# Tiempo total: 18.3s
# Subagentes: 3
#   fastapi_expert: 8.2s
#   express_expert: 7.5s
#   gin_expert: 9.1s
#
# Output: 3,456 chars

Explicación: Los 3 subagentes pueden ejecutarse en paralelo (dependiendo de la implementación de Deep Agents). El tiempo total es cercano al del subagente más lento, no a la suma de los tres.

Ejercicio 3: Subagentes con herramientas (Medio)

Crea un agente que delegue búsquedas web a subagentes. Cada subagente tiene TavilySearchResults y busca sobre un aspecto diferente.

Ver solución
from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

web_search = TavilySearchResults(max_results=3)

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="Web Research Orchestrator",
    instructions=(
        "Para el tema de investigación:\n"
        "1. Identifica 3 aspectos clave\n"
        "2. Crea un subagente para cada aspecto con acceso a web_search\n"
        "3. Cada subagente debe retornar: hallazgos clave, fuentes, y datos específicos\n"
        "4. Integra los resultados en output/report.md\n"
        "5. Escribe el resultado de cada subagente en research/[aspecto].md"
    ),
    agent_config={"max_subagents": 3},
)

result = agent.run("Investiga el estado de AI coding assistants en 2025")

print(f"=== Resultado ===")
print(f"Subagentes: {len(result.subagents_spawned)}")
print(f"Archivos: {len(result.files)}")
for path in sorted(result.files.keys()):
    print(f"  {path} ({len(result.files[path]):,} chars)")
# Output esperado (varía):
# === Resultado ===
# Subagentes: 3
# Archivos: 4
#   output/report.md (5,123 chars)
#   research/market_landscape.md (2,345 chars)
#   research/technical_capabilities.md (2,567 chars)
#   research/user_adoption.md (1,890 chars)

Explicación: Cada subagente usó web_search de forma independiente en su context aislado. Los resultados se almacenaron en archivos (filesystem de cápsula 03) y se integraron en un reporte final. Las tres herramientas del módulo trabajando juntas.

Ejercicio 4: Controlar el número de subagentes (Medio)

Configura un agente con max_subagents: 2 y dale una tarea que naturalmente pediría 4+ subagentes. Observa cómo se adapta.

Ver solución
from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent

agent = create_deep_agent(
    "openai:gpt-4.1-mini",
    tools=[],
    name="Constrained Orchestrator",
    instructions=(
        "Investiga TODOS los temas mencionados. "
        "Usa subagentes cuando necesites especialización. "
        "Si alcanzas el límite de subagentes, agrupa temas relacionados "
        "o investiga los restantes tú mismo."
    ),
    agent_config={"max_subagents": 2},
)

result = agent.run(
    "Compara 5 bases de datos: PostgreSQL, MySQL, MongoDB, Redis, Cassandra"
)

print(f"Subagentes creados: {len(result.subagents_spawned)} (límite: 2)")
for sa in result.subagents_spawned:
    print(f"  {sa['name']}: {sa['prompt'][:80]}...")

print(f"\nOutput: {len(result.output):,} chars")
# Output esperado (varía):
# Subagentes creados: 2 (límite: 2)
#   relational_db_expert: Compara PostgreSQL y MySQL: rendimiento, features, ecosistema...
#   nosql_db_expert: Compara MongoDB, Redis y Cassandra: modelos de datos, escalabilidad...
#
# Output: 4,567 chars

Explicación: Con un límite de 2, el agente agrupó: SQL (PostgreSQL + MySQL) en un subagente y NoSQL (MongoDB + Redis + Cassandra) en otro. Los límites fuerzan al agente a ser creativo con la organización, no a fallar.

Ejercicio 5: Pipeline completo: planning + filesystem + spawning (Avanzado)

Crea un agente que use las tres herramientas del módulo para una tarea compleja. Imprime un reporte de ejecución que muestre el plan, los subagentes, y los archivos.

Ver solución
from dotenv import load_dotenv
load_dotenv()

from deep_agents import create_deep_agent
from langchain_community.tools import TavilySearchResults

web_search = TavilySearchResults(max_results=3)

agent = create_deep_agent(
    "openai:gpt-4.1",
    tools=[web_search],
    name="Full Pipeline Agent",
    instructions=(
        "Eres un director de investigación. Pipeline obligatorio:\n\n"
        "FASE 1 - PLANNING:\n"
        "  Usa write_todos para crear un plan de 5-7 pasos\n\n"
        "FASE 2 - INVESTIGACIÓN:\n"
        "  Para cada paso de investigación, crea un subagente con web_search\n"
        "  Escribe el resultado de cada subagente en research/[tema].md\n\n"
        "FASE 3 - ANÁLISIS:\n"
        "  Lee los archivos de research/\n"
        "  Genera analysis/synthesis.md con comparación cruzada\n\n"
        "FASE 4 - OUTPUT:\n"
        "  Genera output/report.md integrando todo\n"
        "  Actualiza todos los todos como completed"
    ),
    agent_config={"max_subagents": 4},
)

result = agent.run(
    "Analiza el mercado de AI infrastructure: "
    "proveedores de GPU cloud, frameworks de training, y plataformas de deployment"
)

print("╔══════════════════════════════════════════════╗")
print("║         REPORTE DE EJECUCIÓN                ║")
print("╠══════════════════════════════════════════════╣")

print("║ PLAN:")
for todo in result.todos:
    icon = {"completed": "✅", "skipped": "⏭️"}.get(todo["status"], "⏳")
    print(f"║   {icon} {todo['title']}")

print("║")
print(f"║ SUBAGENTES ({len(result.subagents_spawned)}):")
for sa in result.subagents_spawned:
    print(f"║   → {sa['name']}")

print("║")
print(f"║ ARCHIVOS ({len(result.files)}):")
for path in sorted(result.files.keys()):
    size = len(result.files[path])
    print(f"║   {path} ({size:,} chars)")

print("║")
print(f"║ TOKENS: {result.usage.total_tokens:,}")
print(f"║ COSTO ESTIMADO: ${result.usage.total_tokens * 0.00001:.4f}")
print("╚══════════════════════════════════════════════╝")
# Output esperado (varía):
# ╔══════════════════════════════════════════════╗
# ║         REPORTE DE EJECUCIÓN                ║
# ╠══════════════════════════════════════════════╣
# ║ PLAN:
# ║   ✅ Definir dimensiones del mercado de AI infrastructure
# ║   ✅ Investigar proveedores de GPU cloud
# ║   ✅ Investigar frameworks de training
# ║   ✅ Investigar plataformas de deployment
# ║   ✅ Análisis cruzado de hallazgos
# ║   ✅ Generar reporte final
# ║
# ║ SUBAGENTES (3):
# ║   → gpu_cloud_researcher
# ║   → training_frameworks_researcher
# ║   → deployment_platforms_researcher
# ║
# ║ ARCHIVOS (5):
# ║   analysis/synthesis.md (3,456 chars)
# ║   output/report.md (6,789 chars)
# ║   research/deployment_platforms.md (2,345 chars)
# ║   research/gpu_cloud.md (2,678 chars)
# ║   research/training_frameworks.md (2,890 chars)
# ║
# ║ TOKENS: 42,345
# ║ COSTO ESTIMADO: $0.4235
# ╚══════════════════════════════════════════════╝

Explicación: El pipeline completo usa las tres herramientas: write_todos para planificar, subagent spawning para investigar en paralelo con context aislado, y filesystem para almacenar resultados y mantener el context window lean. Este es el patrón que reimplementarás como proyecto en la cápsula 08.

Ejercicio 6: Comparación side-by-side: M10 vs M11 (Avanzado)

Para la misma tarea, compara el resultado de un sistema multi-agente manual (estilo M10, simulado con funciones) vs un Deep Agent con subagent spawning. Mide tokens, tiempo, y longitud del output.

Ver solución
from dotenv import load_dotenv
load_dotenv()

import time
from deep_agents import create_deep_agent

agent_m11 = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    name="M11 Deep Agent",
    instructions=(
        "Investiga el tema usando subagentes especializados. "
        "Crea un subagente para cada aspecto. "
        "Integra los resultados en un reporte."
    ),
    agent_config={"max_subagents": 3},
)

agent_m10_style = create_deep_agent(
    "openai:gpt-4.1",
    tools=[],
    name="M10 Style (Sequential)",
    instructions=(
        "Investiga el tema secuencialmente. "
        "NO uses subagentes. "
        "Investiga cada aspecto tú mismo, uno tras otro. "
        "Genera un reporte al final."
    ),
)

task = "Compara Docker, Kubernetes y serverless para deployar aplicaciones de IA"

start_m11 = time.time()
result_m11 = agent_m11.run(task)
time_m11 = time.time() - start_m11

start_m10 = time.time()
result_m10 = agent_m10_style.run(task)
time_m10 = time.time() - start_m10

print("=== Comparación M10 vs M11 ===")
print(f"\n{'Métrica':<25} {'M10 (secuencial)':<20} {'M11 (subagentes)'}")
print("-" * 65)
print(f"{'Tiempo (s)':<25} {time_m10:<20.1f} {time_m11:.1f}")
print(f"{'Tokens totales':<25} {result_m10.usage.total_tokens:<20,} {result_m11.usage.total_tokens:,}")
print(f"{'Output (chars)':<25} {len(result_m10.output):<20,} {len(result_m11.output):,}")
print(f"{'Subagentes':<25} {len(result_m10.subagents_spawned):<20} {len(result_m11.subagents_spawned)}")
print(f"{'Archivos':<25} {len(result_m10.files):<20} {len(result_m11.files)}")
# Output esperado (varía):
# === Comparación M10 vs M11 ===
#
# Métrica                   M10 (secuencial)     M11 (subagentes)
# -----------------------------------------------------------------
# Tiempo (s)                32.4                 21.7
# Tokens totales            28,901               24,567
# Output (chars)            3,456                5,123
# Subagentes                0                    3
# Archivos                  1                    4

Explicación: M11 con subagentes tiende a ser más rápido (paralelismo) y a producir output más largo (context isolation = mejor focus). Pero el resultado M10 puede ser más coherente (un solo context = más consistencia interna). El trade-off es: velocidad y profundidad (M11) vs coherencia y control (M10).


Resumen

  • Subagent spawning permite al agente crear subagentes especializados on-demand. A diferencia del M10 donde tú diseñaste el equipo multi-agente, aquí el agente decide qué subagentes crear en runtime según lo que la tarea requiere
  • Context isolation es el beneficio principal: cada subagente tiene un context window dedicado 100% a su subtarea, sin ruido de otras investigaciones. Esto mejora calidad y reduce tokens
  • Los controles son esenciales: max_subagents para limitar costos, timeout para prevenir subagentes atascados, validación para verificar que los resultados son útiles
  • La comparación con M10 es directa: en M10 diseñas el equipo en build time con control total; con spawning, el agente forma su equipo en runtime con más flexibilidad pero menos predictibilidad
  • No todo necesita subagentes: tareas simples (1-2 pasos) son más eficientes sin delegación. Usa subagentes cuando la subtarea requiere enfoque sostenido, múltiples tool calls, o hay paralelismo natural
  • Las tres herramientas del módulo se complementan: write_todos planifica qué hacer, filesystem almacena los resultados, subagent spawning ejecuta subtareas con enfoque. Juntas, habilitan agentes autónomos capaces de investigaciones complejas

Recursos adicionales

  1. Deep Agents — Subagent Spawning — Documentación oficial de subagent spawning, configuración, y ejemplos
  2. LangGraph — Multi-Agent Architectures — Los patrones multi-agente manuales que el spawning abstrae
  3. Voyager: An Open-Ended Embodied Agent with LLMs — Paper sobre agentes que crean subprogramas especializados, inspiración para subagent spawning
  4. AutoGen — Multi-Agent Conversation Framework — Framework de Microsoft para multi-agente; útil para comparar enfoques de delegación
  5. The AI Scientist — Automated Research — Paper sobre agentes de investigación autónomos que usan delegación y planning
  6. Cost Management for AI Agents — Best Practices — Guía sobre control de costos en sistemas multi-agente, directamente relevante para límites de spawning

Módulo 11 — LangChain & LangGraph: From Chains to Agents

Siguiente cápsula: Long-term Memory — aprenderás cómo configurar backends de memoria persistente para que tu agente recuerde información entre sesiones, con filesystem backend, LangGraph Store, y composite backends.