How to Build an AI Agent
How to Build an AI Agent
s04

Sub-agentes

Planejamento e Coordenacao

Clean Context Per Subtask

151 LOC5 ferramentasSubagent spawn with isolated messages[]
Subagents use independent messages[], keeping the main conversation clean

s01 > s02 > s03 > [ s04 ] s05 > s06 | s07 > s08 > s09 > s10 > s11 > s12

"Divida tarefas grandes; cada subtarefa recebe um contexto limpo" -- subagentes usam messages[] independentes, mantendo a conversa principal limpa.

Problema

À medida que o agente trabalha, seu array de mensagens cresce. Cada arquivo lido, cada saída do bash permanece no contexto permanentemente. "Qual framework de testes este projeto usa?" pode exigir a leitura de 5 arquivos, mas o pai só precisa da resposta: "pytest."

Solução

Parent agent                     Subagent
+------------------+             +------------------+
| messages=[...]   |             | messages=[]      | <-- fresh
|                  |  dispatch   |                  |
| tool: task       | ----------> | while tool_use:  |
|   prompt="..."   |             |   call tools     |
|                  |  summary    |   append results |
|   result = "..." | <---------- | return last text |
+------------------+             +------------------+

Parent context stays clean. Subagent context is discarded.

Como Funciona

  1. O pai recebe uma ferramenta task. O filho recebe todas as ferramentas base exceto task (sem spawn recursivo).
PARENT_TOOLS = CHILD_TOOLS + [
    {"name": "task",
     "description": "Spawn a subagent with fresh context.",
     "input_schema": {
         "type": "object",
         "properties": {"prompt": {"type": "string"}},
         "required": ["prompt"],
     }},
]
  1. O subagente começa com messages=[] e executa seu próprio loop. Apenas o texto final retorna ao pai.
def run_subagent(prompt: str) -> str:
    sub_messages = [{"role": "user", "content": prompt}]
    for _ in range(30):  # safety limit
        response = client.messages.create(
            model=MODEL, system=SUBAGENT_SYSTEM,
            messages=sub_messages,
            tools=CHILD_TOOLS, max_tokens=8000,
        )
        sub_messages.append({"role": "assistant",
                             "content": response.content})
        if response.stop_reason != "tool_use":
            break
        results = []
        for block in response.content:
            if block.type == "tool_use":
                handler = TOOL_HANDLERS.get(block.name)
                output = handler(**block.input)
                results.append({"type": "tool_result",
                    "tool_use_id": block.id,
                    "content": str(output)[:50000]})
        sub_messages.append({"role": "user", "content": results})
    return "".join(
        b.text for b in response.content if hasattr(b, "text")
    ) or "(no summary)"

Todo o histórico de mensagens da criança (possivelmente 30+ chamadas de ferramenta) é descartado. O pai recebe um resumo de um parágrafo como um tool_result normal.

O Que Mudou Desde s03

ComponenteAntes (s03)Depois (s04)
Ferramentas55 (base) + task (parent)
ContextoÚnico compartilhadoIsolamento pai + filho
SubagenteNenhumrun_subagent() função
Valor de retornoN/AApenas texto de resumo

Experimente

python agents/s04_subagent.py
  1. Use uma subtarefa para descobrir qual framework de testes este projeto usa
  2. Delegate: leia todos os arquivos .py e resuma o que cada um faz
  3. Use uma task para criar um novo módulo, depois verifique-o a partir daqui