mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-03-22 02:15:42 +08:00
- 11 sessions from basic agent loop to autonomous teams - Python MVP implementations for each session - Mental-model-first docs in en/zh/ja - Interactive web platform with step-through visualizations - Incremental architecture: each session adds one mechanism
145 lines
5.5 KiB
Markdown
145 lines
5.5 KiB
Markdown
# s04: Subagent (子智能体)
|
|
|
|
> 子智能体使用全新的消息列表运行, 与父智能体共享文件系统, 仅返回摘要 -- 保持父上下文的整洁。
|
|
|
|
## 问题
|
|
|
|
随着智能体工作, 它的消息数组不断增长。每次工具调用、每次文件读取、每次 bash 输出都在累积。20-30 次工具调用后, 上下文窗口充满了无关的历史。为了回答一个简单问题而读取的 500 行文件, 会永久占据上下文中的 500 行空间。
|
|
|
|
这对探索性任务尤其糟糕。"这个项目用了什么测试框架?" 可能需要读取 5 个文件, 但父智能体的历史中并不需要这 5 个文件的全部内容 -- 它只需要答案: "pytest, 使用 conftest.py 配置。"
|
|
|
|
解决方案是进程隔离: 以 `messages=[]` 启动一个子智能体。子智能体进行探索、读取文件、运行命令。完成后, 只有最终的文本响应返回给父智能体。子智能体的全部消息历史被丢弃。
|
|
|
|
## 解决方案
|
|
|
|
```
|
|
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.
|
|
```
|
|
|
|
## 工作原理
|
|
|
|
1. 父智能体拥有一个 `task` 工具用于触发子智能体的生成。子智能体获得除 `task` 外的所有基础工具 (不允许递归生成)。
|
|
|
|
```python
|
|
PARENT_TOOLS = CHILD_TOOLS + [
|
|
{"name": "task",
|
|
"description": "Spawn a subagent with fresh context.",
|
|
"input_schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"prompt": {"type": "string"},
|
|
"description": {"type": "string"},
|
|
},
|
|
"required": ["prompt"],
|
|
}},
|
|
]
|
|
```
|
|
|
|
2. 子智能体以全新的消息列表启动, 仅包含委派的 prompt。它共享相同的文件系统。
|
|
|
|
```python
|
|
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
|
|
# execute tools, append results...
|
|
```
|
|
|
|
3. 只有最终文本返回给父智能体。子智能体 30+ 次工具调用的历史被丢弃。
|
|
|
|
```python
|
|
return "".join(
|
|
b.text for b in response.content if hasattr(b, "text")
|
|
) or "(no summary)"
|
|
```
|
|
|
|
4. 父智能体将此摘要作为普通的 tool_result 接收。
|
|
|
|
```python
|
|
if block.name == "task":
|
|
output = run_subagent(block.input["prompt"])
|
|
results.append({
|
|
"type": "tool_result",
|
|
"tool_use_id": block.id,
|
|
"content": str(output),
|
|
})
|
|
```
|
|
|
|
## 核心代码
|
|
|
|
子智能体函数 (来自 `agents/s04_subagent.py`, 第 110-128 行):
|
|
|
|
```python
|
|
def run_subagent(prompt: str) -> str:
|
|
sub_messages = [{"role": "user", "content": prompt}]
|
|
for _ in range(30):
|
|
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)"
|
|
```
|
|
|
|
## 相对 s03 的变更
|
|
|
|
| 组件 | 之前 (s03) | 之后 (s04) |
|
|
|----------------|------------------|---------------------------|
|
|
| Tools | 5 | 5 (基础) + task (仅父端) |
|
|
| 上下文 | 单一共享 | 父 + 子隔离 |
|
|
| Subagent | 无 | `run_subagent()` 函数 |
|
|
| 返回值 | 不适用 | 仅摘要文本 |
|
|
| Todo 系统 | TodoManager | 已移除 (非本节重点) |
|
|
|
|
## 设计原理
|
|
|
|
进程隔离免费提供了上下文隔离。全新的 `messages[]` 意味着子智能体不会被父级的对话历史干扰。代价是通信开销 -- 结果必须压缩回父级, 丢失细节。这与操作系统进程隔离的权衡相同: 用序列化成本换取安全性和整洁性。限制子智能体深度 (不允许递归生成) 防止无限资源消耗, 最大迭代次数确保失控的子进程能终止。
|
|
|
|
## 试一试
|
|
|
|
```sh
|
|
cd learn-claude-code
|
|
python agents/s04_subagent.py
|
|
```
|
|
|
|
可以尝试的提示:
|
|
|
|
1. `Use a subtask to find what testing framework this project uses`
|
|
2. `Delegate: read all .py files and summarize what each one does`
|
|
3. `Use a task to create a new module, then verify it from here`
|