Deep Agents 架构全解:一个构建在 LangChain 与 LangGraph 之上的 Batteries-Included Agent Harness
【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents
Deep Agents 是一个"开箱即用(batteries-included)"的 Agent 框架(harness),它不是新的运行时,而是位于 LangChaincreate_agent()与 LangGraph 之上的意见化(opinionated)装配层。本文以 openwiki/architecture/overview.md 为核心骨架,结合仓库源码(libs/deepagents/deepagents/graph.py、libs/ARCHITECTURE.md 等)深入讲解三层依赖结构、create_deep_agent()的构造与执行边界、中间件栈的组装顺序、状态与持久化设计、monorepo 各包职责边界,以及安全的变更与测试路径。读完本文,你将能够在一个变更发生时迅速定位到正确的代码层,并理解 harness、通用 Agent 抽象与图运行时各自拥有什么行为。
三层架构与依赖方向
Deep Agents 的定位非常明确:它是一个意见化的 harness,而不是替代 LangChain/LangGraph 的运行时。所有行为都可以映射到三层栈中的某一层,这也是任何变更的起点——先在架构上定位行为归属,再顺着create_deep_agent()的某个参数追踪到实现它的中间件、后端、profile 或消费产品。
每一层拥有什么
三层栈的划分如下:
- LangGraph拥有持久的图执行能力:步骤间携带的状态、checkpoint、流式(streaming)输出,以及基于 interrupt 的暂停/恢复。
- LangChain
create_agent()拥有通用 Agent 抽象:模型、工具、中间件,以及它构建在 LangGraph 之上的"模型-工具-循环"(model/tool/repeat loop)。 - Deep Agents拥有上述抽象之上的开箱即用策略:默认中间件、后端(backends)、profile、子代理(subagents)、技能(skills)与记忆(memory)配置。它不引入不同的运行时。
依赖方向是Deep Agents → LangChaincreate_agent()→ LangGraph。这给出了一个递进的选择模型:需要完整 harness 用 Deep Agents;需要一个更轻的 Agent 循环用裸的create_agent();当循环本身必须是自定义图时,直接用 LangGraph。而且这个边界是可组合的——一个 LangGraphCompiledStateGraph可以作为一个 Deep Agents 子代理被接入。
在 libs/ARCHITECTURE.md 中可以看到更细致的描述:本仓库中绝大多数 Deep Agents 专属代码集中在三处——middleware向 Agent 循环添加 harness 行为,backends决定文件、记忆与 shell 执行驻留在哪里,profiles针对特定 provider 或模型调优 harness。理解这三类组件的分工,是阅读后续所有章节的前提。
SDK 构造、执行与安全护栏
create_deep_agent()定义在 libs/deepagents/deepagents/graph.py,是整个 SDK 的集成边界(integration boundary)。它在构造期完成以下工作:
- 解析模型(model)与适用的 harness profile;
- 按需重写工具描述(tool description overrides);
- 默认选择
StateBackend()作为后端; - 组合调用方系统提示词与 profile 提示词;
- 处理子代理(declarative / compiled / async 三种形态);
- 把组装好的模型、工具、中间件、schema、checkpointer、store、debug、name、cache 全部委托给 LangChain
create_agent(...)。
返回的图携带 Deep Agents 元数据,并设置了9,999 的递归上限(recursion limit)。函数末尾的实现(libs/deepagents/deepagents/graph.py#L956-L978)展示了最终委托调用:create_agent(...).with_config({"recursion_limit": 9_999, "metadata": {...}}),元数据中包含ls_integration: "deepagents"、Deep Agents 版本号与lc_agent_name。对应的单元测试 libs/deepagents/tests/unit_tests/test_graph.py(如test_ls_integration_metadata_preserved、test_versions_metadata_reports_release_for_wheel_install)验证了这些元数据与版本信息的写入。
这就是构造与执行的边界:SDK 负责构建配置,LangGraph 负责驱动被 invoke 的图。
中间件栈的顺序与定制点
主中间件栈是有顺序的(ordered)。结合源码(libs/deepagents/deepagents/graph.py#L861-L938)与 openwiki/architecture/middleware-stack.md 的详细拆解,装配逻辑为:
核心带(core band),按序:
SkillsMiddleware——仅在传入了skills时加入;FilesystemMiddleware——内置文件工具与权限执行的载体;SubAgentMiddleware——存在同步内联子代理(通常因默认 general-purpose 子代理被自动添加)时加入;- Deep Agents 的 summarization 中间件(可截断旧的大工具参数、压缩历史、在
ContextOverflowError后通过 compaction 重试); PatchToolCallsMiddleware——工具调用修补;AsyncSubAgentMiddleware——存在远程 async 子代理 spec 时加入。
尾部带(tail band),按序:
- 实例化后的
HarnessProfile.extra_middleware; - provider 的 prompt-caching 中间件(Anthropic 无条件安装、对非 Anthropic 模型 no-op;Bedrock 与 Fireworks 变体仅当对应集成包可导入时添加);
MemoryMiddleware——传入了memory时加入;HumanInTheLoopMiddleware——解析出的 interrupt 映射非空时加入。
缓存中间件故意放在 memory 之前:profile extras 在缓存前运行,而 memory 对系统提示词的修改发生在 Anthropic 缓存前缀之后,避免 memory 更新使缓存前缀失效。
调用方(caller)自定义中间件的插入规则由_apply_custom_middleware(libs/deepagents/deepagents/graph.py#L204-L238)实现:按.name合并而非盲目追加——若调用方条目与栈中现存名称相同,则原位替换保持栈序;新名称则插入最后一个核心成员之后、profile extras/prompt-caching/memory/审批之前。profile 的排除(excluded_middleware)在调用方中间件合并前后各执行一次过滤,工具排除(_ToolExclusionMiddleware)则最后追加——这样后续任何自定义中间件都无法"复活"被排除的工具。
子代理的三种形态与各自边界
子代理在构造期按形态分派(源码见 libs/deepagents/deepagents/graph.py#L663-L788):
- 含
graph_id的 spec 是AsyncSubAgent,由AsyncSubAgentMiddleware以非阻塞后台任务方式运行(当前支持通过 LangSmith deployments 部署的代理); - 含
runnable的是CompiledSubAgent,按调用方预编译的 runnable 原样使用; - 其余为declarative SubAgent,各自独立解析自己的模型与 harness profile,构建独立的中间件栈(Filesystem + summarization + PatchToolCalls,加上自身 skills 或 fork 继承的父 skills、profile extras、prompt caching、两轮排除过滤与覆盖率校验)。
declarative 子代理只在省略某字段时继承顶层tools、permissions与interrupt_on;自己提供的permissions会整体替换父规则而不是扩展。默认模式是isolated(子代理只收到承载委托任务的HumanMessage而非父对话),handoff是其遗留别名;实验性的fork模式则继承父对话的有效压缩历史并重建父提示词,且 fork 子代理不允许定义独立 skills,也不允许递归调用task。若未提供名为general-purpose的子代理且 profile 未禁用,harness 会自动添加默认通用子代理。
工具可见性 ≠ 授权
一个重要的排障原则:工具不可见,通常指向中间件装配问题或 profile 工具排除;工具可见但调用失败,则指向所选后端的能力或文件系统权限执行问题。
文件系统权限(permissions)由内置的FilesystemMiddleware在其内置文件工具层强制执行,而不是在后端层——直接使用后端不会经过这些中间件权限规则。permissions规则按声明顺序求值、首个匹配生效,支持allow/deny/interrupt三种 mode;interrupt模式会安装 human-in-the-loop 中间件,并在配置的调用前暂停等待人工审批。权限派生出的 interrupt 配置与用户interrupt_on合并时,同名工具以用户条目优先(_merge_fs_interrupt_on,libs/deepagents/deepagents/graph.py#L185-L201)。
DeepAgentState 与状态/持久化边界
DeepAgentState扩展了 LangChain 的AgentState,将messages字段挂到DeltaChannelreducer 上(snapshot frequency 为 50),使长线程的 checkpoint 增长从二次方降到线性(见 libs/deepagents/deepagents/graph.py#L73-L76)。自定义状态 schema 必须继承DeepAgentState才能保留该 reducer(由于TypedDict继承无法在运行时检查,这是一个仅靠类型系统约束的契约)。该 schema 与中间件贡献的 schema 合并后转发给 declarative 子代理;compiled 与 remote 子代理则需要自行编译/配置所需的状态。
持久化同样分两层:图状态与 checkpoint 属于 LangGraph(对话状态、消息历史、interrupt、可恢复性);文件与记忆的持久化属于 Deep Agents 后端(默认StateBackend是线程级作用域,store-backed 或 filesystem-backed 路由可以让文件跨线程持久或映射到磁盘/沙箱存储)。
Fail-Closed 的构造校验
构造期会拒绝不安全或无效的 profile 排除配置:受保护脚手架(FilesystemMiddleware与SubAgentMiddleware,即_REQUIRED_MIDDLEWARE定义的集合,见 libs/deepagents/deepagents/graph.py#L241-L268)、私有(下划线前缀)名称、歧义的类匹配、以及未匹配到任何已装配中间件的条目,都会抛出ValueError。字符串排除项按AgentMiddleware.name精确匹配(公共别名如SummarizationMiddleware可以命中实现类),类条目按精确类型而非isinstance匹配。这样做是为了让 profile 配置失败关闭(fail closed),而不是静默地产生一个残缺的 harness。
产品层与集成层:monorepo 的职责边界
libs/是一个各包独立版本化的 monorepo。下表中的边界把"可复用的 harness 行为"与"消费它的应用和适配器"区分开来——通用图策略放在 SDK,终端表现、协议适配、宿主生命周期、行为测量、供应商行为与工作流编排放在各自的消费者中。
| 包 | 架构角色 |
|---|---|
deepagents | 核心 SDK:create_deep_agent、中间件与可插拔后端。可复用的 harness 变更都应落在这里。 |
code(deepagents-code) | Deep Agents Code,以dcode命令暴露的终端编码应用,包含 Textual TUI、远程沙箱、记忆、技能与无头模式。其create_cli_agent()产品入口以 CLI 上下文 schema、复合后端、CLI 中间件、中断策略、子代理、checkpoint/store 与净化后的助手名称构造 SDK 代理。 |
acp(deepagents-acp) | Agent Client Protocol 适配器,用于在 Zed 等 ACP 编辑器中运行 Python Deep Agent。AgentServerACP运行传入的代理;配合持久化 LangGraph checkpointer 与load_sessions=True,可在进程重启后重载线程、校验原始工作目录并重放会话更新。dcode --acp通过 stdio 暴露预构建的编码代理。 |
evals(deepagents-evals) | 端到端行为评测套件。运行真实 LLM 代理、记录工具调用/文件变更/最终响应,再评估正确性与效率;Harbor 集成可运行 Terminal Bench 2.0 等沙箱化基准。 |
talon(deepagents-talon) | 实验性的本地单事件循环宿主,用于长期运行代理、频道适配器与 cron 调度。属 alpha 软件,明确缺乏生产级审批、管理员、沙箱隔离与多租户控制。 |
partners/ | 供应商与沙箱集成区:Daytona、Modal、Runloop、Vercel、QuickJS。 |
依赖方向为:deepagents-code消费deepagents;deepagents-evals与deepagents-talon同时消费 SDK 和 Code。依赖朝向 SDK 流动,而不是从 SDK 流向产品包。整体关系也可参考 libs/README.md 的包列表与 openwiki/architecture/source-map.md 的公共面映射。
dcode 的双运行时路径
值得强调的是,deepagents-code内部有两条刻意分离的运行时路径(详见 openwiki/architecture/code-agent.md):
- 普通交互式与无头模式:终端客户端与自有的本地
langgraph dev服务运行在不同进程。客户端拥有表现、输入与审批;服务端拥有模型、图、工具、记忆、技能、后端与 checkpoint。 dcode --acp:进程内 ACP 服务(stdio),构建本地会话图,既不启动langgraph dev也不用RemoteAgent。
这是所有权边界而非可互换的传输层——对普通服务端的改动必须独立评估其对 ACP 的影响。create_cli_agent()(libs/code/deepagents_code/agent.py)是 dcode 特有的 SDK 组装接缝,make_graph()(libs/code/deepagents_code/server_graph.py)是 LangGraph 服务端工厂。
Talon 生命周期与运维边界
Talon包装而非替换SDK 图(详见 libs/talon/deepagents_talon/runtime.py):
DeepAgentRuntime.start()解析子代理并构建create_deep_agent()图;默认后端是本地 shell 执行,默认 checkpointer 在内存中,因此需要持久历史的调用方必须自行提供宿主的持久 checkpoint/archive 配置;- 每个请求的
invoke()要求图已启动,先刷新运行时工具,建立请求级作用域的 authorization、history、cron、graph 与 background-result 上下文,然后持续调用直到获得文本;结束后总是重置这些上下文并确认已完成的 background 结果; stop()先取消后台子代理,再释放图并关闭可关闭的 checkpointer。
Talon 可以在 MCP 工具或子代理配置重载时重建图;失败的 MCP 刷新会让旧图保持可用并把已保存的变更标记为未激活。其安全警告是实质性的:在 Talon 仍属实验性期间,频道访问应被视为直接访问操作者的代理、凭据、MCP 工具与本地宿主资源。
实际的变更路径与测试路径
大多数 SDK 变更从 libs/deepagents/deepagents/graph.py 开始,再按行为归属进入middleware/、backends/或profiles/。扩展 harness 时必须保留中间件顺序与DeepAgentState的 reducer。产品专属的终端工作流属于code;ACP 协议/会话语义属于acp;频道生命周期、调度与宿主持久化属于talon;基准定义与评分属于evals。
测试策略上,先用聚焦测试,再跑宽泛套件:
- libs/deepagents/tests/unit_tests/test_graph.py 覆盖图构造与编译图元数据(profile、提示词顺序、不可变的工具重写、中间件顺序/排除、默认与自定义子代理、权限 interrupt 接线、自定义状态传播、元数据),以及该模块内其他的 profile 与状态行为;
- SDK 的 pytest 默认会排除带 benchmark 标记的测试,并把非预期的 warning 视为错误;
- 集成边界则使用各包本地的测试:ACP 会话处理(libs/acp/tests/test_agent.py)、Talon 运行时生命周期/重载行为(libs/talon/tests/test_runtime.py)、以及受变更影响的端到端评测轨迹(
evals包内)。
更多可深入的主题包括:中间件栈与定制边界、SDK 构造与执行细节、按职责划分的源码地图、ACP 与 Talon 集成、openwiki/integrations/talon.md,以及 dcode 产品架构 code-agent.md。
小结
Deep Agents 的价值不在于发明新的运行时,而在于把长期运行 Agent 通常需要的部件默认打包:有顺序的中间件栈、可插拔后端、provider 特定的 profile、三种形态的子代理、技能、记忆、权限与人工审批。只要掌握"harness 装配配置、LangChain 构建循环、LangGraph 驱动执行"这条依赖链,面对任何行为问题都能从create_deep_agent()的某个参数出发,一步步追踪到真正拥有该行为的中间件、后端、profile 或消费产品。
【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考