deepagents 深度探究:LangChain 生態中的 Deep Agent 實作框架
0. 為什麼需要 Deep Agent?
在 LLM 應用開發中,最簡單的 Agent 形式是讓模型在迴圈中呼叫工具。然而,這種「淺層 Agent」在處理複雜、長時間的任務時往往表現不佳。它們缺乏規劃能力、無法有效管理上下文、也難以處理需要深度思考的多步驟問題。
像 Deep Research、Manus、Claude Code 這類應用之所以能夠處理複雜任務,是因為它們實現了四個關鍵能力的組合:
- 規劃工具(Planning Tool) - 能夠將複雜任務分解為可執行的步驟
- 子代理(Sub Agents) - 能夠派遣專門的代理處理特定子任務
- 檔案系統存取(File System) - 能夠將大量上下文卸載到外部儲存
- 詳細的系統提示詞(Detailed System Prompt) - 針對深度任務優化的指令
deepagents 正是這樣一個 Python 套件,它將這些能力封裝成通用形式,讓開發者能夠輕鬆為自己的應用程式建立 Deep Agent。
致謝:本專案主要靈感來自 Claude Code,最初是尝试理解 Claude Code 為何具有通用性,並進一步将其泛化。
1. 核心架構總覽
deepagents 的核心是 create_deep_agent 函數,它基於 LangGraph 的 create_agent 建構,並自動附加了三個關鍵的 Middleware:
deepagent_middleware = [
TodoListMiddleware(), # 規劃與任務分解
FilesystemMiddleware(), # 檔案系統上下文管理
SubAgentMiddleware(), # 子代理spawner
SummarizationMiddleware(), # 上下文摘要壓縮
AnthropicPromptCachingMiddleware(), # Prompt 快取優化
PatchToolCallsMiddleware(), # 工具呼叫修補
]
整體架構如下:
flowchart TD
subgraph User["使用者"]
U["輸入查詢"]
end
subgraph DeepAgent["Deep Agent"]
direction TB
P["規劃層<br/>TodoListMiddleware"]
C["上下文層<br/>FilesystemMiddleware"]
S["子代理層<br/>SubAgentMiddleware"]
end
subgraph LangGraph["LangGraph 引擎"]
G["Agent State Graph"]
end
U --> DeepAgent
DeepAgent -->|管理狀態| LangGraph
2. 規劃系統:TodoListMiddleware
規劃是解決複雜問題的核心能力。當你使用 Claude Code 處理複雜的多步驟任務時,你會注意到它在開始行動前會先撰寫一份待辦事項清單,並能夠根據新資訊動態調整計劃。
2.1 核心功能
TodoListMiddleware 為 Agent 提供了 write_todos 工具,允許 Agent:
- 任務分解:將複雜目標拆解為可管理的離散步驟
- 進度追蹤:記錄已完成和待完成的項目
- 動態調整:根據新資訊即時更新計劃
2.2 設計原理
這個 Middleware 的設計靈感來自於人類的認知過程:
- 理解目標:首先理解用戶想要什麼
- 規劃路徑:規劃達成目標所需的步驟
- 執行與迭代:執行每個步驟,根據結果調整計劃
# 當處理複雜查詢時,Agent 會自動:
# 1. 呼叫 write_todos 建立任務清單
# 2. 按順序執行每個任務
# 3. 標記完成項目,更新待辦事項
3. 上下文管理:FilesystemMiddleware
Context Engineering 是建構有效 Agent 的主要挑戰之一。當使用可能返回變動長度結果的工具(如 web_search、RAG)時,長時間的工具結果會迅速填滿上下文視窗。
3.1 提供的工具
FilesystemMiddleware 為 Agent 提供了七個工具來管理短期和長期記憶:
| 工具 | 功能 | 用途 |
|---|---|---|
ls | 列出目錄中的檔案 | 探索檔案系統結構 |
read_file | 讀取檔案內容 | 獲取檔案資訊(支援分頁) |
write_file | 建立新檔案 | 儲存分析結果 |
edit_file | 編輯現有檔案 | 修改內容 |
glob | 模式匹配找檔案 | 批量查找檔案 |
grep | 搜尋檔案內容 | 文字搜尋 |
execute | 執行 shell 命令 | 運行指令碼、測試 |
3.2 上下文卸載機制
當工具結果過大時,FilesystemMiddleware 會自動將結果卸載到檔案系統:
TOO_LARGE_TOOL_MSG = """Tool result too large, the result was saved
at: {file_path}
You can read the result from the filesystem by using read_file tool,
but make sure to only read part of the result at a time."""
這個機制確保 Agent 可以處理任意大小的工具結果,而不會耗盡上下文視窗。
3.3 安全性設計
檔案系統存取涉及安全風險,deepagents 實現了多層防護:
- 路徑驗證:防止目錄遍歷攻擊(
..、~) - O_NOFOLLOW:在支援的系統上防止透過符號連結進行檔案存取
- 虛擬模式:可選的沙盒模式,將所有操作限制在指定目錄內
- Windows 路徑過濾:不支援 Windows 絕對路徑格式
def _validate_path(path: str, *, allowed_prefixes: Sequence[str] | None = None) -> str:
# 防止路徑遍歷
if ".." in path or path.startswith("~"):
raise ValueError(f"Path traversal not allowed: {path}")
# 拒絕 Windows 絕對路徑
if re.match(r"^[a-zA-Z]:", path):
raise ValueError(f"Windows absolute paths are not supported")
3.4 靈活的後端支援
FilesystemMiddleware 支援多種儲存後端:
# 預設:暫時性儲存(Agent 狀態中)
FilesystemMiddleware()
# 混合儲存:暫時性 + 長期記憶
backend = CompositeBackend(
default=StateBackend(),
routes={"/memories/": StoreBackend()}
)
FilesystemMiddleware(backend=backend)
# 沙盒環境:支援命令執行
sandbox = DockerSandboxBackend(container_id="my-container")
FilesystemMiddleware(backend=sandbox)
4. 子代理系統:SubAgentMiddleware
將任務委派給子代理是隔離上下文的好方法,能夠保持主管(Supervisor)Agent 的上下文乾淨,同時仍能深入處理特定子任務。
4.1 子代理的生命週期
┌─────────────────────────────────────────────────────────────┐
│ SubAgent Lifecycle │
├─────────────────────────────────────────────────────────────┤
│ 1. SPAWN → 提供清晰的角色、指令和預期輸出 │
│ 2. RUN → 子代理自主完成任務 │
│ 3. RETURN → 子代理提供單一結構化結果 │
│ 4. RECONCILE → 整合結果到主執行緒 │
└─────────────────────────────────────────────────────────────┘
4.2 使用時機
應該使用 task 工具的情況:
- 任務複雜且可完全隔離委託
- 任務獨立於其他任務,可以平行執行
- 任務需要專注推理或大量 Token/上下文使用
- 沙盒化能提高可靠性(如程式碼執行、結構化搜尋)
不應該使用 task 工具的情況:
- 需要看到子代理完成後的中間推理步驟
- 任務簡單(只需幾個工具呼叫)
- 委託不會減少 Token 使用或複雜度
4.3 通用目的子代理
預設情況下,SubAgentMiddleware 會建立一個「通用目的」子代理,它具有與主 Agent 相同的所有能力:
DEFAULT_GENERAL_PURPOSE_DESCRIPTION = """General-purpose agent for
researching complex questions, searching for files and content, and
executing multi-step tasks. When searching for a keyword or file and
not confident about finding the right match in first few tries,
use this agent. This agent has access to all tools as the main agent."""
4.4 自定義子代理
除了通用目的子代理,你還可以定義專業化的子代理:
research_subagent = {
"name": "research-analyst",
"description": "Thorough research on complex topics",
"system_prompt": "You are a research specialist...",
"tools": [internet_search, read_file],
"model": "openai:gpt-4o",
"middleware": [CustomMiddleware()],
"interrupt_on": {"dangerous_tool": {"allowed_decisions": ["approve", "reject"]}}
}
agent = create_deep_agent(
subagents=[research_subagent]
)
4.5 預編譯子代理
對於更複雜的用例,你可以提供自己預先建構的 LangGraph 圖作為子代理:
# 建立自定義 Agent 圖
custom_graph = create_agent(
model=your_model,
tools=specialized_tools,
prompt="You are a specialized agent for data analysis..."
)
# 包裝為預編譯子代理
custom_subagent = CompiledSubAgent(
name="data-analyzer",
description="Specialized agent for complex data analysis",
runnable=custom_graph
)
agent = create_deep_agent(subagents=[custom_subagent])
5. 長期記憶:LangGraph Store 整合
deepagents 支援透過 LangGraph 的 Store 進行跨執行緒的持久化記憶。Agent 可以儲存和檢索先前對話中的資訊:
from langgraph.store.base import BaseStore
# 建立 Store 用於長期記憶
store = InMemoryStore()
agent = create_deep_agent(
store=store, # 啟用長期記憶
)
這個能力對於需要「記住」先前互動細節的 Agent 特別重要,例如:
- 專案特定的上下文
- 使用者的偏好設定
- 先前的分析結果
6. 上下文壓縮與優化
隨著對話進展,上下文視窗會逐漸被填滿。deepagents 實現了多層優化策略:
6.1 SummarizationMiddleware
當上下文接近限制時,自動摘要早期消息:
SummarizationMiddleware(
model=model,
trigger=("tokens", 170000), # 觸發摘要的閾值
keep=("messages", 6), # 保留最近 6 條消息
)
6.2 AnthropicPromptCachingMiddleware
針對 Anthropic 模型優化,利用 Prompt Caching 減少成本和延遲:
AnthropicPromptCachingMiddleware(
unsupported_model_behavior="ignore"
)
7. Human-in-the-Loop
在實際應用中,某些工具操作可能是敏感的,需要人類批准才能執行。deepagents 透過 LangGraph 的中斷能力支援 Human-in-the-Loop 工作流程:
from langchain.agents.middleware import HumanInTheLoopMiddleware, InterruptOnConfig
agent = create_deep_agent(
interrupt_on={
"delete_file": {
"allowed_decisions": ["approve", "edit", "reject"]
},
"execute": {
"allowed_decisions": ["approve", "reject"]
}
}
)
8. MCP 工具整合
deepagents 可以與 MCP(Model Context Protocol)工具整合:
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from deepagents import create_deep_agent
async def main():
# 收集 MCP 工具
mcp_client = MultiServerMCPClient(...)
mcp_tools = await mcp_client.get_tools()
# 建立 Agent
agent = create_deep_agent(tools=mcp_tools)
# 串流執行
async for chunk in agent.astream(
{"messages": [{"role": "user", "content": "what is langgraph?"}]},
stream_mode="values"
):
if "messages" in chunk:
chunk["messages"][-1].pretty_print()
asyncio.run(main())
9. 完整使用範例
以下是一個完整的研究 Agent 範例:
import os
from typing import Literal
from tavily import TavilyClient
from deepagents import create_deep_agent
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def internet_search(
query: str,
max_results: int = 5,
topic: Literal["general", "news", "finance"] = "general",
):
"""執行網路搜尋"""
return tavily_client.search(query, max_results=max_results, topic=topic)
research_instructions = """你是專業研究員。你的工作是進行深入研究,然後撰寫完整的報告。
你可以使用 internet_search 工具作為收集資訊的主要方式。"""
agent = create_deep_agent(
tools=[internet_search],
system_prompt=research_instructions,
)
# 呼叫 Agent
result = agent.invoke({
"messages": [{"role": "user", "content": "什麼是 LangGraph?"}]
})
10. 與其他框架的比較
| 特性 | deepagents | Claude Agent SDK | LangGraph 原生 |
|---|---|---|---|
| 規劃工具 | TodoListMiddleware | 內建 | 需自行實作 |
| 檔案系統 | FilesystemMiddleware | 內建 | 需自行實作 |
| 子代理 | SubAgentMiddleware | 有限 | 需自行實作 |
| 預設模型 | Claude Sonnet 4 | Claude Code CLI | 無 |
| 中斷支援 | HumanInTheLoop | 內建 | 需設定 Checkpointer |
| 主要語言 | Python | Python | Python |
11. 結語
deepagents 為 LangChain 生態帶來了一個重要的抽象層。它將 Claude Code、Deep Research 等成功應用的核心模式封裝成可重用的元件,讓開發者能夠快速建構具有深度推理能力的 Agent。
這個框架的設計體現了幾個重要原則:
- 模組化:每個能力都是獨立的 Middleware,可獨立使用或組合
- 安全性:預設啟用安全機制,防止常見攻擊
- 可擴展性:支援自定義子代理、自定義後端
- 上下文效率:透過卸載和摘要優化上下文使用
隨著 LLM Agent 技術的發展,這類框架將成為建構複雜 AI 應用的重要基礎設施。