Deep Agents 深度解析:不只是又一个 Agent 框架

拆解 LangChain 最新开源的 Deep Agents 项目,看看这个"batteries-included agent harness"到底"含"了哪些电池,以及背后的设计哲学是什么。


一、定位:它到底是什么?

Deep Agents 不是一个新的 Agent 框架,它是一个高度定制的 Agent Harness——站在 LangGraph 和 LangChain create_agent 的肩膀上,给你一套开箱即用的 Agent 实现。官方的比喻很精准:

LangGraph 是发动机,LangChain create_agent 是一台基础车,Deep Agents 是一台把所有选配都装好的高配车。

这意味着你可以直接用,也可以把任何一个部件换掉——不需要 fork,直接 override

相比 LangChain create_agent,Deep Agents 多了什么?

能力 LangChain create_agent Deep Agents
工具调用
多轮对话
子 Agent 委托 ❌ 自己实现 ✅ 内置
文件系统操作 ❌ 自己实现 ✅ 可插拔后端
上下文管理(自动压缩) ✅ 自动/手动
Shell 执行 ✅ 可配置沙箱
跨会话记忆 ✅ 可插拔
Human-in-the-Loop ✅ 内置
Skills 技能系统
MCP 工具
生产部署 需要自己搭 ✅ LangSmith 全链路

二、核心架构:Middleware 模式

Deep Agents 的核心设计模式是 Middleware——每个功能都以中间件的方式注入到 Agent 的生命周期中。这种设计带来的好处是:

  1. 洋葱模型:每个中间件可以包裹模型调用前后,形成层次化的处理管道
  2. 可组合:任意增加、移除、替换中间件,不影响其他功能
  3. 关注点分离:每个中间件只做一件事,不互相耦合
from deepagents import create_deep_agent

agent = create_deep_agent(
    model="openai:gpt-5.5",
    middleware=[
        FilesystemMiddleware(backend=my_backend),
        SubAgentMiddleware(...),
        SummarizationMiddleware(...),
        HumanInTheLoopMiddleware(...),
    ],
)

默认中间件栈

当你调用 create_deep_agent() 时,它自动组装了一套完整的中间件栈,大致如下:

    请求进入
       │
       ▼
┌─────────────────────────┐
│  PromptMiddleware        │  ← 注入系统提示词
├─────────────────────────┤
│  TodoListMiddleware      │  ← 任务规划(TodoWrite 工具)
├─────────────────────────┤
│  FilesystemMiddleware    │  ← 文件读写/编辑/搜索
├─────────────────────────┤
│  SubAgentMiddleware      │  ← 子 Agent 委托
├─────────────────────────┤
│  SummarizationMiddleware │  ← 上下文压缩
├─────────────────────────┤
│  HumanInTheLoopMiddleware│  ← 人工审批
├─────────────────────────┤
│  SkillsMiddleware        │  ← 动态加载技能
├─────────────────────────┤
│  ToolsMiddleware         │  ← 用户自定义 + MCP 工具
└─────────────────────────┘
       │
       ▼
   LLM 调用

三、子 Agent(Sub-Agent)机制

3.1 核心问题

传统单 Agent 在复杂任务中面临两个挑战:

  • 上下文窗口污染:子任务的分析过程占据大量 context,影响主任务质量
  • 角色混淆:Agent 在处理不同性质的任务时,难以维持一致的角色定位

3.2 设计思想

Sub-Agent 的本质是上下文隔离 + 委托执行 + 结果回收。主 Agent 将子任务"外包"给一个拥有独立上下文窗口的子 Agent,子 Agent 完成任务后返回结果,主 Agent 继续推进。

主 Agent 上下文                子 Agent 上下文
┌──────────────────┐         ┌──────────────────┐
│ "分析项目结构"    │         │                  │
│ "读取 README"     │ spawn   │ 独立分析         │
│ "写研究报告..."   │ ──────► │ 文件读写         │
│                   │         │ 子任务规划       │
│                   │ ◄────── │                  │
│ 回收结果,继续... │  result │                  │
└──────────────────┘         └──────────────────┘

3.3 实现亮点

从代码中可以看到,Sub-Agent 的创建支持非常灵活的配置:

# 预设模板
"research"       # 研究型子 Agent
"coding"         # 编码型子 Agent
"general"        # 通用型子 Agent

# 通用创建
create_subagent(
    name="my_agent",
    description="做什么的",
    system_prompt="自定义提示词",
    tools=[...],             # 子 Agent 的专属工具
    middleware=[...],        # 子 Agent 的专属中间件
    model="...",             # 可以指定不同模型
)

子 Agent 可以拥有与主 Agent 完全不同的工具集(或者共享部分工具),这意味着你可以给编码子 Agent 配备 Shell 和文件工具,而给研究子 Agent 配备搜索引擎——按需配置,不浪费 context


四、上下文管理(Context Management)

