Subagents
Planning & CoordinationClean Context Per Subtask
大任务比如把 7 种耐心资本测算口径都跑一遍并行回归对比,一个会话连着跑会把工作内存撑爆。Claude Code 让主会话派几个"子会话"各自独立处理一种口径。子会话跑完只把一段总结回传,中间产生的几万字过程数据不进主会话。
要把 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
- The parent gets a
tasktool. The child gets all base tools excepttask(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"],
}},
]
- 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
| Component | Before (s03) | After (s04) |
|---|---|---|
| Tools | 5 | 5 (base) + task (parent) |
| Context | Single shared | Parent + child isolation |
| Subagent | None | run_subagent() function |
| Return value | N/A | Summary text only |
Try It
cd claude-code-for-researchers
python agents/s04_subagent.py
Spawn one subagent per PC measure (A1/A2/A3/A4/B1/B2/C/D); each runs the baseline reghdfe and returns β, t, obsDelegate: read every paper under 01_文献/A_主流框架(股权+债权)/ and summarize each in one sentenceUse a subagent to construct PC_A2 from raw CSMAR fields and report the resulting field summary