Subagent
Core LoopFresh Context per Subtask|200 LOC|5 tools
A subagent is mainly a context boundary, not a process trick.
s00 > s01 > s02 > s03 > [ s04 ] > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > s18 > s19
一個大任務,不一定要塞進一個上下文裡做完。
這一章到底要解決什麼問題
當 agent 連續做很多事時,messages 會越來越長。
比如使用者只問:
“這個專案用什麼測試框架?”
但 agent 可能為了回答這個問題:
- 讀了
pyproject.toml - 讀了
requirements.txt - 搜了
pytest - 跑了測試命令
真正有價值的最終答案,可能只有一句話:
“這個專案主要用
pytest。”
如果這些中間過程都永久堆在父對話裡,後面的問題會越來越難回答,因為上下文被大量區域性任務的噪聲填滿了。
這就是子智慧體要解決的問題:
把區域性任務放進獨立上下文裡做,做完只把必要結果帶回來。
先解釋幾個名詞
什麼是“父智慧體”
當前正在和使用者對話、持有主 messages 的 agent,就是父智慧體。
什麼是“子智慧體”
父智慧體臨時派生出來,專門處理某個子任務的 agent,就是子智慧體。
什麼叫“上下文隔離”
意思是:
- 父智慧體有自己的
messages - 子智慧體也有自己的
messages - 子智慧體的中間過程不會自動寫回父智慧體
最小心智模型
Parent agent
|
| 1. 決定把一個區域性任務外包出去
v
Subagent
|
| 2. 在自己的上下文裡讀檔案 / 搜尋 / 執行工具
v
Summary
|
| 3. 只把最終摘要或結果帶回父智慧體
v
Parent agent continues
最重要的點只有一個:
子智慧體的價值,不是“多一個模型例項”本身,而是“多一個乾淨上下文”。
最小實現長什麼樣
第一步:給父智慧體一個 task 工具
父智慧體需要一個工具,讓模型可以主動說:
“這個子任務我想交給一個獨立上下文去做。”
最小 schema 可以非常簡單:
{
"name": "task",
"description": "Run a subtask in a clean context and return a summary.",
"input_schema": {
"type": "object",
"properties": {
"prompt": {"type": "string"}
},
"required": ["prompt"]
}
}
第二步:子智慧體使用自己的訊息列表
def run_subagent(prompt: str) -> str:
sub_messages = [{"role": "user", "content": prompt}]
...
這就是隔離的關鍵。
不是共享父智慧體的 messages,而是從一份新的列表開始。
第三步:子智慧體只拿必要工具
子智慧體通常不需要擁有和父智慧體完全一樣的能力。
最小版本里,常見做法是:
- 給它檔案讀取、搜尋、bash 之類的基礎工具
- 不給它繼續派生子智慧體的能力
這樣可以防止它無限遞迴。
第四步:只把結果帶回父智慧體
子智慧體做完事後,不把全部內部歷史寫回去,而是返回一段總結。
return {
"type": "tool_result",
"tool_use_id": block.id,
"content": summary_text,
}
這一章最關鍵的資料結構
如果你只記一個結構,就記這個:
class SubagentContext:
messages: list
tools: list
handlers: dict
max_turns: int
解釋一下:
messages:子智慧體自己的上下文tools:子智慧體可以呼叫哪些工具handlers:這些工具到底對應哪些 Python 函式max_turns:防止子智慧體無限跑
這就是最小子智慧體的骨架。
為什麼它真的有用
用處 1:給父上下文減負
區域性任務的中間噪聲不會全都留在主對話裡。
用處 2:讓任務描述更清楚
一個子智慧體接到的 prompt 可以非常聚焦:
- “讀完這幾個檔案,給我一句總結”
- “檢查這個目錄裡有沒有測試”
- “對這個函式寫一個最小修復”
用處 3:讓後面的多 agent 協作有基礎
你可以把子智慧體理解成多 agent 系統的最小起點。
先把一次性子任務外包做明白,後面再升級到長期 teammate、任務認領、團隊協議,會順很多。
從 0 到 1 的實現順序
推薦按這個順序寫:
版本 1:空白上下文子智慧體
先只實現:
- 一個
task工具 - 一個
run_subagent(prompt)函式 - 子智慧體自己的
messages - 子智慧體最後返回摘要
這已經夠了。
版本 2:限制工具集
給子智慧體一個更小、更安全的工具集。
比如:
- 允許
read_file - 允許
grep - 允許只讀 bash
- 不允許
task
版本 3:加入最大輪數和失敗保護
至少補兩個保護:
- 最多跑多少輪
- 工具出錯時怎麼退出
版本 4:再考慮 fork
只有當你已經穩定跑通前面三步,才考慮 fork。
什麼是 fork,為什麼它是“下一步”,不是“起步”
前面的最小實現是:
- 子智慧體從空白上下文開始
這叫最樸素的子智慧體。
但有時一個子任務必須知道父智慧體之前在聊什麼。
例如:
“基於我們剛才已經討論出來的方案,去補測試。”
這時可以用 fork:
- 不是從空白
messages開始 - 而是先複製父智慧體的已有上下文,再追加子任務 prompt
sub_messages = list(parent_messages)
sub_messages.append({"role": "user", "content": prompt})
這就是 fork 的本質:
繼承上下文,而不是重頭開始。
初學者最容易踩的坑
坑 1:把子智慧體當成“為了炫技的併發”
子智慧體首先是為了解決上下文問題,不是為了展示“我有很多 agent”。
坑 2:把父歷史全部原樣灌回去
如果你最後又把子智慧體全量歷史粘回父對話,那隔離價值就幾乎沒了。
坑 3:一上來就做特別複雜的角色系統
比如一開始就加:
- explorer
- reviewer
- planner
- tester
- implementer
這些都可以做,但不應該先做。
先把“一個乾淨上下文的子任務執行器”做對,後面角色化只是在它上面再包一層。
坑 4:忘記給子智慧體設定停止條件
如果沒有:
- 最大輪數
- 異常處理
- 工具過濾
子智慧體很容易無限轉。
教學邊界
這章要先打牢的,不是“多 agent 很高階”,而是:
子智慧體首先是一個上下文邊界。
所以教學版先停在這裡就夠了:
- 一次性子任務就夠
- 摘要返回就夠
- 新
messages+ 工具過濾就夠
不要提前把 fork、後臺執行、transcript 持久化、worktree 繫結一起塞進來。
真正該守住的順序仍然是:
先做隔離,再做高階化。
和後續章節的關係
s04解決的是“區域性任務的上下文隔離”s15-s17解決的是“多個長期角色如何協作”s18解決的是“多個執行者如何在檔案系統層面隔離”
它們不是重複關係,而是遞進關係。
這一章學完後,你應該能回答
- 為什麼大任務不應該總塞在一個
messages裡? - 子智慧體最小版為什麼只需要獨立上下文和摘要返回?
- fork 是什麼,為什麼它不該成為第一步?
- 為什麼子智慧體的第一價值是“減噪”,而不是“炫多 agent”?
一句話記住:子智慧體的核心,不是多一個角色,而是多一個乾淨上下文。