摘要LangChain 的 Middleware 机制是生产级 Agent 的核心能力相当于 Spring 的拦截器过滤器。本文用 15 个预构建中间件 6 个钩子点 自定义全流程实战帮你从 0 到 1 掌握 Agent 循环的精细化控制。含完整代码 流程图 避坑指南看完直接复用。关键词LangChain、Middleware、中间件、Agent、Hook、钩子、create_agent一、问题背景为什么需要中间件写 Agent 最常见的问题Agent 死循环烧 token怎么限制调用次数模型偶尔 429 限流怎么自动重试删数据库前怎么让人审批长对话超上下文窗口怎么办答案就是 Middleware中间件——在 Agent 循环的每一步插入自定义逻辑。中间件是什么中间件是钩子Hook的集合在 Agent 循环的每一步模型调用前后、工具调用前后插入逻辑用于实现日志、限流、重试、人工审批、成本控制等功能。类比相当于 Spring 的拦截器Interceptor 过滤器Filter在请求链上层层拦截处理。二、核心拆解中间件在 Agent 循环中的分布2.1 Agent 循环回顾调模型 → 模型选工具 → 执行工具 → 回传结果 → 直到模型不再调工具中间件就在这个循环的每一步前后插入钩子。2.2 完整流程图用户输入 │ ▼ before_agentAgent 启动时只执行一次 • 加载记忆、连接资源、校验初始输入 │ ▼ before_model每次调模型前 • PIIMiddleware → 敏感信息脱敏 • ContextEditingMiddleware → 清理旧工具结果 • SummarizationMiddleware → 超 token 自动摘要 │ ▼ wrap_model_call包裹整个模型调用 • ModelRetryMiddleware → 模型失败自动重试 • ModelFallbackMiddleware → 主模型挂切备用 • ModelCallLimitMiddleware → 限制模型调用次数 • LLMToolSelectorMiddleware → 小模型先筛工具 │ ▼ 模型决策选工具 or 直接回答 │ ├──── 直接回答 ─────────────────────────────────┐ │ │ ▼ ▼ after_model模型返回后工具执行前 • HumanInTheLoopMiddleware → 危险工具需人工审批 • PIIMiddleware → 模型输出脱敏 │ ▼ wrap_tool_call包裹整个工具调用 • ToolRetryMiddleware → 工具失败自动重试 • ToolCallLimitMiddleware → 限制工具调用次数 • LLMToolEmulatorMiddleware → 测试时模拟工具 │ ▼ 工具执行返回结果给模型 │ ▼ 回到 before_model继续循环直到模型不再调工具 │ ▼ after_agentAgent 结束时只执行一次 • 保存结果、发通知、清理资源 │ ▼ 最终输出给用户2.3 按流程步骤总结步骤钩子位置涉及中间件1. 人类询问→发给模型before_model wrap_model_callPII 脱敏 → Summarization 摘要 → ModelRetry 重试 → LLMToolSelector 筛工具2. 模型调用工具after_model wrap_tool_callHumanInTheLoop 审批 → ToolRetry 重试 → ToolCallLimit 限次3. 工具回复模型before_model回到循环ContextEditing 清理 → Summarization 摘要4. 输出答案after_agent自定义收尾逻辑三、15 个预构建中间件按工业使用频率排序3.1 高频生产标配序号中间件作用代码示例1SummarizationMiddleware超 token 阈值自动摘要旧消息SummarizationMiddleware(modelllm, trigger(tokens, 4000))2ModelCallLimitMiddleware限制模型调用次数ModelCallLimitMiddleware(run_limit5)3ToolCallLimitMiddleware限制工具调用次数ToolCallLimitMiddleware(run_limit3)4ModelRetryMiddleware模型调用失败自动重试ModelRetryMiddleware(max_retries3)5ModelFallbackMiddleware主模型挂了自动切备用ModelFallbackMiddleware(fallback_models[llm_backup])3.2 中频按需启用序号中间件作用典型场景6HumanInTheLoopMiddleware危险工具需人工审批金融/写库/发邮件7ToolRetryMiddleware工具调用失败自动重试第三方接口不稳定8ContextEditingMiddleware清理旧工具结果保最新长对话控上下文9LLMToolSelectorMiddleware小模型先筛相关工具工具多时省 token10PIIMiddleware敏感信息检测与脱敏合规/日志清洗3.3 低频特殊场景序号中间件作用11TodoListMiddleware自动维护任务清单12FilesystemMiddleware文件系统中间件13SubagentMiddleware子智能体中间件14LLMToolEmulatorMiddleware用 LLM 模拟工具执行测试用15ProviderToolSearchMiddleware厂商端工具搜索3.4 重点中间件详解SummarizationMiddleware长对话必备from langchain.agents.middleware import SummarizationMiddleware SummarizationMiddleware( modelllm, # 用哪个模型做摘要 trigger(tokens, 4000), # 触发条件累计超过 4000 tokens keep(messages, 20), # 摘要后保留最近 20 条消息 )触发流程每轮对话后检查总 tokens ↓ 超过 4000 ├─ 否 → 不做任何事 └─ 是 → 触发摘要 旧消息 → 模型生成摘要 保留最近 20 条 继续HumanInTheLoopMiddleware危险操作审批from langchain.agents.middleware import HumanInTheLoopMiddleware HumanInTheLoopMiddleware( interrupt_on{ send_email: { allowed_decisions: [approve, edit, reject], }, read_email: False, # 读邮件不需要审批 } )决策含义效果approve同意直接执行工具edit编辑人类修改参数后执行reject拒绝不执行告诉模型被拒绝ModelFallbackMiddleware自动降级ModelFallbackMiddleware( fallback_models[llm_backup1, llm_backup2], )主模型 qwen-plus 调用失败429/500 ↓ 自动切备用模型1 → 还是失败 ↓ 自动切备用模型2 → 成功 ↓ 返回结果用户无感四、自定义中间件全流程实战4.1 方式一装饰器式单个钩子from langchain.agents.middleware import before_model, after_model before_model def log_before(state, runtime): 模型调用前打印消息数 print(f即将调用模型消息数: {len(state[messages])}) return None # 返回 None 不修改 state after_model def log_after(state, runtime): 模型调用后打印返回内容 last_msg state[messages][-1] print(f模型返回: {last_msg.content[:50]}) return None4.2 方式二类式多个钩子封装在一起from langchain.agents.middleware import AgentMiddleware class MyLoggingMiddleware(AgentMiddleware): 自定义日志中间件同时定义 before_model after_model def before_model(self, state, runtime): print(f[before] 消息数: {len(state[messages])}) return None def after_model(self, state, runtime): last_msg state[messages][-1] print(f[after] 返回: {last_msg.content[:50]}) return None4.3 使用自定义中间件agent create_agent( modelllm, tools[get_weather], middleware[log_before, MyLoggingMiddleware()], # 装饰器式 类式混用 )4.4 装饰器式 vs 类式对比装饰器式类式适合单个钩子多个钩子共享状态代码量少多可复用性低高可带配置类比 JavaBefore注解HandlerInterceptor接口实现4.5 钩子返回值规则返回值效果None不修改 statedict合并进 statemessages 走 add_messages reducer五、6 个钩子点总结钩子时机执行次数典型用途before_agentAgent 启动1 次加载记忆、连接资源before_model每次调模型前每轮脱敏、摘要、清理上下文wrap_model_call包裹模型调用每轮重试、降级、限流、筛工具after_model模型返回后、工具执行前每轮人工审批、输出脱敏wrap_tool_call包裹工具调用每次工具调用工具重试、限次、模拟after_agentAgent 结束1 次保存结果、发通知六、避坑指南坑1after_model 签名没有 response 参数# ❌ 错误after_model 没有 response 参数 after_model def my_hook(state, runtime, response): print(response.content) # 报错 # ✅ 正确模型返回的内容在 state[messages][-1] 里 after_model def my_hook(state, runtime): last_msg state[messages][-1] print(last_msg.content)坑2中间件顺序影响执行结果# 顺序敏感先摘要再脱敏 vs 先脱敏再摘要结果可能不同 middleware[ PIIMiddleware(...), # 先脱敏 SummarizationMiddleware(...), # 再摘要基于脱敏后的内容 ]坑3HumanInTheLoopMiddleware 需要 checkpointer# 没有 checkpointerHumanInTheLoop 无法暂停恢复 agent create_agent( modelllm, tools[send_email], middleware[HumanInTheLoopMiddleware(interrupt_on{send_email: ...})], checkpointerInMemorySaver(), # ← 必须有 )七、总结概念一句话理解中间件钩子集合在 Agent 循环每一步插入逻辑钩子特定位置的插入点before_model/after_model 等预构建中间件15 个开箱即用按频率分三档自定义中间件装饰器式单钩子或类式多钩子钩子返回值None 不修改dict 合并进 state核心认知中间件是 Agent 的免疫系统神经系统——控制成本限流、保障稳定重试/降级、确保安全PII/审批、管理上下文摘要/清理。6 个钩子点覆盖了 Agent 循环的每一个环节15 个预构建中间件 自定义能力 生产级 Agent 的精细化控制。互动讨论你在实际项目中用过哪些中间件遇到过什么坑欢迎评论区交流下一篇我们将深入Short-term Memory短期记忆包括 Checkpointer 机制、trim 裁剪策略、自定义 State敬请关注。
【一文吃透】LangChain Middleware 中间件详解:15个预构建中间件+6个钩子点+自定义全流程实战
摘要LangChain 的 Middleware 机制是生产级 Agent 的核心能力相当于 Spring 的拦截器过滤器。本文用 15 个预构建中间件 6 个钩子点 自定义全流程实战帮你从 0 到 1 掌握 Agent 循环的精细化控制。含完整代码 流程图 避坑指南看完直接复用。关键词LangChain、Middleware、中间件、Agent、Hook、钩子、create_agent一、问题背景为什么需要中间件写 Agent 最常见的问题Agent 死循环烧 token怎么限制调用次数模型偶尔 429 限流怎么自动重试删数据库前怎么让人审批长对话超上下文窗口怎么办答案就是 Middleware中间件——在 Agent 循环的每一步插入自定义逻辑。中间件是什么中间件是钩子Hook的集合在 Agent 循环的每一步模型调用前后、工具调用前后插入逻辑用于实现日志、限流、重试、人工审批、成本控制等功能。类比相当于 Spring 的拦截器Interceptor 过滤器Filter在请求链上层层拦截处理。二、核心拆解中间件在 Agent 循环中的分布2.1 Agent 循环回顾调模型 → 模型选工具 → 执行工具 → 回传结果 → 直到模型不再调工具中间件就在这个循环的每一步前后插入钩子。2.2 完整流程图用户输入 │ ▼ before_agentAgent 启动时只执行一次 • 加载记忆、连接资源、校验初始输入 │ ▼ before_model每次调模型前 • PIIMiddleware → 敏感信息脱敏 • ContextEditingMiddleware → 清理旧工具结果 • SummarizationMiddleware → 超 token 自动摘要 │ ▼ wrap_model_call包裹整个模型调用 • ModelRetryMiddleware → 模型失败自动重试 • ModelFallbackMiddleware → 主模型挂切备用 • ModelCallLimitMiddleware → 限制模型调用次数 • LLMToolSelectorMiddleware → 小模型先筛工具 │ ▼ 模型决策选工具 or 直接回答 │ ├──── 直接回答 ─────────────────────────────────┐ │ │ ▼ ▼ after_model模型返回后工具执行前 • HumanInTheLoopMiddleware → 危险工具需人工审批 • PIIMiddleware → 模型输出脱敏 │ ▼ wrap_tool_call包裹整个工具调用 • ToolRetryMiddleware → 工具失败自动重试 • ToolCallLimitMiddleware → 限制工具调用次数 • LLMToolEmulatorMiddleware → 测试时模拟工具 │ ▼ 工具执行返回结果给模型 │ ▼ 回到 before_model继续循环直到模型不再调工具 │ ▼ after_agentAgent 结束时只执行一次 • 保存结果、发通知、清理资源 │ ▼ 最终输出给用户2.3 按流程步骤总结步骤钩子位置涉及中间件1. 人类询问→发给模型before_model wrap_model_callPII 脱敏 → Summarization 摘要 → ModelRetry 重试 → LLMToolSelector 筛工具2. 模型调用工具after_model wrap_tool_callHumanInTheLoop 审批 → ToolRetry 重试 → ToolCallLimit 限次3. 工具回复模型before_model回到循环ContextEditing 清理 → Summarization 摘要4. 输出答案after_agent自定义收尾逻辑三、15 个预构建中间件按工业使用频率排序3.1 高频生产标配序号中间件作用代码示例1SummarizationMiddleware超 token 阈值自动摘要旧消息SummarizationMiddleware(modelllm, trigger(tokens, 4000))2ModelCallLimitMiddleware限制模型调用次数ModelCallLimitMiddleware(run_limit5)3ToolCallLimitMiddleware限制工具调用次数ToolCallLimitMiddleware(run_limit3)4ModelRetryMiddleware模型调用失败自动重试ModelRetryMiddleware(max_retries3)5ModelFallbackMiddleware主模型挂了自动切备用ModelFallbackMiddleware(fallback_models[llm_backup])3.2 中频按需启用序号中间件作用典型场景6HumanInTheLoopMiddleware危险工具需人工审批金融/写库/发邮件7ToolRetryMiddleware工具调用失败自动重试第三方接口不稳定8ContextEditingMiddleware清理旧工具结果保最新长对话控上下文9LLMToolSelectorMiddleware小模型先筛相关工具工具多时省 token10PIIMiddleware敏感信息检测与脱敏合规/日志清洗3.3 低频特殊场景序号中间件作用11TodoListMiddleware自动维护任务清单12FilesystemMiddleware文件系统中间件13SubagentMiddleware子智能体中间件14LLMToolEmulatorMiddleware用 LLM 模拟工具执行测试用15ProviderToolSearchMiddleware厂商端工具搜索3.4 重点中间件详解SummarizationMiddleware长对话必备from langchain.agents.middleware import SummarizationMiddleware SummarizationMiddleware( modelllm, # 用哪个模型做摘要 trigger(tokens, 4000), # 触发条件累计超过 4000 tokens keep(messages, 20), # 摘要后保留最近 20 条消息 )触发流程每轮对话后检查总 tokens ↓ 超过 4000 ├─ 否 → 不做任何事 └─ 是 → 触发摘要 旧消息 → 模型生成摘要 保留最近 20 条 继续HumanInTheLoopMiddleware危险操作审批from langchain.agents.middleware import HumanInTheLoopMiddleware HumanInTheLoopMiddleware( interrupt_on{ send_email: { allowed_decisions: [approve, edit, reject], }, read_email: False, # 读邮件不需要审批 } )决策含义效果approve同意直接执行工具edit编辑人类修改参数后执行reject拒绝不执行告诉模型被拒绝ModelFallbackMiddleware自动降级ModelFallbackMiddleware( fallback_models[llm_backup1, llm_backup2], )主模型 qwen-plus 调用失败429/500 ↓ 自动切备用模型1 → 还是失败 ↓ 自动切备用模型2 → 成功 ↓ 返回结果用户无感四、自定义中间件全流程实战4.1 方式一装饰器式单个钩子from langchain.agents.middleware import before_model, after_model before_model def log_before(state, runtime): 模型调用前打印消息数 print(f即将调用模型消息数: {len(state[messages])}) return None # 返回 None 不修改 state after_model def log_after(state, runtime): 模型调用后打印返回内容 last_msg state[messages][-1] print(f模型返回: {last_msg.content[:50]}) return None4.2 方式二类式多个钩子封装在一起from langchain.agents.middleware import AgentMiddleware class MyLoggingMiddleware(AgentMiddleware): 自定义日志中间件同时定义 before_model after_model def before_model(self, state, runtime): print(f[before] 消息数: {len(state[messages])}) return None def after_model(self, state, runtime): last_msg state[messages][-1] print(f[after] 返回: {last_msg.content[:50]}) return None4.3 使用自定义中间件agent create_agent( modelllm, tools[get_weather], middleware[log_before, MyLoggingMiddleware()], # 装饰器式 类式混用 )4.4 装饰器式 vs 类式对比装饰器式类式适合单个钩子多个钩子共享状态代码量少多可复用性低高可带配置类比 JavaBefore注解HandlerInterceptor接口实现4.5 钩子返回值规则返回值效果None不修改 statedict合并进 statemessages 走 add_messages reducer五、6 个钩子点总结钩子时机执行次数典型用途before_agentAgent 启动1 次加载记忆、连接资源before_model每次调模型前每轮脱敏、摘要、清理上下文wrap_model_call包裹模型调用每轮重试、降级、限流、筛工具after_model模型返回后、工具执行前每轮人工审批、输出脱敏wrap_tool_call包裹工具调用每次工具调用工具重试、限次、模拟after_agentAgent 结束1 次保存结果、发通知六、避坑指南坑1after_model 签名没有 response 参数# ❌ 错误after_model 没有 response 参数 after_model def my_hook(state, runtime, response): print(response.content) # 报错 # ✅ 正确模型返回的内容在 state[messages][-1] 里 after_model def my_hook(state, runtime): last_msg state[messages][-1] print(last_msg.content)坑2中间件顺序影响执行结果# 顺序敏感先摘要再脱敏 vs 先脱敏再摘要结果可能不同 middleware[ PIIMiddleware(...), # 先脱敏 SummarizationMiddleware(...), # 再摘要基于脱敏后的内容 ]坑3HumanInTheLoopMiddleware 需要 checkpointer# 没有 checkpointerHumanInTheLoop 无法暂停恢复 agent create_agent( modelllm, tools[send_email], middleware[HumanInTheLoopMiddleware(interrupt_on{send_email: ...})], checkpointerInMemorySaver(), # ← 必须有 )七、总结概念一句话理解中间件钩子集合在 Agent 循环每一步插入逻辑钩子特定位置的插入点before_model/after_model 等预构建中间件15 个开箱即用按频率分三档自定义中间件装饰器式单钩子或类式多钩子钩子返回值None 不修改dict 合并进 state核心认知中间件是 Agent 的免疫系统神经系统——控制成本限流、保障稳定重试/降级、确保安全PII/审批、管理上下文摘要/清理。6 个钩子点覆盖了 Agent 循环的每一个环节15 个预构建中间件 自定义能力 生产级 Agent 的精细化控制。互动讨论你在实际项目中用过哪些中间件遇到过什么坑欢迎评论区交流下一篇我们将深入Short-term Memory短期记忆包括 Checkpointer 机制、trim 裁剪策略、自定义 State敬请关注。