这是 Deep Agents 最"硬核"的三个功能之一。让我从代码层面深入剖析。

4.1 问题定义

在长时间运行的 Agent 会话中,消息历史会不断膨胀。一个复杂编程任务可能产生几百条消息、几十万 tokens——远超任何模型的上下文窗口。

4.2 三层上下文压缩策略

深入读了源码后,我发现 Deep Agents 的上下文管理实际上分三个层次

第一层:工具参数截断(Truncate Args)

在触发完整摘要之前,先对旧消息中的大参数做轻量级裁剪。代码中的 _truncate_args 方法只针对 write_fileedit_fileargs 做截断:

原始: write_file(path="main.py", content="(5000行代码)")
截断: write_file(path="main.py", content="import os\nimport...(argument truncated)")

这层策略的精妙之处在于:

  • 触发阈值比完整摘要低(默认 20 条消息或 10% context window)
  • 只影响旧消息,最新 20 条消息保持完整
  • 不需要 LLM 调用,纯计算操作,零成本

第二层:自动摘要压缩(Auto Summarization)

当 token 使用量达到触发阈值(默认 85% context window),自动触发摘要。核心流程:

1. 计算 cutoff_index(保留最近 N 条消息)
2. 将 cutoff 之前的历史 → 写入后端文件 → 生成 LLM 摘要
3. 用摘要 HumanMessage 替代所有旧消息
4. 模型看到的是: [摘要消息] + [保留的最近消息]

关键实现细节(从 wrap_model_call 代码中看到):

# Step 1: 先尝试不摘要的调用
if not should_summarize:
    try:
        return handler(request.override(messages=truncated_messages))
    except ContextOverflowError:
        # 如果模型报 context overflow,fallback 到摘要路径
        pass

# Step 2: 摘要 + 重试
messages_to_summarize, preserved_messages = _partition_messages(...)
file_path = _offload_to_backend(backend, messages_to_summarize)
summary = _create_summary(messages_to_summarize)

这个设计非常聪明

  • 正常情况下走 threshold 检查
  • 如果 provider 突然报 ContextOverflowError(比如 token 计算不准),自动 fallback 到摘要
  • 非破坏性:使用 wrap_model_call 而非直接修改 state["messages"],原始消息历史完整保留
  • 摘要链式支持:第二次摘要时自动过滤上一次的摘要消息,不重复存储

第三层:手动压缩工具(compact_conversation)

Agent 自己可以主动调用 compact_conversation 工具来压缩上下文。这在以下场景特别有用:

  • 任务切换:上一个任务的分析过程不再需要
  • 阶段性总结:提取关键信息后可以压缩

有趣的是,代码中设置了 50% 触发阈值的 eligibility gate——在上下文还没达到 auto-summarization 触发阈值的一半时,手动压缩会返回"Nothing to compact"。

4.3 大工具结果处理(Large Tool Result Offloading)

代码中的 _message_eviction.py 专门处理单个工具结果的 offload。当某个 ToolMessage 的内容过大时:

TOO_LARGE_TOOL_MSG = """Tool result too large, the result was saved at: {file_path}

Here is a preview showing the head and tail of the result:
{content_sample}
"""
  • 完整结果写入后端文件(路径包含 tool_call_id 供回溯)
  • 消息中只保留 head(前5行)+ tail(后5行)预览
  • Agent 需要用 read_file 工具按需读取完整结果

4.4 后端存储策略

压缩掉的消息不丢失,统一追加到:

/conversation_history/{thread_id}.md

每次压缩在文件中追加一个新 section:

## Summarized at 2026-05-30T22:04:00+00:00

Human: ...
AI: ...
Tool: ...

这个设计让 Agent 在需要时可以 read_file 回到历史中去查找细节。


五、文件系统中间件

5.1 设计哲学

Deep Agents 通过 CompositeBackendFilesystemMiddleware 实现了统一的文件操作接口。核心设计:

  • 三层后端体系StateBackend(对话级临时存储)、FilesystemBackend(本地磁盘)、StoreBackend(跨会话持久化)
  • 统一 API:所有后端实现 read/write/edit/ls/grep 等接口,对 Agent 透明
  • 资源路由:不同级别的资源(临时文件、项目文件、持久数据)自动路由到对应后端

5.2 关键机制

                CompositeBackend
                      │
         ┌────────────┼────────────┐
         ▼            ▼            ▼
   StateBackend  FilesystemBackend  StoreBackend
   /memory_memory/       /            /store/
   对话级缓存          项目文件      跨会话数据

每次工具调用时,后端会根据资源路径自动选择对应的存储层。Agent 不需要关心文件存在哪里。


六、可插拔后端

6.1 协议设计

从代码中可以看到,所有后端都遵循 BackendProtocol

