You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
claude-code/docs/en/s04-subagent.md

102 lines
4.1 KiB

# s04: Subagents
`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 one word: "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 agent has a `task` tool. The subagent gets all base tools except `task` (no recursive spawning).
```java
// Parent Agent: has base tools + SubagentTool
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem("You are a coding agent. "
+ "Use the task tool to delegate subtasks.")
.defaultTools(
new BashTool(),
new ReadFileTool(),
new WriteFileTool(),
new EditFileTool(),
new SubagentTool(chatModel) // Parent Agent exclusive
)
.build();
```
2. The subagent starts with a brand new `ChatClient` and an independent context. Only the final text returns to the parent.
```java
@Tool(description = "Spawn a subagent with fresh context. "
+ "Use for exploration or subtasks that might pollute the main context.")
public String task(
@ToolParam(description = "The task prompt") String prompt,
@ToolParam(description = "Short description", required = false)
String description) {
// Create a brand new ChatClient -- this IS "context isolation"
ChatClient subClient = ChatClient.builder(chatModel)
.defaultSystem("You are a coding subagent. "
+ "Complete the task, then summarize findings.")
.defaultTools( // Base tools, no task (prevents recursion)
new BashTool(),
new ReadFileTool(),
new WriteFileTool(),
new EditFileTool()
)
.build();
String result = subClient.prompt()
.user(prompt)
.call()
.content();
// Only the final text is returned; subagent context is discarded
return (result != null) ? result : "(no summary)";
}
```
The subagent may have run multiple tool calls, but its entire message history is discarded. The parent receives only a summary text, returned as a normal `tool_result`. Spring AI's `ChatClient.call()` manages the tool loop internally -- no need to manually limit iteration count.
## What Changed From s03
| Component | Before (s03) | After (s04) |
|----------------|------------------|---------------------------------------|
| Tools | 5 | 5 (base) + SubagentTool (parent only) |
| Context | Single shared | Parent + child isolation (independent ChatClient) |
| Subagent | None | `SubagentTool.task()` method |
| Return value | N/A | Summary text only |
## Try It
```sh
cd learn-claude-code
mvn exec:java -Dexec.mainClass=io.mybatis.learn.s04.S04Subagent
```
Try these prompts (English prompts work better with LLMs, but Chinese also works):
1. `Use a subtask to find what testing framework this project uses`
2. `Delegate: read all .java files and summarize what each one does`
3. `Use a task to create a new module, then verify it from here`