文章目录
-
- 一句话概括
- 项目架构一览
- 核心组件详解
- 核心入口:create_deep_agent
- 基础系统提示
- [中间件系统:Deep Agents 的核心设计](#中间件系统:Deep Agents 的核心设计)
-
- [1. 什么是中间件?](#1. 什么是中间件?)
- [2. 为什么需要中间件?](#2. 为什么需要中间件?)
- [3. Deep Agents 的中间件架构](#3. Deep Agents 的中间件架构)
- [4. 中间件栈的构建](#4. 中间件栈的构建)
-
- [创建 Agent 时中间件的应用顺序](#创建 Agent 时中间件的应用顺序)
- [1. 通用子 Agent 的中间件](#1. 通用子 Agent 的中间件)
- [2. 主 Agent 的中间件](#2. 主 Agent 的中间件)
- [3. 系统提示的组合](#3. 系统提示的组合)
- [4. 最终的 Agent 创建](#4. 最终的 Agent 创建)
- 递归限制
- 中间件系统详解
-
-
- [1. TodoListMiddleware](#1. TodoListMiddleware)
- [2. FilesystemMiddleware](#2. FilesystemMiddleware)
- [3. SubAgentMiddleware](#3. SubAgentMiddleware)
- [4. SummarizationMiddleware](#4. SummarizationMiddleware)
- [5. SkillsMiddleware](#5. SkillsMiddleware)
- [6. MemoryMiddleware](#6. MemoryMiddleware)
- [7. PatchToolCallsMiddleware](#7. PatchToolCallsMiddleware)
- [8. AnthropicPromptCachingMiddleware](#8. AnthropicPromptCachingMiddleware)
- [9. HumanInTheLoopMiddleware](#9. HumanInTheLoopMiddleware)
- [10. AsyncSubAgentMiddleware](#10. AsyncSubAgentMiddleware)
-
- 最终系统提示词结构
- 中间件的状态管理
- 子代理的自动添加
- 默认工具
-
- [1. 任务规划](#1. 任务规划)
- [2. 文件操作](#2. 文件操作)
- [3. Shell 执行](#3. Shell 执行)
- [4. 子 Agent](#4. 子 Agent)
- 返回值
-
- [1. 使用流式输出](#1. 使用流式输出)
- [2. 保存和恢复状态](#2. 保存和恢复状态)
- [3. 与 LangGraph Studio 集成](#3. 与 LangGraph Studio 集成)
- [4. 结构化输出 (response_format)](#4. 结构化输出 (response_format))
- [5. 上下文模式 (context_schema)](#5. 上下文模式 (context_schema))
- [6. 缓存 (cache)](#6. 缓存 (cache))
- [7. 调试模式 (debug)](#7. 调试模式 (debug))
- [8. 状态持久化 (checkpointer vs store)](#8. 状态持久化 (checkpointer vs store))
-
- [Checkpointer - 对话状态持久化](#Checkpointer - 对话状态持久化)
- [Store - 命名空间存储](#Store - 命名空间存储)
- [后端系统:Agent 与外部世界的交互](#后端系统:Agent 与外部世界的交互)
-
- 后端接口定义
- 内置后端实现
-
- [1. StateBackend(默认)](#1. StateBackend(默认))
- [2. FilesystemBackend](#2. FilesystemBackend)
- [3. LocalShellBackend](#3. LocalShellBackend)
- [4. LangSmithSandbox](#4. LangSmithSandbox)
- [5. StoreBackend](#5. StoreBackend)
- [6. CompositeBackend](#6. CompositeBackend)
- [CompositeBackend 实现原理](#CompositeBackend 实现原理)
-
- [1. 初始化配置](#1. 初始化配置)
- [2. 路由匹配逻辑](#2. 路由匹配逻辑)
- [3. 路由流程](#3. 路由流程)
- [4. 路径重映射](#4. 路径重映射)
- [5. 特殊处理](#5. 特殊处理)
- 后端与中间件的交互
- 如何选择后端?
- 技能系统:自定义工作流
- 记忆系统:持久上下文
- 子代理系统:任务委托
-
- 子代理类型
-
- [1. SubAgent(声明式)](#1. SubAgent(声明式))
- 子代理的技能
- [2. CompiledSubAgent(预编译)](#2. CompiledSubAgent(预编译))
- [3. AsyncSubAgent(异步)](#3. AsyncSubAgent(异步))
- SubAgentMiddleware
-
- 工作原理
- [task 工具参数](#task 工具参数)
- 调用子代理
- 主代理与子代理的通信机制
- 人在环中 (Human in the Loop)
-
- 工作原理
-
- [1. 配置需要审批的工具](#1. 配置需要审批的工具)
- [2. 执行流程](#2. 执行流程)
- [3. 详细配置](#3. 详细配置)
- HumanInTheLoopMiddleware
- 检查点要求
- 上下文摘要:处理长对话
-
- SummarizationMiddleware
- 摘要触发条件
- 摘要过程
-
- [1. 检测需要摘要](#1. 检测需要摘要)
- [2. 生成摘要](#2. 生成摘要)
- [3. 替换历史](#3. 替换历史)
- 文件系统卸载
- 架构设计理念
-
- [1. 开箱即用](#1. 开箱即用)
- [2. 可定制](#2. 可定制)
- [3. 基于 LangGraph](#3. 基于 LangGraph)
- [4. Provider 无关](#4. Provider 无关)
- 进阶配置与实战示例
- 总结
- 示例项目
一句话概括
Deep Agents 是一个开箱即用的 AI Agent 框架。
想象一下,你要做一个 AI 助手,通常需要自己组装很多零件:prompt、工具、上下文管理...但 Deep Agents 帮你把这些都准备好了,你只需要几行代码,就能得到一个功能强大的 AI Agent。
它受 Claude Code 启发,旨在打造一个"通用目的"的 AI 助手,能够帮你完成各种复杂任务。
普通的 LLM 只能对话。但"深度 Agent"可以做更多:
- 规划 - 使用
write_todos工具来分解任务、跟踪进度 - 文件系统访问 - 读取、写入、编辑文件,搜索代码
- Shell 执行 - 运行命令(带沙箱隔离)
- 子 Agent - 使用
task工具委托工作给专门的子 Agent - 智能默认 - 内置的 prompt 教模型如何有效使用这些工具
- 上下文管理 - 自动摘要长对话,大输出保存到文件
项目架构一览
这个项目是一个 monorepo(单体仓库),包含多个独立版本管理的包:
deepagents/
├── libs/
│ ├── deepagents/ # 核心 SDK(Python)
│ ├── cli/ # 命令行工具
│ ├── acp/ # Agent Context Protocol 支持
│ ├── evals/ # 评估套件
│ └── partners/ # 第三方集成
├── examples/ # 示例项目
└── .github/ # CI/CD 配置
核心组件详解
Deep Agents SDK (libs/deepagents/)
这是整个项目的心脏。它是一个 Python 包,提供了创建"深度 Agent"的所有能力。
快速开始
python
from deepagents import create_deep_agent
agent = create_deep_agent()
result = agent.invoke({"messages": [{"role": "user", "content": "Research LangGraph and write a summary"}]})
就这几行代码!你得到了一个可以规划、读写文件、管理上下文的完整 Agent。
核心模块
SDK 的代码结构:
deepagents/
├── graph.py # 创建 Agent 的主入口 (create_deep_agent)
├── _models.py # 模型解析 (resolve_model, get_default_model)
├── base_prompt.md # 基础提示词模板
├── middleware/ # 中间件(核心逻辑)
│ ├── __init__.py # 导出和中间件工厂函数
│ ├── _utils.py # 工具函数
│ ├── filesystem.py # 文件系统工具 (ls, read, write, edit, glob, grep)
│ ├── memory.py # 记忆系统 (AGENTS.md)
│ ├── skills.py # 技能系统 (SKILL.md)
│ ├── subagents.py # 同步子 Agent 管理
│ ├── async_subagents.py # 异步子 Agent 管理
│ ├── summarization.py # 上下文摘要(长对话压缩)
│ └── patch_tool_calls.py # 工具调用修补
└── backends/ # 后端实现
├── __init__.py # 导出和后端工厂
├── protocol.py # 协议定义 (BackendProtocol, SandboxBackendProtocol)
├── state.py # 内存状态后端
├── filesystem.py # 真实文件系统后端
├── sandbox.py # 沙箱执行后端 (支持 execute 命令)
├── local_shell.py # 本地 Shell 后端
├── composite.py # 组合后端
├── langsmith.py # LangSmith 后端
├── store.py # 持久化存储后端
└── utils.py # 后端工具函数
核心文件说明:
| 文件 | 作用 |
|---|---|
graph.py |
create_deep_agent() 入口函数 |
middleware/filesystem.py |
提供文件操作和执行命令工具 |
middleware/subagents.py |
提供 task 工具调用子代理 |
middleware/summarization.py |
自动压缩长对话 |
backends/protocol.py |
定义后端接口规范 |
backends/sandbox.py |
远程沙箱执行环境 |
核心入口:create_deep_agent
所有 Magic 从 create_deep_agent 函数开始。打开 graph.py,我们来看这个核心函数。
函数签名
python
def create_deep_agent(
model: str | BaseChatModel | None = None,
tools: Sequence[BaseTool | Callable | dict[str, Any]] | None = None,
*,
system_prompt: str | SystemMessage | None = None,
middleware: Sequence[AgentMiddleware] = (),
subagents: Sequence[SubAgent | CompiledSubAgent | AsyncSubAgent] | None = None,
skills: list[str] | None = None,
memory: list[str] | None = None,
response_format: ResponseFormat | None = None,
context_schema: type[Any] | None = None,
checkpointer: Checkpointer | None = None,
store: BaseStore | None = None,
backend: BackendProtocol | BackendFactory | None = None,
interrupt_on: dict[str, bool | InterruptOnConfig] | None = None,
debug: bool = False,
name: str | None = None,
cache: BaseCache | None = None,
) -> CompiledStateGraph:
这个函数接受很多参数,但不要被吓到------它们都有合理的默认值。
参数详解
| 参数 | 类型 | 说明 |
|---|---|---|
model |
`str | BaseChatModel |
tools |
`Sequence[BaseTool | Callable |
system_prompt |
`str | SystemMessage |
middleware |
Sequence[AgentMiddleware] |
额外的中间件 |
subagents |
`Sequence[SubAgent | ...]` |
skills |
`list[str] | None` |
memory |
`list[str] | None` |
checkpointer |
`Checkpointer | None` |
store |
`BaseStore | None` |
backend |
`BackendProtocol | BackendFactory` |
interrupt_on |
`dict[str, bool | InterruptOnConfig]` |
模型解析 (resolve_model)
Deep Agents 使用 provider:model 格式来指定模型,并提供 resolve_model 函数统一处理模型参数。内部通过 langchain.chat_models.init_chat_model() 初始化模型。
python
from deepagents._models import resolve_model
# 支持的格式:
model = resolve_model("claude-sonnet-4-6") # 简短名称:默认使用 Anthropic
model = resolve_model("openai:gpt-4o") # OpenAI 模型 (使用 Responses API)
model = resolve_model("anthropic:claude-3-5-sonnet") # 带前缀:明确指定提供商
model = resolve_model(existing_model) # 直接传递模型实例
解析逻辑:
- 如果已经是
BaseChatModel实例,直接返回 - 如果以
openai:开头,使用 OpenAI Responses API - 其他情况使用
init_chat_model初始化
支持的模型格式:
| 格式 | 示例 | 说明 |
|---|---|---|
| 简短名称 | claude-sonnet-4-6 |
默认使用 Anthropic |
| 带前缀 | anthropic:claude-3-5-sonnet |
明确指定提供商 |
| OpenAI | openai:gpt-4o |
使用 Responses API |
| 模型实例 | ChatAnthropic(...) |
直接传递实例 |
默认模型
如果你不指定模型,默认使用 Claude Sonnet 4.6:
python
def get_default_model() -> ChatAnthropic:
return ChatAnthropic(
model_name="claude-sonnet-4-6",
)
默认后端
如果你不指定后端,默认使用 StateBackend(内存存储):
python
backend = backend if backend is not None else (StateBackend)
基础系统提示
Deep Agents 有一个精心设计的基础系统提示,定义了 Agent 的核心行为:
python
BASE_AGENT_PROMPT = """你是一个 Deep Agent,一个使用工具帮助用户完成任务的 AI 助手。你通过文本和工具调用来回复。用户可以实时看到你的回复和工具输出。
## 核心行为规范
- 简洁直接。除非被要求,否则不要过度解释。
- 永远不要添加不必要的开场白(如 "好的!"、"好问题!"、"我现在...")。
- 不要说 "我现在来做 X" --- 直接去做。
- 如果请求不明确,在行动前先提问。
- 如果被问及如何处理某事,先解释再行动。
## 专业客观
- 重视准确性而非验证用户的信念
- 当用户错误时礼貌地不同意
- 避免不必要的夸张、赞美或情感认同
## 执行任务
当用户让你做某事时:
1. **先理解** --- 阅读相关文件,检查现有模式。
2. **行动** --- 实现解决方案。
3. **验证** --- 检查你的工作是否符合要求。
持续工作直到任务完全完成。不要中途停止。"""
这个提示定义了 Agent 的行为准则:
- 简洁直接
- 不说废话
- 先理解再行动
- 验证自己的工作
中间件系统:Deep Agents 的核心设计
这是 Deep Agents 最核心的设计。
1. 什么是中间件?
想象一下:你和 LLM 之间有一个"关卡",每次你发送消息给 LLM,或者收到 LLM 的响应时,都会经过这个关卡。
中间件就是这个关卡上的"拦截器"。
它可以在:
- 消息发送给 LLM 之前拦截并修改
- LLM 响应回来 之后拦截并处理
- 工具被调用 之前 /之后做额外处理
2. 为什么需要中间件?
普通的工具函数只能在 LLM 调用 时被触发。但中间件可以在 LLM 调用之前拦截请求,做很多事情:
- 动态过滤工具 - 比如
FilesystemMiddleware根据后端类型决定是否暴露execute工具 - 注入系统提示 - 比如
MemoryMiddleware和SkillsMiddleware在每次调用时注入相关指令 - 转换消息 - 比如
SummarizationMiddleware统计 token 数、截断旧内容、用摘要替换历史 - 维护跨轮状态 - 中间件可以读写跨 Agent 轮次持久化的状态字典
3. Deep Agents 的中间件架构
类层次结构
所有中间件都继承自 AgentMiddleware:
python
class AgentMiddleware(Generic[ContextT, ModelRequest, ModelResponse, ResponseT]):
def wrap_model_request(self, request: ModelRequest) -> ModelRequest:
"""在请求发送给 LLM 之前调用"""
return request
def wrap_model_response(self, response: ModelResponse) -> ModelResponse:
"""在收到 LLM 响应后调用"""
return response
def wrap_tool_calls(self, tool_calls: list[ToolCallRequest]) -> list[ToolCallRequest]:
"""在工具调用执行前调用"""
return tool_calls
def wrap_tool_result(self, tool_name: str, result: Any) -> Any:
"""在工具执行后调用"""
return result
关键钩子方法
AgentMiddleware 提供了多个钩子:
| 方法 | 调用时机 | 用途 |
|---|---|---|
before_agent |
Agent 执行前 | 初始化状态、加载数据 |
modify_request |
修改请求 | 转换输入数据 |
wrap_model_call |
LLM 调用前后 | 拦截请求/响应 |
wrap_tool_call |
工具调用前后 | 处理工具输入/输出 |
after_agent |
Agent 执行后 | 清理、保存状态 |
4. 中间件栈的构建
这是整个函数最复杂的部分。中间件的执行顺序非常关键。
创建 Agent 时中间件的应用顺序
主 Agent:
1. TodoListMiddleware # 任务规划
2. SkillsMiddleware # 技能系统(如果启用)
3. FilesystemMiddleware # 文件操作
4. SubAgentMiddleware # 子 Agent
5. SummarizationMiddleware # 上下文摘要
6. PatchToolCallsMiddleware # 工具调用修补
7. AnthropicPromptCachingMiddleware # 提示缓存
8. MemoryMiddleware # 记忆系统(如果启用)
9. HumanInTheLoopMiddleware # 人在环中(如果启用)
1. 通用子 Agent 的中间件
python
gp_middleware: list[AgentMiddleware[Any, Any, Any]] = [
TodoListMiddleware(), # 任务规划
FilesystemMiddleware(backend=backend), # 文件系统
create_summarization_middleware(model, backend), # 摘要
PatchToolCallsMiddleware(), # 工具调用修补
]
if skills is not None:
gp_middleware.append(SkillsMiddleware(backend=backend, sources=skills))
gp_middleware.append(AnthropicPromptCachingMiddleware(...))
if interrupt_on is not None:
gp_middleware.append(HumanInTheLoopMiddleware(interrupt_on=interrupt_on))
注意 :通用子代理(general-purpose)的中间件栈不包括 SubAgentMiddleware,因为它本身就是子代理。
2. 主 Agent 的中间件
python
deepagent_middleware: list[AgentMiddleware[Any, Any, Any]] = [
TodoListMiddleware(),
]
if skills is not None:
deepagent_middleware.append(SkillsMiddleware(backend=backend, sources=skills))
deepagent_middleware.extend([
FilesystemMiddleware(backend=backend),
SubAgentMiddleware(backend=backend, subagents=inline_subagents),
create_summarization_middleware(model, backend),
PatchToolCallsMiddleware(),
])
if async_subagents:
deepagent_middleware.append(AsyncSubAgentMiddleware(async_subagents=async_subagents))
if middleware:
deepagent_middleware.extend(middleware)
# 缓存和记忆放在最后
# 原因:记忆更新不应该使 Anthropic 提示缓存前缀失效
deepagent_middleware.append(AnthropicPromptCachingMiddleware(...))
if memory is not None:
deepagent_middleware.append(MemoryMiddleware(backend=backend, sources=memory))
if interrupt_on is not None:
deepagent_middleware.append(HumanInTheLoopMiddleware(interrupt_on=interrupt_on))
3. 系统提示的组合
在 create_deep_agent 中,系统提示词会进行智能组合:
python
if system_prompt is None:
final_system_prompt = BASE_AGENT_PROMPT
elif isinstance(system_prompt, SystemMessage):
final_system_prompt = SystemMessage(
content_blocks=[*system_prompt.content_blocks,
{"type": "text", "text": f"\n\n{BASE_AGENT_PROMPT}"}]
)
else:
# String: simple concatenation
final_system_prompt = system_prompt + "\n\n" + BASE_AGENT_PROMPT
4. 最终的 Agent 创建
python
return create_agent(
model,
system_prompt=final_system_prompt,
tools=tools,
middleware=deepagent_middleware,
response_format=response_format,
context_schema=context_schema,
checkpointer=checkpointer,
store=store,
debug=debug,
name=name,
cache=cache,
).with_config({
"recursion_limit": 1000,
"metadata": {
"ls_integration": "deepagents",
"versions": {"deepagents": __version__},
},
})
递归限制
默认设置 recursion_limit=1000,这意味着 Agent 最多可以执行 1000 步(LLM 调用次数)。这是一个安全保护,防止无限循环。
中间件系统详解
1. TodoListMiddleware
功能:提供任务规划能力
提供的工具:
write_todos- 创建、更新、删除待办事项
工作原理:
- 维护一个待办事项列表在 Agent 状态中
- 每次 LLM 调用时,将待办事项注入系统提示
- 工具调用后更新状态
注入到系统提示词的内容(动态生成):
markdown
## 待办事项
你的当前待办列表:
- [ ] 阅读现有代码库
- [ ] 实现新功能
- [ ] 编写测试
使用 `write_todos` 工具更新你的待办列表.
每次 LLM 调用时,会将当前待办事项列表格式化后注入到系统提示中,让 Agent 随时了解任务进度。
2. FilesystemMiddleware
功能:提供文件系统操作能力
提供的工具:
ls- 列出目录read_file- 读取文件write_file- 写入文件edit_file- 编辑文件glob- 文件名匹配grep- 文本搜索execute- 执行命令(需要沙箱后端)
工作原理:
- 根据后端类型动态决定提供哪些工具
- 使用后端协议与实际存储交互
- 处理文件路径验证、权限检查
关键实现细节:
python
class FilesystemMiddleware(AgentMiddleware[FilesystemState, ContextT, ResponseT]):
state_schema = FilesystemState
def __init__(self, backend, tool_token_limit_before_evict=20000):
self.backend = backend
self._tool_token_limit_before_evict = tool_token_limit_before_evict
self.tools = [
self._create_ls_tool(),
self._create_read_file_tool(),
self._create_write_file_tool(),
self._create_edit_file_tool(),
self._create_glob_tool(),
self._create_grep_tool(),
self._create_execute_tool(),
]
大结果驱逐机制:
当工具返回结果过大时(超过 20000 token),自动将结果写入文件系统:
python
def _process_large_message(self, message: ToolMessage, backend):
# 检查是否超过阈值
if len(content_str) > NUM_CHARS_PER_TOKEN * self._tool_token_limit_before_evict:
# 写入文件系统
file_path = f"/large_tool_results/{sanitized_id}"
backend.write(file_path, content_str)
# 返回预览和文件引用
return ToolMessage(content=f"结果已保存到 {file_path}...")
注入到系统提示词的内容:
markdown
## 遵循惯例
- 编辑前先阅读文件 --- 在做出更改之前了解现有内容
- 模仿现有的风格、命名约定和模式
## 文件系统工具 `ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`
你可以使用这些工具与文件系统交互。所有文件路径必须以 / 开头。
- ls: 列出目录中的文件(需要绝对路径)
- read_file: 从文件系统读取文件
- write_file: 向文件系统写入文件
- edit_file: 编辑文件系统中的文件
- glob: 查找匹配模式的文件(如 "**/*.py")
- grep: 在文件中搜索文本
## 大型工具结果
当工具结果太大时,可能会被卸载到文件系统而不是内联返回。在这种情况下,使用 `read_file` 分块检查保存的结果,或在 `/large_tool_results/` 中使用 `grep`。
当后端支持执行时额外注入:
markdown
## 执行工具 `execute`
你有一个 `execute` 工具用于在沙箱环境中运行 shell 命令。
使用此工具运行命令、脚本、测试、构建和其他 shell 操作。
3. SubAgentMiddleware
功能:提供子 Agent 委托能力
提供的工具:
task- 调用子 Agent
工作原理:
- 在系统提示中注入可用子 Agent 的描述
- 拦截
task工具调用 - 创建并运行子 Agent
- 将结果作为 ToolMessage 返回给主 Agent
注入到系统提示词的内容:
markdown
## `task`(子代理生成器)
你有一个 `task` 工具来启动处理独立任务的短生命周期子代理。这些代理是临时的------它们只存在于任务期间并返回单个结果。
何时使用 task 工具:
- 当任务复杂且多步骤,可以完全独立委托时
- 当任务独立于其他任务,可以并行运行时
- 当任务需要集中推理或大量 token/上下文使用时
子代理生命周期:
1. 生成 → 提供清晰的角色、指令和预期输出
2. 运行 → 子代理自主完成任务
3. 返回 → 子代理提供单个结构化结果
4. 调和 → 将结果合并到主线程
可用子代理类型:
- general-purpose: 用于研究复杂问题的通用代理
- researcher: 用于搜索和收集信息的研究代理
Task 工具签名:
python
def task(
description: str, # 任务描述
subagent_type: str, # 子代理类型
runtime: ToolRuntime,
) -> str | Command:
# 1. 验证子代理类型
# 2. 准备子代理状态
# 3. 调用子代理
# 4. 提取返回消息
return _return_command_with_state_update(result, tool_call_id)
4. SummarizationMiddleware
功能:管理长上下文
工作原理:
- 跟踪对话的 token 数量
- 当接近上下文窗口限制时:
- 调用 LLM 生成历史摘要
- 用摘要替换原始历史
- 继续处理当前请求
触发阈值:默认 80% 上下文使用率
注入到系统提示词的内容:
markdown
## 压缩对话工具 `compact_conversation`
你有一个 `compact_conversation` 工具。这个工具刷新你的上下文窗口以减少上下文膨胀和成本。
你应该何时使用这个工具:
- 当用户要求完全转向新任务,且之前的上下文可能无关时
- 当你已完成结果提取或综合,且之前的上下文不再需要时
5. SkillsMiddleware
功能:提供技能系统
工作原理:
- 扫描指定目录查找
SKILL.md文件 - 解析 YAML frontmatter 获取技能元数据
- 在系统提示中注入可用技能列表(渐进式披露)
- 按需读取完整技能内容
注入到系统提示词的内容:
markdown
## 技能系统
你有一个技能库,提供专业能力和领域知识。
**技能位置**:
- **用户技能**: `/skills/user/`
- **项目技能**: `/skills/project/`(更高优先级)
**可用技能**:
- **web-research**: 进行深入网络研究的结构化方法
-> 可用工具: search, fetch
-> 阅读 `/skills/user/web-research/SKILL.md` 获取完整说明
**如何使用技能(渐进式披露)**:
1. 识别技能何时适用:检查用户任务是否匹配技能描述
2. 阅读技能的完整说明:使用上面技能列表中的路径
3. 按照技能的说明执行:SKILL.md 包含分步工作流、最佳实践和示例
4. 访问支持文件:技能可能包含辅助脚本、配置或参考文档
技能元数据结构:
python
class SkillMetadata(TypedDict):
path: str # SKILL.md 文件路径
name: str # 技能名称(1-64 字符)
description: str # 技能描述(1-1024 字符)
license: str | None
compatibility: str | None
metadata: dict[str, str]
allowed_tools: list[str]
6. MemoryMiddleware
功能:提供持久记忆
工作原理:
- 加载
AGENTS.md文件 - 在系统提示中注入记忆内容
- 每次请求时自动包含
注入到系统提示词的内容:
markdown
<agent_memory>
~/.deepagents/AGENTS.md
# 项目指南
- 所有新代码使用 TypeScript
- 遵循 src/ 中的现有代码风格
- 提交前运行测试
./project/AGENTS.md
# Agent 上下文
这是一个使用 Next.js 14 的 React 项目。
API 路由在 src/app/api/ 中
</agent_memory>
<memory_guidelines>
上面的 <agent_memory> 是从文件系统中的文件加载的。当你在与用户的交互中学习时,你可以通过调用 `edit_file` 工具保存新知识。
**从反馈中学习:**
- 你最主要的任务之一是从与用户的交互中学习。
- 当你需要记住某些东西时,更新记忆必须是你的第一个、立即的行动。
- 当用户说某些东西更好/更差时,捕获原因并将其编码为模式。
**何时更新记忆:**
- 当用户明确要求你记住某些东西时
- 当用户描述你的角色或你应该如何行为时
- 当用户对你的工作提供反馈时
- 当用户提供工具使用所需的信息时
**何时不更新记忆:**
- 当信息是临时的或短暂的时
- 当信息是一次性任务请求时
- 永远不要在任何文件或记忆中存储 API 密钥、访问令牌、密码
</memory_guidelines>
7. PatchToolCallsMiddleware
功能:修补工具调用
工作原理:
- 规范化工具参数
- 处理参数类型转换
- 添加默认参数值
是否修改系统提示词:否(该中间件只处理工具调用参数,不涉及提示词注入)
8. AnthropicPromptCachingMiddleware
功能:优化 Anthropic 模型的提示缓存
工作原理:
- 检测静态内容(系统提示、工具定义)
- 使用 Anthropic 的提示缓存 API
- 减少重复传输的 token
是否修改系统提示词:否(该中间件使用 API 层面的缓存机制,不修改提示词内容)
9. HumanInTheLoopMiddleware
功能:人在环中审批
工作原理:
- 配置哪些工具需要审批
- 执行前暂停 Agent
- 等待人类批准或修改
- 继续执行或拒绝
是否修改系统提示词:否(该中间件在运行时拦截工具调用,不修改提示词)
10. AsyncSubAgentMiddleware
功能:提供异步子 Agent(远程 LangGraph 服务器)
工作原理:
- 在远程 LangGraph 服务器上启动后台任务
- 提供异步任务管理工具
- 支持任务状态检查、更新、取消
提供的工具:
start_async_task- 启动后台任务check_async_task- 检查任务状态update_async_task- 更新任务指令cancel_async_task- 取消任务list_async_tasks- 列出所有任务
注入到系统提示词的内容:
markdown
## 异步子代理(远程 LangGraph 服务器)
你有一个异步子代理工具,可以在远程 LangGraph 服务器上启动后台任务。
#### 工具:
- `start_async_task`: 启动新的后台任务。立即返回任务 ID。
- `check_async_task`: 获取任务的当前状态和结果。
- `update_async_task`: 向正在运行的任务发送新指令。
- `cancel_async_task`: 停止正在运行的任务。
- `list_async_tasks`: 列出所有跟踪的任务及其实时状态。
#### 关键规则:
- 启动后,始终立即将控制权返回给用户。启动后永远不要自动检查。
- 永远不要循环轮询 `check_async_task`。
- 对话历史中的任务状态始终是过时的------始终调用工具获取当前状态。
可用异步子代理类型:
- my-agent: 异步子代理的描述
最终系统提示词结构
当用户调用 create_deep_agent() 时,最终发送给 LLM 的系统提示词按照以下顺序拼接:
markdown
[用户自定义 system_prompt]
你是一个 Deep Agent,一个使用工具帮助用户完成任务的 AI 助手。用户可以实时看到你的回复和工具输出...
## 核心行为规范
- 简洁直接。除非被要求,否则不要过度解释。
- 永远不要添加不必要的开场白(如 "好的!"、"好问题!"、"我现在...")。
- 如果请求不明确,在行动前先提问。
- 如果被问及如何处理某事,先解释再行动。
## 专业客观
- 重视准确性而非验证用户的信念
- 当用户错误时礼貌地不同意
- 避免不必要的夸张、赞美或情感认同
## 执行任务
当用户让你做某事时...
## 待办事项
你的当前待办列表:
- [ ] 任务 1
- [ ] 任务 2
使用 `write_todos` 工具更新你的待办列表。
## 技能系统
你有一个技能库,提供专业能力和领域知识。
**技能位置**:
- **用户技能**: `/skills/user/`
- **项目技能**: `/skills/project/`(更高优先级)
**可用技能**:
- **web-research**: 进行深入网络研究的结构化方法
-> 可用工具: search, fetch
-> 阅读 `/skills/user/web-research/SKILL.md` 获取完整说明
**如何使用技能(渐进式披露)**:
1. 识别技能何时适用:检查用户任务是否匹配技能描述
2. 阅读技能的完整说明:使用上面技能列表中的路径
3. 按照技能的说明执行:SKILL.md 包含分步工作流、最佳实践和示例
4. 访问支持文件:技能可能包含辅助脚本、配置或参考文档
## 遵循惯例
- 编辑前先阅读文件 --- 在做出更改之前了解现有内容
- 模仿现有的风格、命名约定和模式
## 文件系统工具 `ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`
你可以使用这些工具与文件系统交互。所有文件路径必须以 / 开头。
- ls: 列出目录中的文件(需要绝对路径)
- read_file: 从文件系统读取文件
- write_file: 向文件系统写入文件
- edit_file: 编辑文件系统中的文件
- glob: 查找匹配模式的文件(如 "**/*.py")
- grep: 在文件中搜索文本
## 大型工具结果
当工具结果太大时,可能会被卸载到文件系统而不是内联返回。在这种情况下,使用 `read_file` 分块检查保存的结果,或在 `/large_tool_results/` 中使用 `grep`。
## `task`(子代理生成器)
你有一个 `task` 工具来启动处理独立任务的短生命周期子代理。这些代理是临时的------它们只存在于任务期间并返回单个结果。
何时使用 task 工具:
- 当任务复杂且多步骤,可以完全独立委托时
- 当任务独立于其他任务,可以并行运行时
- 当任务需要集中推理或大量 token/上下文使用时
子代理生命周期:
1. 生成 → 提供清晰的角色、指令和预期输出
2. 运行 → 子代理自主完成任务
3. 返回 → 子代理提供单个结构化结果
4. 调和 → 将结果合并到主线程
可用子代理类型:
- general-purpose: 用于研究复杂问题的通用代理
## 压缩对话工具 `compact_conversation`
你有一个 `compact_conversation` 工具。这个工具刷新你的上下文窗口以减少上下文膨胀和成本。
你应该何时使用这个工具:
- 当用户要求完全转向新任务,且之前的上下文可能无关时
- 当你已完成结果提取或综合,且之前的上下文不再需要时
<agent_memory>
[memory 内容]
</agent_memory>
<memory_guidelines>
上面的 <agent_memory> 是从文件系统中的文件加载的。当你在与用户的交互中学习时,你可以通过调用 `edit_file` 工具保存新知识。
**从反馈中学习:**
- 你最主要的任务之一是从与用户的交互中学习。
- 当你需要记住某些东西时,更新记忆必须是你的第一个、立即的行动。
- 当用户说某些东西更好/更差时,捕获原因并将其编码为模式。
**何时更新记忆:**
- 当用户明确要求你记住某些东西时
- 当用户描述你的角色或你应该如何行为时
- 当用户对你的工作提供反馈时
- 当用户提供工具使用所需的信息时
**何时不更新记忆:**
- 当信息是临时的或短暂的时
- 当信息是一次性任务请求时
- 永远不要在任何文件或记忆中存储 API 密钥、访问令牌、密码
</memory_guidelines>
提示词组装顺序:
- 用户自定义
system_prompt(如有) - BASE_AGENT_PROMPT - Deep Agent 核心行为规范
- TodoListMiddleware - 待办事项(动态)
- SkillsMiddleware - 技能系统(如果有 skills 配置)
- FilesystemMiddleware - 文件系统工具说明
- SubAgentMiddleware - 子 Agent 工具说明
- SummarizationMiddleware - 上下文压缩工具
- AnthropicPromptCachingMiddleware - 缓存标记(API 层面)
- MemoryMiddleware - 记忆内容(如果有 memory 配置)
每个中间件通过 modify_request 或 wrap_model_call 方法将内容追加到系统消息末尾。
中间件的状态管理
每个中间件可以定义自己的状态类型:
python
class MyMiddlewareState(AgentState):
my_data: str
counter: int
class MyMiddleware(AgentMiddleware):
state_schema = MyMiddlewareState
def wrap_model_request(self, request, state):
# 读取状态
current_count = state.get("counter", 0)
# 修改状态
state["counter"] = current_count + 1
return request
私有状态属性:
使用 PrivateStateAttr 标记不传播到父 Agent 的状态:
python
from langchain.agents.middleware.types import PrivateStateAttr
class SkillsState(AgentState):
skills_metadata: NotRequired[Annotated[list[SkillMetadata], PrivateStateAttr]]
"""不会传播到父 Agent"""
状态通过 LangGraph 的状态管理机制在轮次之间持久化。
子代理的自动添加
通用子代理的创建
如果没有提供名为 general-purpose 的子代理,会自动创建一个:
python
GENERAL_PURPOSE_SUBAGENT: SubAgent = {
"name": "general-purpose",
"description": "General-purpose agent for researching complex questions...",
"system_prompt": DEFAULT_SUBAGENT_PROMPT,
}
子代理中间件栈
每个子代理都会获得完整的中间件栈:
python
subagent_middleware: list[AgentMiddleware[Any, Any, Any]] = [
TodoListMiddleware(),
FilesystemMiddleware(backend=backend),
create_summarization_middleware(subagent_model, backend),
PatchToolCallsMiddleware(),
]
# 添加技能(如果指定)
if subagent_skills:
subagent_middleware.append(SkillsMiddleware(backend=backend, sources=subagent_skills))
# 添加用户自定义中间件
subagent_middleware.extend(spec.get("middleware", []))
# 添加提示缓存
subagent_middleware.append(AnthropicPromptCachingMiddleware(...))
默认工具
创建 Deep Agent 时,你不需要手动添加任何工具------以下工具默认可用:
1. 任务规划
write_todos- 管理待办事项列表
2. 文件操作
ls- 列出目录内容read_file- 读取文件write_file- 写入文件edit_file- 编辑文件glob- 文件名模式匹配grep- 文本搜索
3. Shell 执行
execute- 运行 Shell 命令(需要支持沙箱的后端)
4. 子 Agent
task- 调用子 Agent
返回值
create_deep_agent 返回一个 CompiledStateGraph------这是 LangGraph 的编译状态图。
这意味着你可以:
1. 使用流式输出
python
for chunk in agent.stream({"messages": [("user", "Hello")]):
print(chunk)
2. 保存和恢复状态
python
# 保存状态
config = {"configurable": {"thread_id": "my-session"}}
agent.invoke({"messages": [...]}, config)
# 恢复状态
agent.invoke({"messages": [("user", "继续")], config)
3. 与 LangGraph Studio 集成
python
# 导出到 LangGraph Studio
agent.get_graph().draw_mermaid()
4. 结构化输出 (response_format)
使用 response_format 强制 Agent 返回特定格式:
python
from langchain.agents.structured_output import ResponseFormat
from pydantic import BaseModel
class Answer(BaseModel):
reasoning: str
answer: str
confidence: float
agent = create_deep_agent(
response_format=ResponseFormat(
schema=Answer,
mode="json", # 或 "xml"
)
)
# Agent 必须返回符合 Answer 格式的 JSON
result = await agent.ainvoke({"messages": [("user", "什么是 2+2?")]})
支持的模式:
json- JSON 格式输出xml- XML 格式输出
5. 上下文模式 (context_schema)
定义 Agent 状态的结构:
python
from typing import TypedDict
class MyAgentState(TypedDict):
messages: list
todo_items: list[str]
current_task: str | None
agent = create_deep_agent(
context_schema=MyAgentState,
)
这允许你:
- 定义自定义状态字段
- 类型安全的状态管理
- 与 LangGraph 的状态管理集成
6. 缓存 (cache)
使用 LangGraph 缓存加速重复查询:
python
from langgraph.cache import InMemoryCache
agent = create_deep_agent(
cache=InMemoryCache(),
)
# 相同输入会直接从缓存返回
缓存类型:
InMemoryCache- 内存缓存- 自定义缓存实现
7. 调试模式 (debug)
启用详细日志:
python
agent = create_deep_agent(
debug=True, # 启用 LangGraph 调试日志
)
调试模式会输出:
- Agent 决策过程
- 工具调用详情
- 状态变化
- 中间件执行信息
8. 状态持久化 (checkpointer vs store)
Deep Agents 支持两种持久化机制:
Checkpointer - 对话状态持久化
保存整个对话状态,支持恢复:
python
from langgraph.checkpoint.memory import MemorySaver
from langgraph.checkpoint.sqlite import SqliteSaver
# 内存检查点
agent = create_deep_agent(
checkpointer=MemorySaver(),
)
# SQLite 持久化
agent = create_deep_agent(
checkpointer=SqliteSaver.from_conn_string("./checkpoints.db"),
)
# 使用检查点
config = {"configurable": {"thread_id": "session-1"}}
result = await agent.ainvoke({"messages": [("user", "Hello")]}, config)
# 恢复会话
result = await agent.ainvoke({"messages": [("user", "Continue")]}, config)
Store - 命名空间存储
用于跨会话的持久化数据:
python
from langgraph.store.memory import MemoryStore
agent = create_deep_agent(
store=MemoryStore(),
)
# 存储数据
await agent.store.put(
("user_prefs", "theme"),
{"value": "dark", "font_size": 14}
)
# 读取数据
result = await agent.store.get(("user_prefs", "theme"))
对比:
| 特性 | Checkpointer | Store |
|---|---|---|
| 用途 | 对话状态 | 持久化数据 |
| 范围 | 当前会话 | 跨会话 |
| 数据 | 完整状态 | 任意数据 |
| 典型场景 | 会话恢复 | 用户偏好、配置 |
后端系统:Agent 与外部世界的交互
Deep Agents 是一个可插拔的框架。不同的使用场景需要不同的后端:
- 开发/测试 - 需要安全隔离,数据存在内存中
- 生产环境 - 需要访问真实文件系统
- 沙箱执行 - 需要在隔离环境中运行命令
后端系统抽象了这些差异,让同一套代码可以适配不同场景。
后端接口定义
所有后端都实现 BackendProtocol 接口。打开 backends/protocol.py 看看:
核心接口
python
class BackendProtocol(Protocol):
"""所有后端必须实现的接口"""
async def read_file(self, path: str) -> ReadResult:
"""读取文件"""
...
async def write_file(self, path: str, content: str) -> WriteResult:
"""写入文件"""
...
async def edit_file(self, path: str, old_string: str, new_string: str) -> EditResult:
"""编辑文件"""
...
async def ls(self, path: str) -> LsResult:
"""列出目录"""
...
async def glob(self, path: str, pattern: str) -> GlobResult:
"""文件名匹配"""
...
async def grep(self, path: str, pattern: str, **kwargs) -> GrepResult:
"""文本搜索"""
...
沙箱协议
如果后端支持命令执行,还需要实现 SandboxBackendProtocol:
python
class SandboxBackendProtocol(BackendProtocol):
"""支持命令执行的后端"""
async def execute(
self,
command: str,
timeout: float = ...,
context: dict | None = None
) -> ExecuteResult:
"""执行命令"""
...
内置后端实现
1. StateBackend(默认)
位置 :backends/state.py
特点:
- 所有数据存在内存中
- 最安全,适合开发/测试
- 不需要任何持久化
工作原理:
python
class StateBackend:
"""内存状态后端"""
def __init__(self, runtime: Runtime | None = None):
self._files: dict[str, FileData] = {} # 文件存储
self._runtime = runtime # LangGraph runtime
async def read_file(self, path: str) -> ReadResult:
if path not in self._files:
raise FileNotFoundError(f"File not found: {path}")
return ReadResult(
content=self._files[path].content,
size=len(self._files[path].content),
)
使用场景:
- 本地开发
- 单元测试
- 不需要持久化的场景
2. FilesystemBackend
位置 :backends/filesystem.py
特点:
- 访问真实文件系统
- 需要配置根目录
- 支持路径验证和安全检查
使用示例:
python
from deepagents.backends import FilesystemBackend
# 限制在项目目录
backend = FilesystemBackend(root_dir="/path/to/project")
# 限制在用户目录
backend = FilesystemBackend(root_dir="~")
安全考虑:
- 默认只能访问配置的根目录
- 可以添加路径验证
- 建议配合人在环中使用
3. LocalShellBackend
位置 :backends/local_shell.py
特点:
- 本地 Shell 命令执行
- 支持超时设置
- 可以捕获输出
使用示例:
python
from deepagents.backends import LocalShellBackend
backend = LocalShellBackend(
timeout=30.0, # 默认超时 30 秒
)
result = await backend.execute("ls -la")
安全考虑:
- ⚠️ 危险!可以执行任何命令
- 建议只在受控环境使用
- 建议配合人在环中使用
4. LangSmithSandbox
位置 :backends/langsmith.py
特点:
- LangSmith 远程沙箱
- 完全隔离的环境
- 自动清理
使用示例:
python
from deepagents.backends import LangSmithSandbox
backend = LangSmithSandbox(
api_key=os.getenv("LANGSMITH_API_KEY"),
)
5. StoreBackend
位置 :backends/store.py
特点:
- 持久化存储
- 基于 LangGraph Store
- 支持命名空间
使用场景:
- 需要跨会话持久化
- 复杂的数据结构
6. CompositeBackend
位置 :backends/composite.py
特点:
- 组合多个后端
- 可以为不同操作指定不同后端
- 灵活的路由逻辑
使用示例:
python
from deepagents.backends import CompositeBackend, FilesystemBackend, LangSmithSandbox
backend = CompositeBackend(
# 文件操作使用真实文件系统
file_backend=FilesystemBackend(root_dir="/project"),
# 命令执行使用远程沙箱
execute_backend=LangSmithSandbox(),
)
CompositeBackend 实现原理
CompositeBackend 通过路径前缀路由实现不同操作指定不同后端。
1. 初始化配置
python
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
composite = CompositeBackend(
default=StateBackend(runtime), # 默认后端
routes={
"/memories/": StoreBackend(runtime), # 路由到持久化存储
"/cache/": FilesystemBackend(...), # 路由到文件系统
}
)
2. 路由匹配逻辑
关键函数 _route_for_path:
python
def _route_for_path(*, default, sorted_routes, path):
# 按长度排序(最长优先),确保精确匹配
for route_prefix, backend in sorted_routes:
normalized_prefix = route_prefix if route_prefix.endswith("/") else f"{route_prefix}/"
if path.startswith(normalized_prefix):
# 匹配成功,剥离前缀后传递给目标后端
suffix = path[len(normalized_prefix):]
backend_path = f"/{suffix}" if suffix else "/"
return backend, backend_path, route_prefix
# 无匹配,使用默认后端
return default, path, None
3. 路由流程
每个文件操作都会经过路由:
python
def read(self, file_path: str, ...):
# 1. 根据路径找到对应的后端和实际路径
backend, stripped_key = self._get_backend_and_key(file_path)
# 2. 委托给正确的后端处理
return backend.read(stripped_key, offset=offset, limit=limit)
4. 路径重映射
当路由到子后端时,需要剥离路由前缀,返回时再还原:
用户访问 /memories/notes.txt
↓
实际传递给 StoreBackend 的是 /notes.txt
↓
返回结果时再拼接回 /memories/notes.txt
5. 特殊处理
- 根目录
/:聚合所有后端的文件列表 - grep/glob:搜索所有后端并合并结果
- execute:始终使用默认后端(不支持路由)
这种设计让同一个文件系统 API 可以透明地路由到不同的存储后端。
后端与中间件的交互
中间件通过后端协议与后端交互:
python
class FilesystemMiddleware:
def __init__(self, backend: BackendProtocol):
self._backend = backend
async def read_file(self, path: str):
# 调用后端
return await self._backend.read_file(path)
这种设计让中间件不需要关心数据存储在哪里。
如何选择后端?
| 场景 | 推荐后端 |
|---|---|
| 本地开发/测试 | StateBackend(默认) |
| 生产文件操作 | FilesystemBackend |
| 本地命令执行 | LocalShellBackend |
| 隔离执行 | LangSmithSandbox |
| 持久化存储 | StoreBackend |
| 混合需求 | CompositeBackend |
技能系统:自定义工作流
技能(Skills)是一种可重用的工作流 ,Agent 可以通过斜杠命令(如 /skill-name)调用它们。
想象一下:
- 你有一个常用的代码审查流程
- 你有一个常用的测试生成流程
- 你有一个常用的文档生成流程
把这些流程封装成技能,Agent 就可以在需要时调用它们。
技能 vs 记忆
| 特性 | 技能 | 记忆 |
|---|---|---|
| 调用方式 | 按需(斜杠命令) | 自动(始终加载) |
| 用途 | 工作流 | 持久上下文 |
| 触发 | 用户显式调用 | Agent 启动时 |
| 动态性 | 高度动态 | 相对静态 |
SKILL.md 格式
技能定义在 SKILL.md 文件中:
markdown
# Skill Name
Description of what this skill does and when to use it.
## Steps
1. First step description
2. Second step description
3. Third step description
## Example
/example argument
字段说明
- # Skill Name - 技能名称(用于斜杠命令)
- Description - 描述,说明何时使用
- Steps - 执行步骤
- Example - 使用示例
技能系统架构
SkillsMiddleware
核心是 SkillsMiddleware,它:
- 扫描指定目录查找
SKILL.md文件 - 解析技能定义
- 在系统提示中注入可用技能
- 拦截技能调用并执行
技能调用机制
1. 技能发现(Session 启动时)
每次 LLM 调用前,SkillsMiddleware 会:
- 扫描技能目录
- 加载所有
SKILL.md文件 - 解析技能定义(YAML frontmatter)
- 注入到系统提示(渐进式披露)
关键:技能元数据只加载一次
python
def before_agent(self, state, runtime, config):
# 如果 skills_metadata 已存在,跳过加载
if "skills_metadata" in state:
return None
# 从所有源加载技能
for source_path in self.sources:
source_skills = _list_skills(backend, source_path)
all_skills[skill["name"]] = skill
return SkillsStateUpdate(skills_metadata=skills)
2. 渐进式披露(每次 LLM 调用)
系统提示中只注入技能的元数据,不加载完整内容:
markdown
**Available Skills**:
- **web-research**: Structured approach to conducting thorough web research
-> Allowed tools: search, fetch
-> Read `/skills/user/web-research/SKILL.md` for full instructions
Agent 需要使用技能时,会主动读取 SKILL.md 文件。
3. 技能调用流程
用户: /web-research 最佳AI助手是什么?
1. SkillsMiddleware 识别斜杠命令
2. Agent 读取 /skills/user/web-research/SKILL.md
3. 执行技能定义的工作流
4. 返回结果
4. 按需加载的优势
- 减少 Token 消耗:完整技能文档可能很大,按需加载避免每次都注入
- 提高响应速度:初始提示更小,LLM 处理更快
- 灵活性:Agent 可以根据任务选择性地读取相关技能
5. 技能执行
技能执行本质上是一个提示模板:
python
# 技能调用时,生成如下提示:
f"""Execute skill: {skill_name}
{skill_description}
## Steps
{skill_steps}
Now execute this skill."""
记忆系统:持久上下文
记忆(Memory)是 Agent 启动时自动加载的持久上下文。
与技能不同,记忆:
- 始终加载(不需要显式调用)
- 提供项目级上下文
- 在每次对话中都可用的
AGENTS.md 规范
Deep Agents 支持 AGENTS.md 规范。
基本格式
markdown
# Project Name
## Overview
Brief description of the project.
## Build Commands
- `npm install` - Install dependencies
- `npm run dev` - Start development server
- `npm test` - Run tests
## Code Style
- Use TypeScript
- 4 spaces for indentation
- Prefer functional components
## Architecture
- `/src/components` - UI components
- `/src/hooks` - Custom hooks
- `/src/utils` - Utility functions
常用章节
- Overview - 项目概述
- Build Commands - 构建命令
- Code Style - 代码风格
- Architecture - 架构说明
- Testing - 测试指南
- Deployment - 部署指南
MemoryMiddleware
工作原理
python
class MemoryMiddleware(AgentMiddleware):
def __init__(self, backend: BackendProtocol, sources: list[str]):
self._backend = backend
self._sources = sources
def wrap_model_request(self, request, state):
# 加载所有记忆文件
memories = []
for source in self._sources:
content = load_agents_md(source)
memories.append(content)
# 注入到系统提示
prompt = format_memory(memories)
request = append_to_system_message(request, prompt)
return request
使用方式
python
agent = create_deep_agent(
memory=[
"~/.deepagents/AGENTS.md", # 用户级记忆
"./.deepagents/AGENTS.md", # 项目级记忆
]
)
记忆来源
1. 用户级记忆
位置:~/.deepagents/AGENTS.md
包含:
- 用户偏好
- 常用命令
- 个人习惯
2. 项目级记忆
位置:.deepagents/AGENTS.md
包含:
- 项目特定配置
- 构建命令
- 代码规范
3. 环境级记忆
位置:可以在任何地方指定
python
agent = create_deep_agent(
memory=["/path/to/custom/AGENTS.md"]
)
记忆加载顺序
多个记忆文件按顺序加载,后面的会覆盖前面的:
python
memory = [
"~/.deepagents/AGENTS.md", # 先加载
"./.deepagents/AGENTS.md", # 后加载(优先级高)
]
子代理系统:任务委托
子代理(SubAgent)是主 Agent 可以调用的专门 Agent。
当你有一个复杂任务时,可以:
- 自己完成所有事情
- 把任务分解,委托给子代理
子代理的优势:
- 专业化 - 每个子代理专注特定任务
- 隔离 - 子代理有独立的上下文
- 可复用 - 一次定义,多次使用
子代理类型
Deep Agents 支持三种类型的子代理:
1. SubAgent(声明式)
最常用的子代理类型,定义为一个配置字典:
python
subagent = {
"name": "reviewer",
"description": "代码审查专家,帮助审查代码质量和安全问题",
"system_prompt": """你是一个严格的代码审查专家。
审查时关注:
1. 代码风格一致性
2. 错误处理
3. 安全问题
4. 性能问题
5. 测试覆盖
审查结果要具体、可操作。""",
"tools": [some_tools], # 可选:指定工具
"model": "claude-sonnet-4", # 可选:指定模型
"skills": ["/reviewer/skills/"], # 可选:子代理独立的技能
"middleware": [...], # 可选:额外的中间件
"interrupt_on": {"edit_file": True}, # 可选:人在环中配置
}
子代理的技能
子代理的 skills 与主 agent 不共享,需要单独配置。每个子代理可以拥有自己独立的技能系统:
python
agent = create_deep_agent(
skills=["/main/skills/"], # 主 Agent 的技能
subagents=[
{
"name": "reviewer",
"description": "代码审查专家",
"system_prompt": "你是一个严格的代码审查专家...",
"tools": [read_file, glob, grep],
"model": "claude-sonnet-4",
"skills": ["/reviewer/skills/"], # 子代理独立的技能
}
]
)
子代理的中间件栈构建过程:
python
# graph.py 中的子代理中间件构建
subagent_middleware: list[AgentMiddleware[Any, Any, Any]] = [
TodoListMiddleware(),
FilesystemMiddleware(backend=backend),
create_summarization_middleware(subagent_model, backend),
PatchToolCallsMiddleware(),
]
# 添加子代理自己的技能(如果有)
subagent_skills = spec.get("skills")
if subagent_skills:
subagent_middleware.append(SkillsMiddleware(backend=backend, sources=subagent_skills))
# 添加用户自定义中间件
subagent_middleware.extend(spec.get("middleware", []))
# 添加提示缓存
subagent_middleware.append(AnthropicPromptCachingMiddleware(unsupported_model_behavior="ignore"))
2. CompiledSubAgent(预编译)
使用已编译的 LangGraph 图:
python
from langgraph.graph import StateGraph
# 创建一个预编译的子代理
subagent_graph = create_my_subagent() # 返回 CompiledStateGraph
compiled_subagent = {
"name": "researcher",
"description": "研究助手,帮助收集和分析信息",
"runnable": subagent_graph,
}
3. AsyncSubAgent(异步)
用于远程或后台执行的子代理:
python
async_subagent = {
"name": "background-worker",
"description": "后台任务执行器",
"graph_id": "my-deployment-id", # LangSmith deployment ID
"url": "https://...",
"headers": {"Authorization": "Bearer ..."},
}
SubAgentMiddleware
工作原理
python
class SubAgentMiddleware(AgentMiddleware):
def __init__(self, backend, subagents):
self._backend = backend
self._subagents = subagents
def wrap_model_request(self, request, state):
# 注入子代理描述到系统提示
subagent_descriptions = format_subagents(self._subagents)
request = append_to_system_message(request, subagent_descriptions)
return request
def wrap_tool_calls(self, tool_calls, state):
# 拦截 task 工具调用
for call in tool_calls:
if call.tool_name == "task":
return self._execute_subagent(call, state)
return tool_calls
task 工具参数
python
{
"name": "task",
"description": "委托任务给子代理",
"parameters": {
"subagent": "子代理名称",
"task": "任务描述",
"context": {} # 可选的上下文
}
}
调用子代理
在对话中:
用户: 帮我审查这段代码
Agent: (调用 reviewer 子代理)
或者显式调用:
用户: 使用 reviewer 审查 src/utils.py
主代理与子代理的通信机制
主代理和子代理通过 task 工具调用进行通信。
通信流程
主 Agent: "帮我搜索这个项目的架构"
↓
调用 task 工具
↓
SubAgentMiddleware 拦截
↓
子 Agent 执行任务
↓
返回 ToolMessage 给主 Agent
关键代码实现
1. 任务调用
python
def task(description, subagent_type, runtime):
# 1. 获取子代理
subagent = subagent_graphs[subagent_type]
# 2. 准备子代理状态(隔离上下文)
subagent_state = {k: v for k, v in runtime.state.items() if k not in _EXCLUDED_STATE_KEYS}
subagent_state["messages"] = [HumanMessage(content=description)]
# 3. 调用子代理
result = subagent.invoke(subagent_state)
# 4. 返回结果(转为 ToolMessage)
return _return_command_with_state_update(result, runtime.tool_call_id)
2. 状态隔离(排除的键)
python
_EXCLUDED_STATE_KEYS = {"messages", "todos", "structured_response", "skills_metadata", "memory_contents"}
子代理不继承主 Agent 的这些状态,确保独立上下文。
3. 结果返回
python
def _return_command_with_state_update(result, tool_call_id):
# 提取子代理返回的消息
message_text = result["messages"][-1].text
# 作为 ToolMessage 返回给主 Agent
return Command(update={
"messages": [ToolMessage(message_text, tool_call_id=tool_call_id)],
})
通信特点
| 特性 | 说明 |
|---|---|
| 调用方式 | 同步/异步函数调用 |
| 状态传递 | 主 Agent → 子 Agent(排除敏感状态) |
| 结果返回 | 子 Agent → 主 Agent(通过 ToolMessage) |
| 上下文隔离 | 子代理有独立的 messages 列表 |
| 单向通信 | 子代理完成后,结果以工具结果形式返回 |
这种设计让子代理可以专注完成任务,返回简洁的结果给主 Agent 合成。
人在环中 (Human in the Loop)
人在环中 (Human in the Loop, HITL) 是一种安全机制,允许在危险操作执行前等待人类批准。
这对于:
- 防止意外删除文件
- 防止执行危险命令
- 审核敏感操作
- 符合安全合规要求
工作原理
1. 配置需要审批的工具
python
agent = create_deep_agent(
interrupt_on={
"edit_file": True, # 编辑文件前需要批准
"write_file": True, # 写入文件前需要批准
"execute": True, # 执行命令前需要批准
}
)
2. 执行流程
Agent 决定执行危险操作
↓
暂停 Agent 执行
↓
显示操作详情给用户
↓
用户决定:批准 / 拒绝 / 修改
↓
继续执行或取消
3. 详细配置
python
from langchain.agents.middleware import InterruptOnConfig
agent = create_deep_agent(
interrupt_on={
"edit_file": InterruptOnConfig(
allow_continue=True, # 允许跳过
auto_approve=False, # 不自动批准
),
"execute": InterruptOnConfig(
allow_continue=False, # 不允许跳过
auto_approve=False,
),
}
)
HumanInTheLoopMiddleware
实现原理
python
class HumanInTheLoopMiddleware(AgentMiddleware):
def __init__(self, interrupt_on: dict[str, bool | InterruptOnConfig]):
self._interrupt_on = interrupt_on
def wrap_tool_calls(self, tool_calls, state):
# 检查哪些工具需要审批
for call in tool_calls:
if call.tool_name in self._interrupt_on:
# 暂停执行,返回审批请求
return self._create_interrupt(call)
return tool_calls
InterruptOnConfig
python
class InterruptOnConfig:
allow_continue: bool = True # 允许用户选择"继续"跳过
auto_approve: bool = False # 自动批准(危险!)
检查点要求
人在环中功能需要配置检查点 (checkpointer):
python
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(
checkpointer=MemorySaver(),
interrupt_on={"edit_file": True},
)
原因:暂停后需要保存状态,批准后恢复执行。
上下文摘要:处理长对话
LLM 有上下文窗口限制(比如 200K token)。当对话很长时:
- 会达到窗口限制
- 性能下降
- 成本增加
摘要机制可以在上下文即将满时:
- 将历史对话压缩成摘要
- 用摘要替换原始历史
- 继续处理当前请求
SummarizationMiddleware
python
class SummarizationMiddleware(AgentMiddleware):
def __init__(self, model, backend, threshold=0.8):
self._model = model
self._backend = backend
self._threshold = threshold # 触发摘要的阈值
def wrap_model_request(self, request, state):
# 计算当前 token 使用率
token_count = count_tokens(request.messages)
limit = get_context_limit(self._model)
if token_count / limit > self._threshold:
# 需要摘要
summary = await self._summarize(request.messages)
request.messages = self._replace_with_summary(summary)
return request
摘要触发条件
默认当上下文使用率达到 80% 时触发:
python
threshold = 0.8 # 80% 触发
摘要过程
1. 检测需要摘要
python
# 计算当前消息的 token 数
token_count = estimate_token_count(messages)
max_tokens = get_model_max_tokens(model)
if token_count > max_tokens * threshold:
# 需要触发摘要
2. 生成摘要
调用 LLM 生成历史摘要:
python
summary_prompt = f"""请总结以下对话的要点:
{format_messages_for_summary(messages)}
请用简洁的语言总结:
1. 已经完成的任务
2. 当前进行中的任务
3. 重要的上下文信息
"""
summary = await model.invoke(summary_prompt)
3. 替换历史
python
# 用摘要替换原始消息
summarized_messages = [
SystemMessage(content=f"Previous conversation summary: {summary}"),
*recent_messages, # 保留最近的几个消息
]
文件系统卸载
除了内存摘要,还可以将历史卸载到文件系统:
python
SummarizationMiddleware(
model=model,
backend=backend,
offload_to_filesystem=True, # 卸载到文件
offload_dir="/path/to/offload",
)
架构设计理念
1. 开箱即用
Deep Agents 的核心理念是"batteries included"------你不需要自己组装零件,拿来就能用。
2. 可定制
虽然默认配置已经很好,但你可以在任何层面定制:
- 替换模型
- 添加工具
- 修改提示
- 配置子 Agent
- 选择后端
3. 基于 LangGraph
所有 Agent 都是编译后的 LangGraph 图。这意味着你可以:
- 使用流式输出
- 与 LangGraph Studio 集成
- 使用检查点保存状态
- 使用任何 LangGraph 特性
4. Provider 无关
不依赖特定的 LLM 提供商。任何支持工具调用的模型都可以使用。
进阶配置与实战示例
安装
SDK
bash
pip install deepagents
# 或
uv add deepagents
CLI
bash
curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
第一个 Agent
python
from deepagents import create_deep_agent
agent = create_deep_agent()
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]})
添加自定义工具
python
from deepagents import create_deep_agent
def get_weather(city: str) -> str:
"""获取城市天气"""
return f"{city} 今天是晴天!"
agent = create_deep_agent(tools=[get_weather])
使用不同模型
python
from langchain.chat_models import init_chat_model
# OpenAI
agent = create_deep_agent(model="openai:gpt-4o")
# Anthropic
agent = create_deep_agent(model="anthropic:claude-opus-4-6")
# 或直接传入模型实例
agent = create_deep_agent(model=init_chat_model("openai:gpt-4o"))
配置后端
python
from deepagents.backends import FilesystemBackend
# 使用文件系统后端
agent = create_deep_agent(backend=FilesystemBackend(root_dir="/path/to/project"))
添加技能
python
agent = create_deep_agent(skills=["/path/to/skills/"])
添加记忆
python
agent = create_deep_agent(memory=["~/.deepagents/AGENTS.md"])
配置人在环中
python
agent = create_deep_agent(
interrupt_on={
"edit_file": True,
"execute": True,
}
)
添加子代理
python
agent = create_deep_agent(
subagents=[
{
"name": "reviewer",
"description": "代码审查专家",
"system_prompt": "你是一个严格的代码审查专家...",
}
]
)
使用检查点
python
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(checkpointer=MemorySaver())
# 保存状态
config = {"configurable": {"thread_id": "my-session"}}
agent.invoke({"messages": [...]}, config)
# 恢复状态
agent.invoke({"messages": [...]}, config)
完整示例
python
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import MemorySaver
from langchain.chat_models import init_chat_model
# 创建 Agent
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[my_custom_tool],
backend=FilesystemBackend(root_dir="/project"),
skills=["/skills/"],
memory=["~/.deepagents/AGENTS.md"],
subagents=[
{
"name": "reviewer",
"description": "代码审查专家",
"system_prompt": "你是一个专业的代码审查专家...",
}
],
interrupt_on={
"edit_file": True,
"execute": True,
},
checkpointer=MemorySaver(),
)
# 使用 Agent
result = agent.invoke({
"messages": [{"role": "user", "content": "帮我审查代码"}]
})
总结
create_deep_agent 是整个 SDK 的核心入口。它:
- 设置默认配置 - 模型、后端、中间件
- 构建中间件栈 - 按正确顺序组合所有功能
- 组合系统提示 - 用户提示 + 基础提示
- 创建 LangGraph Agent - 返回可用的 Agent 图
中间件是 Deep Agents 灵活性的核心:
- 拦截请求/响应 - 在合适的位置做合适的事情
- 动态工具 - 根据上下文决定提供什么工具
- 状态持久化 - 跨轮次维护状态
- 组合能力 - 多个中间件可以组合使用
后端系统是 Deep Agents 灵活性的另一个关键:
- 接口抽象 - 统一的后端协议
- 多种实现 - 内存、文件系统、沙箱、远程
- 可组合 - 可以组合多个后端
- 可扩展 - 轻松添加自定义后端
理解了这个函数和中间件系统,你就理解了 Deep Agents 的一半。
示例项目
如果你想深入了解 Deep Agents 的实际使用,推荐参考 https://github.com/seanzhang-zhichen/deepagents-demo 项目。