Learn Claude Code
s04

Subagents

Planning & Coordination

Clean Context Per Subtask

154 LOC5 toolsSubagent spawn with isolated messages[]
Overview

大任务比如把 7 种耐心资本测算口径都跑一遍并行回归对比,一个会话连着跑会把工作内存撑爆。Claude Code 让主会话派几个"子会话"各自独立处理一种口径。子会话跑完只把一段总结回传,中间产生的几万字过程数据不进主会话。

Running example
Research project
耐心资本对企业 ESG 表现的实证项目 do10 稳健性表 10A
What happens in this section

要把 A2 主测度、A1 经典版、B2 中位数门槛、C 熵值法、仅股权侧 Stequity、仅 Bank(A2 债权侧)、仅 Rdebt(A1 债权侧)共 7 种 PC 测度并行跑 firm+year FE 基准回归,主会话只接每个口径的 β、SE、obs 与显著性结论,合成 table10A_pc_swap.csv。

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

"Break big tasks down; each subtask gets a clean context" -- subagents use independent messages[], keeping the main conversation clean.

Harness layer: Context isolation -- protecting the model's clarity of thought.

Problem

As the agent works, its messages array grows. Every file read, every bash output stays in context permanently. "What testing framework does this project use?" might require reading 5 files, but the parent only needs the answer: "pytest."

Solution

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.

How It Works

  1. The parent gets a task tool. The child gets all base tools except task (no recursive spawning).
PARENT_TOOLS = CHILD_TOOLS + [
    {"name": "task",
     "description": "Spawn a subagent with fresh context.",
     "input_schema": {
         "type": "object",
         "properties": {"prompt": {"type": "string"}},
         "required": ["prompt"],
     }},
]
  1. The subagent starts with messages=[] and runs its own loop. Only the final text returns to the parent.
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)"

The child's entire message history (possibly 30+ tool calls) is discarded. The parent receives a one-paragraph summary as a normal tool_result.

What Changed From s03

ComponentBefore (s03)After (s04)
Tools55 (base) + task (parent)
ContextSingle sharedParent + child isolation
SubagentNonerun_subagent() function
Return valueN/ASummary text only

Try It

cd claude-code-for-researchers
python agents/s04_subagent.py
  1. Spawn one subagent per PC measure (A1/A2/A3/A4/B1/B2/C/D); each runs the baseline reghdfe and returns β, t, obs
  2. Delegate: read every paper under 01_文献/A_主流框架(股权+债权)/ and summarize each in one sentence
  3. Use a subagent to construct PC_A2 from raw CSMAR fields and report the resulting field summary