主题
中间件链机制
本章目标:
- 讲清 DeerFlow 为什么用 LangGraph
AgentMiddleware链来组织横切逻辑,而不是把这些逻辑塞进 LeadAgent 本体。- 逐个拆解约 18 个中间件的职责、实现的 hook、启用条件,以及它们在
build_lead_runtime_middlewares和_build_middlewares两处装配点的严格顺序与原因。- 给出自定义
AgentMiddleware的最小模板、hook 签名约束、装配位置选择,以及顺序敏感性等真实存在的踩坑点。
TL;DR
DeerFlow 的 LeadAgent 几乎不含横切逻辑:目录初始化、沙箱获取、上传注入、错误恢复、摘要压缩、循环检测、标题/记忆/Token 统计、澄清中断等全部由一条按 append 顺序构造的 AgentMiddleware 链承担。链分两段装配:共享基础段由 build_lead_runtime_middlewares(实为 _build_runtime_middlewares)产出,Lead 专属段由 _build_middlewares 追加,最后 create_agent(middleware=...) 把它编织进 LangGraph 图。每个中间件按需实现 before_agent / before_model / after_model / after_agent / wrap_model_call / wrap_tool_call 六类 hook,顺序决定 hook 触发的洋葱嵌套层级,因此顺序是语义的一部分而非风格。ClarificationMiddleware 必须最后、ThreadDataMiddleware 必须最先,这类约束在代码注释里写死并被本章源码核实。
Overview
为什么用中间件链,而不是把逻辑写进 Agent
一个生产级 super agent 在「调用模型 → 执行工具 → 再调用模型」的循环外,还需要做大量横切的事情:为线程创建隔离目录、获取沙箱、把上传文件注入对话、把工具异常转成可恢复的 ToolMessage、对过长上下文做摘要、检测重复调用循环、统计 Token、生成标题、异步入队记忆、拦截澄清请求并中断。如果把这些都写进 LeadAgent 工厂,会产生三个问题:(1) Agent 工厂变成上帝函数;(2) 条件开关(plan 模式、vision、tool_search、subagent、guardrails)散落在主流程里难以推理;(3) 这些逻辑无法在 LeadAgent 与 Subagent 之间复用。
DeerFlow 的选择是:LeadAgent 工厂 _make_lead_agent 只负责解析模型名、装配工具、生成系统提示,然后把一条中间件链交给 create_agentbackend/packages/harness/deerflow/agents/lead_agent/agent.py:434-446。所有横切逻辑被拆成独立的 AgentMiddleware 子类,每个只实现自己需要的 hook,启用与否由 AppConfig / RunnableConfig 决定。共享段 _build_runtime_middlewares 同时被 Lead(build_lead_runtime_middlewares)和 Subagent(build_subagent_runtime_middlewares)复用backend/packages/harness/deerflow/agents/middlewares/tool_error_handling_middleware.py:129-167,Subagent 执行器直接调用同一构造器backend/packages/harness/deerflow/subagents/executor.py:284-297。
中间件链是「洋葱模型」:wrap_model_call / wrap_tool_call 类 hook 形成嵌套包裹,链中靠前的中间件包在外层,靠后的包在内层。这意味着顺序即语义——例如 ToolErrorHandlingMiddleware 必须排在 ClarificationMiddleware 之前,否则澄清的 Command(goto=END) 控制流会被错误的异常处理吞掉。
Architecture
两处装配点
中间件链由两个函数协作构造,顺序通过 Python list 的 append / insert 显式控制:
共享基础段:
_build_runtime_middlewares(对外暴露为build_lead_runtime_middlewares)backend/packages/harness/deerflow/agents/middlewares/tool_error_handling_middleware.py:70-137。它产出ThreadDataMiddleware、SandboxMiddleware,按需insertUploadsMiddleware、appendDanglingToolCallMiddleware、LLMErrorHandlingMiddleware、可选GuardrailMiddleware,再固定appendSandboxAuditMiddleware、ToolErrorHandlingMiddleware。Lead 专属段:
_build_middlewares先调用上面的共享段,再依次appendDynamicContextMiddleware、可选DeerFlowSummarizationMiddleware、可选TodoMiddleware、可选TokenUsageMiddleware、TitleMiddleware、MemoryMiddleware、可选ViewImageMiddleware、可选DeferredToolFilterMiddleware、可选SubagentLimitMiddleware、可选LoopDetectionMiddleware、外部注入的custom_middlewares,最后无条件appendClarificationMiddlewarebackend/packages/harness/deerflow/agents/lead_agent/agent.py:240-318。
注意一处易错点:
_build_middlewares顶部有一段长注释列举顺序约定backend/packages/harness/deerflow/agents/lead_agent/agent.py:230-239,但实际顺序以两个函数的append/insert调用为准——注释里的相对顺序与运行时一致,本章已逐行核实。
DeerFlowClient 嵌入式路径复用同一个 _build_middlewares,额外支持 custom_middlewares 注入backend/packages/harness/deerflow/client.py:233。
顺序总览(以默认全开为例)
| # | 中间件 | 装配函数 | Source |
|---|---|---|---|
| 1 | ThreadDataMiddleware | _build_runtime_middlewares | agent...:82-85 |
| 2 | UploadsMiddleware | insert(1, ...)(仅 Lead) | ...:87-90 |
| 3 | SandboxMiddleware | _build_runtime_middlewares | ...:82-85 |
| 4 | DanglingToolCallMiddleware | append(条件) | ...:92-95 |
| 5 | LLMErrorHandlingMiddleware | append | ...:97 |
| 6 | GuardrailMiddleware | append(条件) | ...:99-120 |
| 7 | SandboxAuditMiddleware | append | ...:122-124 |
| 7.5 | ToolErrorHandlingMiddleware | append | ...:125 |
| 8 | DynamicContextMiddleware | _build_middlewares append | agent.py:263-265 |
| 9 | DeerFlowSummarizationMiddleware | append(条件) | agent.py:268-270 |
| 10 | TodoMiddleware | append(条件 plan) | agent.py:273-277 |
| 11 | TokenUsageMiddleware | append(条件) | agent.py:280-281 |
| 12 | TitleMiddleware | append | agent.py:284 |
| 13 | MemoryMiddleware | append | agent.py:287 |
| 14 | ViewImageMiddleware | append(条件 vision) | agent.py:291-293 |
| 15 | DeferredToolFilterMiddleware | append(条件) | agent.py:296-299 |
| 16 | SubagentLimitMiddleware | append(条件) | agent.py:302-305 |
| 17 | LoopDetectionMiddleware | append(条件,默认开) | agent.py:308-310 |
| — | custom_middlewares | extend(条件) | agent.py:313-314 |
| 18 | ClarificationMiddleware | append(永远最后) | agent.py:316-317 |
UploadsMiddleware用insert(1, ...)插在ThreadDataMiddleware之后、SandboxMiddleware之前;ToolErrorHandlingMiddleware是共享段最后一个append,故编号写作 7.5 表示它紧随 SandboxAudit。
Components / Subsystems
按装配顺序逐个说明。每条给出:一句话职责 / 关键类位置 / 实现的 hook / 启用条件。
1. ThreadDataMiddleware
- 职责:为每个线程计算/创建隔离目录(
workspace/uploads/outputs),并把run_id、timestamp补进最后一条HumanMessage的additional_kwargs。 - 类:thread_data_middleware.py:24-118。
- Hook:
before_agent(lazy_init=True时只算路径不建目录)thread_data_middleware.py:81-118。 - 启用:始终。必须最先,因为后续中间件依赖
thread_id/thread_data。
2. UploadsMiddleware
- 职责:把当前消息
additional_kwargs.files与历史上传目录中的文件,格式化成<uploaded_files>块预置到最后一条HumanMessage。 - 类:uploads_middleware.py:66-295。
- Hook:
before_agentuploads_middleware.py:187-295。 - 启用:仅 Lead(
include_uploads=True时insert(1, ...));Subagent 不含tool_error_handling_middleware.py:87-90。须在 ThreadData 之后(要 thread_id)。
3. SandboxMiddleware
- 职责:为线程获取沙箱并把
sandbox_id写入 state;沙箱跨多轮复用,不在每轮释放。 - 类:sandbox/middleware.py:21-84。
- Hook:
before_agent(lazy_init=True时延迟到首个工具调用)、after_agent(释放沙箱)sandbox/middleware.py:51-83。 - 启用:始终。
4. DanglingToolCallMiddleware
- 职责:历史里若
AIMessage的tool_calls(含invalid_tool_calls、原始additional_kwargs.tool_calls)缺失对应ToolMessage(如用户中断),在该AIMessage后插合成占位ToolMessage,保证发给模型的对话格式合法。 - 类:dangling_tool_call_middleware.py:29-185。
- Hook:
wrap_model_call/awrap_model_call(刻意不用before_model,以保证插入位置正确而非追加到末尾)dangling_tool_call_middleware.py:165-185。 - 启用:
include_dangling_tool_call_patch=True(Lead 与 Subagent 均开)。
5. LLMErrorHandlingMiddleware
- 职责:对模型调用做重试/退避(可解析
Retry-After)、错误分类(quota/auth/transient/busy)、熔断器(closed/open/half_open),失败时返回友好AIMessage而非抛出。 - 类:llm_error_handling_middleware.py:66-298。
- Hook:
wrap_model_call/awrap_model_call;显式raiseGraphBubbleUp以保留中断/暂停控制流llm_error_handling_middleware.py:208-252。 - 启用:始终(熔断阈值来自
app_config.circuit_breaker)。
6. GuardrailMiddleware
- 职责:工具执行前用可插拔
GuardrailProvider鉴权,拒绝则返回错误ToolMessage;provider 异常时按fail_closed决定放行或拦截。 - 类:guardrails/middleware.py:20-98。
- Hook:
wrap_tool_call/awrap_tool_call;同样保留GraphBubbleUpguardrails/middleware.py:54-98。 - 启用:
app_config.guardrails.enabled and guardrails.provider,provider 经resolve_variable反射加载tool_error_handling_middleware.py:99-120。
7. SandboxAuditMiddleware
- 职责:对
bash工具做安全审计——高危(rm -rf /、curl|sh、fork bomb 等)直接拦截返回错误ToolMessage,中危(pip install、chmod 777)放行但追加警告,所有 bash 调用写结构化审计日志。 - 类:sandbox_audit_middleware.py:197-364。
- Hook:
wrap_tool_call/awrap_tool_call(非 bash 直接透传)sandbox_audit_middleware.py:329-363。 - 启用:始终(
_build_runtime_middlewares固定 append)。
7.5 ToolErrorHandlingMiddleware
- 职责:把工具执行抛出的异常转成
status="error"的ToolMessage,让 agent 循环能继续而非整体中止。 - 类:tool_error_handling_middleware.py:21-67。
- Hook:
wrap_tool_call/awrap_tool_call;同样raise GraphBubbleUptool_error_handling_middleware.py:39-67。 - 启用:始终,是共享段最后一个 append。须排在
ClarificationMiddleware之前(见 Pitfalls)。
8. DynamicContextMiddleware
- 职责:把 per-user 记忆 + 当前日期作为
<system-reminder>注入首条HumanMessage(冻结快照,保系统提示静态以利前缀缓存);跨午夜则在当前轮前补一条日期更新提醒。 - 类:dynamic_context_middleware.py:81-204。
- Hook:
before_agent/abefore_agentdynamic_context_middleware.py:198-204。 - 启用:始终(记忆注入受
memory.injection_enabled门控,日期始终注入)。
9. DeerFlowSummarizationMiddleware
- 职责:接近 Token 上限时压缩历史;扩展了 LangChain 内置
SummarizationMiddleware,带 before_summarization hook 派发(如memory_flush_hook)、技能 bundle 抢救(保留近期加载的 skill 文件)、保留隐藏的 dynamic-context 提醒。 - 类:summarization_middleware.py:98-375。
- Hook:
before_model/abefore_model(→_maybe_summarize)summarization_middleware.py:120-176。 - 启用:
app_config.summarization.enabled,由_create_summarization_middleware工厂构造agent.py:53-112。
10. TodoMiddleware
- 职责:扩展 LangChain
TodoListMiddleware,提供write_todos;检测摘要后 todo 上下文丢失并注入提醒,阻止有未完成 todo 时过早退出(after_model注入完成提醒并jump_to: model,有_MAX_COMPLETION_REMINDERS=2上限)。 - 类:todo_middleware.py:107-359。
- Hook:
before_model/abefore_model、before_agent/abefore_agent、after_model/aafter_model(@hook_config(can_jump_to=["model"]))、wrap_model_call/awrap_model_call、after_agent/aafter_agenttodo_middleware.py:116-359。 - 启用:
config.configurable.is_plan_mode=True(经_create_todo_list_middleware)agent.py:115-227。
11. TokenUsageMiddleware
- 职责:记录模型响应 Token 用量日志;把 subagent token(按
tool_call_id缓存)合并回派发的AIMessage;在additional_kwargs写入 step 归因元数据供前端展示。 - 类:token_usage_middleware.py:267-358。
- Hook:
after_model/aafter_modeltoken_usage_middleware.py:352-358。 - 启用:
app_config.token_usage.enabled。
12. TitleMiddleware
- 职责:首轮完整交互后自动生成线程标题(异步路径调小模型,失败回退到截断的用户消息);归一化结构化消息内容、剥离
<think>标签。 - 类:title_middleware.py:29-184。
- Hook:
after_model(同步=本地回退)、aafter_model(异步=LLM 生成)title_middleware.py:178-184。 - 启用:始终(
config.title.enabled在_should_generate_title内部判定)。
13. MemoryMiddleware
- 职责:agent 执行完把对话(过滤为用户输入 + 最终 AI 回复)入队做异步记忆更新;入队时捕获
user_id(因threading.Timer不传 ContextVar)。 - 类:memory_middleware.py:28-110。
- Hook:
after_agentmemory_middleware.py:52-110。 - 启用:始终(
memory.enabled在after_agent内部判定),装配在 TitleMiddleware 之后。
14. ViewImageMiddleware
- 职责:上一轮
view_image工具全部完成后,模型调用前把已查看图片的 base64 数据作为HumanMessage(混合文本+image_url 块)注入,使模型能"看"图。 - 类:view_image_middleware.py:19-223。
- Hook:
before_model/abefore_modelview_image_middleware.py:190-223。 - 启用:
model_config.supports_vision(Lead 用运行时解析的model_name;Subagent 在build_subagent_runtime_middlewares内判定)agent.py:289-293。
15. DeferredToolFilterMiddleware
- 职责:tool_search 开启时,从
request.tools移除已延迟(deferred)的工具 schema,使模型只 bind 活跃工具;若模型仍调用未提升的延迟工具,返回提示先调tool_search的错误ToolMessage。 - 类:deferred_tool_filter_middleware.py:26-107。
- Hook:
wrap_model_call/awrap_model_call(过滤)、wrap_tool_call/awrap_tool_call(拦截未提升调用)deferred_tool_filter_middleware.py:71-107。 - 启用:
app_config.tool_search.enabled。
16. SubagentLimitMiddleware
- 职责:单次模型响应中并行
task调用超限时,截断保留前max_concurrent个(钳制在 [2,4]),用clone_ai_message_with_tool_calls保持原始 provider 元数据同步。 - 类:subagent_limit_middleware.py:25-76。
- Hook:
after_model/aafter_modelsubagent_limit_middleware.py:70-76。 - 启用:
config.configurable.subagent_enabled=Trueagent.py:301-305。
17. LoopDetectionMiddleware
- 职责:两层检测——(1) hash 相同工具调用集合达阈值注入警告 / 硬上限剥离
tool_calls强制出文本;(2) 同一工具类型按频次告警/硬停。硬停时清空结构化与原始 provider tool-call 元数据。 - 类:loop_detection_middleware.py:144-440。
- Hook:
after_model/aafter_modelloop_detection_middleware.py:419-425。 - 启用:
app_config.loop_detection.enabled,默认Trueconfig/loop_detection_config.py:27-30;经from_config构造。
18. ClarificationMiddleware
- 职责:拦截
ask_clarification工具调用,格式化问题(含 options/icon),返回Command(update=..., goto=END)中断执行把问题抛给用户;用确定性 message id 让重试的澄清替换而非追加。 - 类:clarification_middleware.py:25-201。
- Hook:
wrap_tool_call/awrap_tool_call(非ask_clarification直接透传)clarification_middleware.py:158-201。 - 启用:始终,且永远是最后一个 appendagent.py:316-317。
Data Flow
下面是一次完整 model 调用前后,中间件按链顺序触发的时序(只画装配全开时的关键 hook;wrap_* 是嵌套包裹,靠前的在外层):
LangGraph agent 内部的节点级状态机(before_agent/after_agent 包住整轮,before_model/after_model 包住每次模型调用):
速查表
全部中间件 × hook 矩阵。✓ 表示该类实现了对应 hook(含其 a* 异步对偶)。wrap_model 含 wrap_model_call,wrap_tool 含 wrap_tool_call。
| 中间件 | before_agent | before_model | after_model | after_agent | wrap_model | wrap_tool | 启用条件 | 来源(装配函数) | Source |
|---|---|---|---|---|---|---|---|---|---|
| ThreadDataMiddleware | ✓ | 始终 | 共享段 | L24-118 | |||||
| UploadsMiddleware | ✓ | Lead 专属 | 共享段 insert | L66-295 | |||||
| SandboxMiddleware | ✓ | ✓ | 始终 | 共享段 | L21-84 | ||||
| DanglingToolCallMiddleware | ✓ | patch 标志 | 共享段(条件) | L29-185 | |||||
| LLMErrorHandlingMiddleware | ✓ | 始终 | 共享段 | L66-298 | |||||
| GuardrailMiddleware | ✓ | guardrails.enabled | 共享段(条件) | L20-98 | |||||
| SandboxAuditMiddleware | ✓ | 始终 | 共享段 | L197-364 | |||||
| ToolErrorHandlingMiddleware | ✓ | 始终 | 共享段 | L21-67 | |||||
| DynamicContextMiddleware | ✓ | 始终 | Lead 段 | L81-204 | |||||
| DeerFlowSummarizationMiddleware | ✓ | summarization.enabled | Lead 段(条件) | L98-375 | |||||
| TodoMiddleware | ✓ | ✓ | ✓ | ✓ | ✓ | is_plan_mode | Lead 段(条件) | L107-359 | |
| TokenUsageMiddleware | ✓ | token_usage.enabled | Lead 段(条件) | L267-358 | |||||
| TitleMiddleware | ✓ | 始终(内部判 title.enabled) | Lead 段 | L29-184 | |||||
| MemoryMiddleware | ✓ | 始终(内部判 memory.enabled) | Lead 段 | L28-110 | |||||
| ViewImageMiddleware | ✓ | model.supports_vision | Lead 段(条件) | L19-223 | |||||
| DeferredToolFilterMiddleware | ✓ | ✓ | tool_search.enabled | Lead 段(条件) | L26-107 | ||||
| SubagentLimitMiddleware | ✓ | subagent_enabled | Lead 段(条件) | L25-76 | |||||
| LoopDetectionMiddleware | ✓ | loop_detection.enabled(默认开) | Lead 段(条件) | L144-440 | |||||
| ClarificationMiddleware | ✓ | 始终(永远最后) | Lead 段 | L25-201 |
ViewImageMiddleware 也出现在 Subagent 共享段(当 subagent 模型支持 vision 时)tool_error_handling_middleware.py:161-167。
扩展指南
自定义 AgentMiddleware 最小模板
所有 hook 签名从源码读出:before_agent/after_agent/before_model/after_model(self, state, runtime) -> dict | None;wrap_model_call(self, request: ModelRequest, handler) -> ModelCallResult;wrap_tool_call(self, request: ToolCallRequest, handler) -> ToolMessage | Command。异步对偶在方法名前加 a(abefore_model、awrap_tool_call 等)。返回 dict 即对 state 的增量更新(走 LangGraph reducer);返回 None 表示不改 state。
python
from typing import override
from collections.abc import Callable
from langchain.agents import AgentState
from langchain.agents.middleware import AgentMiddleware
from langchain.agents.middleware.types import ModelCallResult, ModelRequest, ModelResponse
from langchain_core.messages import ToolMessage
from langgraph.errors import GraphBubbleUp
from langgraph.prebuilt.tool_node import ToolCallRequest
from langgraph.runtime import Runtime
class MyMiddleware(AgentMiddleware[AgentState]):
"""一句话职责。"""
@override
def before_model(self, state: AgentState, runtime: Runtime) -> dict | None:
# 改写发给模型前的 state,如注入提醒消息
return None # 或 {"messages": [...]}
@override
def wrap_tool_call(
self,
request: ToolCallRequest,
handler: Callable[[ToolCallRequest], ToolMessage | Command],
) -> ToolMessage | Command:
try:
return handler(request)
except GraphBubbleUp:
raise # 必须:保留 interrupt/pause/resume 控制流
except Exception as exc:
return ToolMessage(content=f"Error: {exc}", tool_call_id=request.tool_call.get("id", ""), status="error")约束清单(均从代码读出)
- 必须继承
AgentMiddleware[StateSchema];若中间件需要新 state 键,定义class XxxState(AgentState)并设类属性state_schema = XxxState(见ThreadDataMiddleware/UploadsMiddleware/TitleMiddleware均用NotRequired字段扩展)。 - 只实现需要的 hook,空实现会调
super()(如SandboxMiddleware.before_agent在 lazy 时return super().before_agent(...))。 - 保留
GraphBubbleUp:wrap_*hook 里所有except必须先except GraphBubbleUp: raise,否则会吞掉 LangGraph 的中断/暂停/恢复信号——ToolError/Guardrail/LLMError三处都这么做。 - 修改
AIMessage的 tool_calls 时用clone_ai_message_with_tool_callstool_call_metadata.py:18-50,它会同步清理additional_kwargs.tool_calls、function_call、response_metadata.finish_reason,否则严格的 OpenAI 兼容校验会因结构化/原始 tool_calls 不一致而 400。 after_model想跳回模型需加@hook_config(can_jump_to=["model"])并返回{"jump_to": "model"}(见TodoMiddleware.after_model)。- 装配位置怎么加:把实例
append进_build_middlewares——若是工具/模型横切且 Lead/Subagent 共用,放进_build_runtime_middlewares;若 Lead 专属,放进_build_middlewares;务必排在ClarificationMiddleware(永远最后)之前。DeerFlowClient路径还可通过custom_middlewares参数注入,会被extend到 Clarification 之前agent.py:312-317。
Common Pitfalls / Tips
- 顺序敏感性是硬约束:
ToolErrorHandlingMiddleware必须在ClarificationMiddleware之前。Clarification 通过wrap_tool_call返回Command(goto=END)中断;若 ToolError 包在它内层(更靠后),澄清的控制流不会被影响,但若顺序反了,异常处理可能把澄清逻辑吞掉——这正是注释明确写「ToolErrorHandlingMiddleware should be before ClarificationMiddleware」的原因agent.py:238-239。 - ThreadData 必须最先:
UploadsMiddleware、SandboxMiddleware等都依赖thread_id/thread_data,所以它是共享段第一个,UploadsMiddleware用insert(1, ...)紧随其后tool_error_handling_middleware.py:82-90。 - DanglingToolCall 刻意不用
before_model:文件头注释明确说,用before_model+add_messagesreducer 会把补丁追加到消息末尾而非紧跟悬空AIMessage,所以必须用wrap_model_call在 request 层重排dangling_tool_call_middleware.py:11-13。 - LoopDetection 警告注入是已知临时方案:
_apply把警告追加进AIMessagecontent 而非插独立HumanMessage,因为在after_model时 tools 节点还没跑,插非 tool 消息会破坏 OpenAI/Moonshot 严格的 tool_call 配对校验;副作用是警告文本会泄漏给 Memory/Title/telemetry,正解见 RFC #2517loop_detection_middleware.py:391-415。 - Summarization 必须保留 dynamic-context 提醒:否则
DynamicContextMiddleware会把摘要后的 summaryHumanMessage误当首条用户消息,在错误位置重注入提醒——_preserve_dynamic_context_reminders专门防这个summarization_middleware.py:185-201。 _build_middlewares顶部注释的顺序仅供参考:运行时顺序以append/insert实际调用为准,改顺序要改的是调用序列,不是注释。- 共享段被 Subagent 复用:在共享段加中间件会同时影响 Subagent;Subagent 不含
UploadsMiddleware且 Lead 专属段全部不参与 Subagenttool_error_handling_middleware.py:139-167。
References
- backend/packages/harness/deerflow/agents/middlewares/tool_error_handling_middleware.py —
_build_runtime_middlewares/build_lead_runtime_middlewares/build_subagent_runtime_middlewares与ToolErrorHandlingMiddleware - backend/packages/harness/deerflow/agents/lead_agent/agent.py —
_build_middlewaresLead 专属段装配 - backend/packages/harness/deerflow/agents/middlewares/dangling_tool_call_middleware.py — 悬空 tool_call 修补
- backend/packages/harness/deerflow/agents/middlewares/loop_detection_middleware.py — 双层循环检测与硬停
- backend/packages/harness/deerflow/agents/middlewares/clarification_middleware.py — 澄清拦截与
Command(goto=END) - backend/packages/harness/deerflow/agents/middlewares/summarization_middleware.py — 摘要扩展与技能抢救
- backend/packages/harness/deerflow/agents/middlewares/tool_call_metadata.py —
clone_ai_message_with_tool_calls - backend/packages/harness/deerflow/subagents/executor.py — Subagent 复用共享中间件段
Related Pages
| 页面 | 关系 |
|---|---|
| ./10-LeadAgent与Agent工厂.md | 上游:_make_lead_agent 调 _build_middlewares 并把链交给 create_agent,本章是其横切层 |
| ./11-ThreadState与状态管理.md | 中间件 hook 的 state 即 ThreadState,各 XxxState(AgentState) 扩展的键由其 reducer 合并 |
| ./23-长期记忆系统.md | MemoryMiddleware 在 after_agent 入队、DynamicContextMiddleware 注入记忆,本章给出装配位置 |
| ./33-上下文工程-摘要与循环检测.md | DeerFlowSummarizationMiddleware 与 LoopDetectionMiddleware 的算法细节在该章展开 |
| ./35-可观测性-Tracing与Token用量.md | TokenUsageMiddleware 的 Token 统计与 step 归因如何被 tracing 消费 |
| ./24-Guardrails安全守卫.md | GuardrailMiddleware 是本链中的一环,其 provider 协议与授权算法在 24 章展开 |