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

Sotto-agenti

Pianificazione & Coordinamento

Clean Context Per Subtask

151 LOC5 strumentiSubagent 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

"Dividi i task grandi; ogni subtask ottiene un contesto pulito" -- i sotto-agenti usano messages[] indipendenti, mantenendo pulita la conversazione principale.

Problema

Mentre l'agente lavora, il suo array di messaggi cresce. Ogni file letto, ogni output bash rimane nel contesto permanentemente. "Quale framework di testing usa questo progetto?" potrebbe richiedere la lettura di 5 file, ma il genitore ha solo bisogno della risposta: "pytest."

Soluzione

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.

Come Funziona

  1. Il genitore ottiene uno strumento task. Il figlio ottiene tutti gli strumenti base eccetto task (nessuno spawn ricorsivo).
PARENT_TOOLS = CHILD_TOOLS + [
    {"name": "task",
     "description": "Spawn a subagent with fresh context.",
     "input_schema": {
         "type": "object",
         "properties": {"prompt": {"type": "string"}},
         "required": ["prompt"],
     }},
]
  1. Il sotto-agente inizia con messages=[] ed esegue il suo proprio loop. Solo il testo finale ritorna al genitore.
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)"

L'intera storia dei messaggi del figlio (possibilmente 30+ chiamate strumento) viene scartata. Il genitore riceve un riassunto di un paragrafo come normale tool_result.

Cosa è Cambiato da s03

ComponentePrima (s03)Dopo (s04)
Strumenti55 (base) + task (parent)
ContestoSingolo condivisoIsolamento Parent + child
Sotto-agenteNessunoFunzione run_subagent()
Valore ritornoN/DSolo testo riassunto

Provalo

python agents/s04_subagent.py
  1. Usa un subtask per trovare quale framework di testing usa questo progetto
  2. Delega: leggi tutti i file .py e riassumi cosa fa ciascuno
  3. Usa un task per creare un nuovo modulo, poi verificalo da qui