第四章:Deep Agents 默认 middleware 栈
Deep Agents 不是另起炉灶的 Agent runtime,它是把 LangChain agent loop 和一组默认 middleware 打包成 harness。createdeepagent(..., middleware=[...]) 里的自定义 middleware 会插入 Deep Agents
Deep Agents 不是另起炉灶的 Agent runtime,它是把 LangChain agent loop 和一组默认 middleware 打包成 harness。create_deep_agent(..., middleware=[...]) 里的自定义 middleware 会插入 Deep Agents 默认栈中间,而不是替换整个栈。
最小代码
代码在 deepagent_src/middleware_teach/04_deepagents_default_stack.py。
@before_model(name="custom_probe")
def custom_probe(state, runtime):
return None
agent = create_deep_agent(
model=FakeListChatModel(responses=["OK"]),
subagents=[],
middleware=[custom_probe],
)
graph_nodes = list(agent.get_graph().nodes.keys())
这章不调用模型,只编译 Deep Agent 并检查 LangGraph 节点。能稳定观察到的是:PatchToolCallsMiddleware.before_agent 在图里,你传入的 custom_probe.before_model 也在图里,并且排在 Patch 之后。
运行命令
uv run python -m deepagent_src.middleware_teach.04_deepagents_default_stack
预期现象
base_stack: SkillsMiddleware -> FilesystemMiddleware -> SubAgentMiddleware -> SummarizationMiddleware -> PatchToolCallsMiddleware -> AsyncSubAgentMiddleware -> your middleware
tail_stack: harness profile extras -> tool exclusion -> prompt caching -> MemoryMiddleware -> HumanInTheLoopMiddleware
graph_nodes: ['__start__', 'model', 'tools', 'PatchToolCallsMiddleware.before_agent', 'custom_probe.before_model', '__end__']
deepagents default stack local check ok
默认主栈顺序
根据当前本地 deepagents==0.7.0b2 的 create_deep_agent docstring,主 agent 的顺序是:
SkillsMiddleware:只有传skills时出现。FilesystemMiddleware:文件系统工具和权限的基础层。SubAgentMiddleware:同步 subagent /task工具。SummarizationMiddleware:上下文变长后的压缩。PatchToolCallsMiddleware:修复中断恢复或 malformed tool call 造成的悬空工具调用。AsyncSubAgentMiddleware:只有配置 async subagents 时出现。- 你传入的
middleware=[...]。 - Harness profile extras。
- excluded-tool filtering。
- prompt caching middleware。
MemoryMiddleware:只有传memory时出现。HumanInTheLoopMiddleware:只有传interrupt_on时出现。
常见误区
不要以为 middleware=[custom] 会让 Deep Agents 只剩你的 middleware。艹,不会。文件系统、subagent、summarization、patch、memory、HITL 这些默认能力仍然按栈顺序存在;你只是把自己的逻辑插进去。
另一个坑是“图节点看不到全部 middleware”。before_model / before_agent 这类 node-style hook 会变成可见节点;wrap_model_call / wrap_tool_call 这类 wrap-style hook 是包在模型或工具执行器周围的,通常不会作为独立节点出现在 get_graph().nodes。
和前面三章的关系
第一章、第二章、第三章讲的是 LangChain middleware 的基本钩子。Deep Agents 默认栈说明这些钩子在真实 harness 里怎么排列:你的模型层逻辑、工具层逻辑不是孤立跑的,而是夹在 Deep Agents 已经组装好的能力层里。
相关资源
查看示例代码:deepagent_src/middleware_teach/04_deepagents_default_stack.py
from __future__ import annotations from typing import Any from deepagents import create_deep_agent from langchain.agents.middleware import AgentState, before_model from langchain_core.language_models.fake_chat_models import FakeListChatModel from langgraph.runtime import Runtime BASE_STACK = [ "SkillsMiddleware", "FilesystemMiddleware", "SubAgentMiddleware", "SummarizationMiddleware", "PatchToolCallsMiddleware", "AsyncSubAgentMiddleware", "your middleware", ] TAIL_STACK = [ "harness profile extras", "tool exclusion", "prompt caching", "MemoryMiddleware", "HumanInTheLoopMiddleware", ] @before_model(name="custom_probe") def custom_probe( state: AgentState, runtime: Runtime[Any], ) -> dict[str, Any] | None: return None def main() -> None: agent = create_deep_agent( model=FakeListChatModel(responses=["OK"]), subagents=[], middleware=[custom_probe], ) graph_nodes = list(agent.get_graph().nodes.keys()) print("base_stack:", " -> ".join(BASE_STACK)) print("tail_stack:", " -> ".join(TAIL_STACK)) print("graph_nodes:", graph_nodes) patch_node = "PatchToolCallsMiddleware.before_agent" custom_node = "custom_probe.before_model" assert patch_node in graph_nodes, graph_nodes assert custom_node in graph_nodes, graph_nodes assert graph_nodes.index(patch_node) < graph_nodes.index(custom_node), graph_nodes print("deepagents default stack local check ok") if __name__ == "__main__": main()