# 核心接口
class BackendProtocol:
    # 基础 CRUD
    async def aread(paths) -> list[FileResponse]
    async def awrite(path, content) -> Result
    async def aedit(path, old_content, new_content) -> Result
    
    # 列表与搜索
    async def als(paths) -> list[DirectoryResponse]
    async def agrep(pattern, paths) -> list[GrepMatch]
    
    # 批量传输
    async def aupload(paths) -> ...
    async def adownload_files(paths) -> ...

这意味着你可以把 Deep Agents 的后端从本地文件系统一键切换到

  • StateBackend:纯内存,对话级生命周期
  • FilesystemBackend:本地磁盘或沙箱
  • StoreBackend:跨会话持久化(通过 LangGraph Store)
  • CompositeBackend:组合多个后端,按路径前缀自动路由
  • 自定义后端:实现 BackendProtocol 即可接入任何存储(S3、数据库、分布式文件系统…)

6.2 CompositeBackend 的资源路由

/                          → FilesystemBackend (本地/沙箱)
/conversation_history/*    → StoreBackend (跨会话)
/memory_*                  → StateBackend (对话级)
/large_tool_results/*      → FilesystemBackend (按需读取)

七、生产级特性

7.1 Human-in-the-Loop

Deep Agents 内置了工具调用审批机制。Agent 在执行敏感操作(写文件、执行 Shell 命令、发送 HTTP 请求)前,需要人工审批:

HumanInTheLoopMiddleware(
    interrupts_on={
        "write_file": "always",     # 文件写入:总是审批
        "execute": "always",        # Shell:总是审批
        "read_file": "never",       # 文件读取:不审批
    }
)

支持三种审批结果:

  • Approve:批准执行
  • Edit:修改参数后批准
  • Reject:拒绝执行,Agent 收到拒绝反馈后调整策略

7.2 Skills 系统

Skills 是可复用的"行为包",Agent 在需要时动态加载:

# 每个 Skill 包含:
create_skill(
    name="pdf-reader",
    description="读取和解析 PDF 文件",
    tools=[PDFTool],
    middleware=[PDFMiddleware],
    system_prompt="你是一个 PDF 专家...",
)

Skills 的加载方式透明——Agent 看到 load_skill 工具,调用它获得新的能力和上下文。

7.3 MCP 集成

通过 Model Context Protocol (MCP) 协议接入外部工具服务器:

from deepagents.middleware.tools import MCPToolsMiddleware

agent = create_deep_agent(
    middleware=[
        tools_middleware(
            mcp_servers={"search": {"command": "..."}}
        )
    ]
)

这让 Deep Agents 的工具生态可以无限扩展。


八、项目工程结构赏析

deepagents/
├── libs/
│   ├── deepagents/      # Python 核心库
│   ├── cli/             # 命令行工具
│   ├── code/            # Deep Agents Code(类 Claude Code 终端编码 Agent)
│   ├── acp/             # Agent Communication Protocol
│   ├── evals/           # 评估框架
│   └── partners/        # 合作伙伴集成
├── examples/            # 示例
└── .github/             # CI/CD + 自动评估 + SWE-bench

工程上值得注意的点:

  • Monorepo 结构:多个子包共享版本和 lint 规则
  • 自动化评估.github/workflows/evals.yml 每次 PR 自动跑评估
  • SWE-bench 集成.github/scripts/ 下有自动管理 SWE-bench PR 的脚本
  • Release Please:自动 changelog 生成和版本发布

九、总结:Deep Agents 的价值所在

它解决了什么问题?

LangGraph 给了你做 Agent 的所有"零件",但拼装成一套生产级的 Agent 需要大量代码——上下文压缩、子 Agent 委托、沙箱隔离、人工审批……这些都不是 Agent 框架本身的范畴,但缺了这些,Agent 没法真正干活

Deep Agents 把这些"工程化电池"装好了,让你不用从零搭。

谁适合用?

场景 适合度
原型验证 → 直接想用 ⭐⭐⭐⭐⭐
复杂多步骤任务 Agent ⭐⭐⭐⭐⭐
生产级 Agent 部署 ⭐⭐⭐⭐⭐
只想要最小 Agent ⭐⭐ (用 LangChain create_agent 更轻)
深度定制 Agent 框架 ⭐⭐⭐ (可 override 任何组件)

核心设计模式

  1. Middleware 洋葱模型:一切功能都是中间件,组合自由
  2. Backend 可插拔协议:存储层完全解耦
  3. Sub-Agent 上下文隔离:复杂任务进行分治而不污染 context
  4. 三层上下文压缩:truncate → summarize → compact,渐进式处理
  5. 非破坏性状态管理:原始消息历史不丢失,压缩是可逆的

如果你正在构建一个需要做复杂、长周期任务的 AI Agent——研究、编码、数据分析——Deep Agents 是目前少有的把"工程化电池"装齐全的开源方案。


本文基于 Deep Agents 源码分析撰写。项目采用 MIT 协议,由 LangChain 团队维护。

posted @ 2026-05-31 09:46  古客  阅读(106)  评论(0)    收藏  举报