news 2026/7/31 4:35:44

LangChain Agent 中间件全解与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangChain Agent 中间件全解与实战

前言:为什么 Agent 需要中间件?

如果你用过 LangChain 构建过 AI Agent,大概率遇到过这样的困境:测试阶段一切正常,部署到生产环境后却问题频发——上下文管理混乱、Agent 行为不可预测、工具调用失控……最后不得不写一堆自定义代码来补救。

问题根源在于:Agent 的可靠性取决于上下文工程。模型接收什么信息,决定了它输出什么结果。而过多的配置参数、散落在各处的自定义逻辑,让 Agent 变得难以维护和扩展。

LangChain 1.0 引入的Agent 中间件(Middleware)正是为了解决这个问题。它借鉴了 Web 框架(如 FastAPI)的中间件模式,在 Agent 执行流程的关键节点提供标准化的钩子(Hooks),让开发者能系统化地控制上下文、注入业务逻辑、增强生产可靠性。

本文将带你全面理解 Agent 中间件的设计理念、核心钩子、内置实现,并通过实战案例掌握自定义中间件的开发。

一、中间件是什么?Agent 的“信息调度中心”

1.1 核心思想

中间件本质上是一组可组合的执行钩子,在 Agent 循环的各个阶段运行。它不改变 Agent 的核心逻辑(模型调用 → 工具执行 → 循环),而是在这些步骤前后插入自定义逻辑,实现:

  • 输入预处理:PII 脱敏、提示词动态生成、对话摘要

  • 执行控制:工具权限校验、人工审批(HITL)、重试与降级

  • 输出后处理:结果验证、日志记录、状态更新

1.2 中间件 vs 传统参数配置

在 v1.0 之前,Agent 的定制依赖大量参数和手写循环,代码臃肿且难以复用。例如旧版AgentExecutor需要配置max_iterationshandle_parsing_errorstrim_intermediate_steps等十几个参数。

中间件的优势在于:

  • 模块化:每个中间件独立负责一个功能(如摘要、缓存、日志)

  • 可组合:多个中间件按顺序叠加,互不干扰

  • 可复用:写好的中间件可在不同项目间共享


二、中间件的核心钩子(Hooks)

LangChain 中间件提供了 6 个核心钩子,覆盖 Agent 的完整生命周期:

钩子执行时机典型用途
before_agentAgent 启动前(仅一次)加载外部记忆、初始化资源、输入校验
before_model每次模型调用前动态更新提示词、对话摘要、PII 脱敏
wrap_model_call包裹模型调用重试机制、模型降级、动态工具绑定
after_model模型响应后、工具执行前人工审批(HITL)、输出格式校验
wrap_tool_call包裹工具调用工具权限控制、参数修改、缓存结果
after_agentAgent 完成后(仅一次)保存结果、释放资源、发送通知

钩子分为两种风格:

  • 节点式钩子(Node-style):顺序执行,通过返回dict更新 Agent 状态。如before_modelafter_model

  • 包裹式钩子(Wrap-style):包裹核心调用,可控制是否执行、重试或短路。如wrap_model_callwrap_tool_call


三、开箱即用的内置中间件

LangChain 提供了多个生产级中间件,可直接引入使用。

3.1 对话摘要中间件(SummarizationMiddleware)

长对话容易超出模型上下文窗口。该中间件在before_model阶段检测消息数量或 Token 阈值,自动生成摘要替换历史消息。

python

from langchain.agents import create_agent from langchain.agents.middleware import SummarizationMiddleware agent = create_agent( model="claude-sonnet-4-6", tools=[...], middleware=[ SummarizationMiddleware( model="claude-sonnet-4-6", trigger={"tokens": 500} # 超过 500 token 触发摘要 ) ] )

3.2 人工审批中间件(HumanInTheLoopMiddleware)

敏感操作(如发送邮件、删除数据)需人工确认。该中间件在after_model阶段拦截指定工具调用,挂起执行等待人工决策。

python

from langchain.agents.middleware import HumanInTheLoopMiddleware agent = create_agent( model="claude-sonnet-4-6", tools=[send_email, read_email], middleware=[ HumanInTheLoopMiddleware( interrupt_on={ "send_email": { "allowed_decisions": ["approve", "edit", "reject"] } } ) ], checkpointer=MemorySaver() # 必须配合 checkpointer 实现暂停与恢复 )

恢复挂起的执行:

python

from langgraph.types import Command agent.invoke( Command(resume={"decisions": [{"type": "approve"}]}), config={"configurable": {"thread_id": "session-123"}} )

3.3 PII 脱敏中间件(PIIRedactionMiddleware)

在模型调用前自动识别并脱敏敏感信息(邮箱、电话、身份证号等),防止数据泄露。

python

from langchain.agents.middleware import PIIRedactionMiddleware agent = create_agent( model="claude-sonnet-4-6", middleware=[ PIIRedactionMiddleware( patterns=["email", "phone", "ssn"], strategy="redact" # 或 "mask", "block" ) ] )

3.4 Anthropic 专属中间件

针对 Claude 模型,langchain-anthropic提供了专用中间件:

  • Prompt Caching:缓存系统提示词和工具定义,降低成本和延迟

  • Bash Tool:提供生产级的 Bash 命令执行(支持 Docker 隔离)

  • Text Editor:文件编辑工具(支持状态持久化和文件系统两种模式)

python

from langchain_anthropic.middleware import ( AnthropicPromptCachingMiddleware, ClaudeBashToolMiddleware ) agent = create_agent( model=ChatAnthropic(model="claude-sonnet-4-6"), middleware=[ AnthropicPromptCachingMiddleware(ttl="5m"), ClaudeBashToolMiddleware( workspace_root="/workspace", execution_policy=DockerExecutionPolicy(image="python:3.11") ) ] )

四、实战:自定义中间件开发

内置中间件无法覆盖所有场景,自定义中间件才是真正的杀手锏。我们通过两个实战案例演示如何开发。

4.1 装饰器式中间件(快速开发)

适合单钩子、逻辑简单的场景。使用@before_model@wrap_tool_call等装饰器。

需求:为所有工具调用添加重试机制,失败时返回友好提示。

python

from langchain.agents.middleware import wrap_tool_call, ToolCallRequest from langchain_core.messages import ToolMessage from typing import Callable @wrap_tool_call def retry_on_tool_failure( request: ToolCallRequest, handler: Callable[[ToolCallRequest], ToolMessage] ) -> ToolMessage: for attempt in range(3): try: return handler(request) except Exception as e: print(f"工具 {request.tool_call['name']} 第 {attempt+1} 次尝试失败: {e}") if attempt == 2: return ToolMessage( content=f"工具执行失败,请重试或换一种方式。错误:{e}", tool_call_id=request.tool_call["id"] ) # 不会执行到这里

使用中间件:

python

agent = create_agent( model="gpt-4", tools=[search, calculator], middleware=[retry_on_tool_failure] )

4.2 类式中间件(复杂场景)

适合多钩子、需维护状态的场景。继承AgentMiddleware并实现对应钩子方法。

需求:根据用户技术水平动态调整模型和工具。专家用户使用高级模型 + 复杂工具,新手使用轻量模型 + 基础工具。

python

from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse from typing import Callable, Any from pydantic import BaseModel # 1. 定义上下文 Schema(运行时传入,不持久化) class UserContext(BaseModel): user_expertise: str = "beginner" # "beginner" 或 "expert" # 2. 自定义中间件 class ExpertiseBasedToolMiddleware(AgentMiddleware): context_schema = UserContext def wrap_model_call( self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse] ) -> ModelResponse: # 从运行时上下文读取用户级别 user_level = request.runtime.context.get("user_expertise", "beginner") if user_level == "expert": # 专家用户:切换更强大的模型 + 高级工具 request = request.override( model="gpt-4", tools=[advanced_search, data_analysis, calculator] ) else: # 新手用户:轻量模型 + 基础工具 request = request.override( model="gpt-3.5-turbo", tools=[simple_search, basic_calculator] ) return handler(request)

使用中间件,并在调用时传入上下文:

python

agent = create_agent( model="gpt-4", # 默认模型,会被中间件覆盖 tools=[simple_search, advanced_search, basic_calculator, data_analysis], middleware=[ExpertiseBasedToolMiddleware()] ) # 专家用户调用 result = agent.invoke( {"messages": [HumanMessage("分析这份销售数据")]}, config={"context": {"user_expertise": "expert"}} )

4.3 中间件状态管理

如果中间件需要跨轮次持久化数据(如调用计数、Token 用量),可扩展 Agent 的状态 Schema。

python

from langchain.agents.middleware import AgentMiddleware, AgentState from typing import NotRequired class TrackingState(AgentState): model_call_count: NotRequired[int] class UsageTrackingMiddleware(AgentMiddleware): state_schema = TrackingState def after_model(self, state: TrackingState, runtime) -> dict[str, Any] | None: # 每次模型调用后更新计数 current = state.get("model_call_count", 0) return {"model_call_count": current + 1}

五、进阶:中间件组合与执行顺序

多个中间件按注册顺序执行,类似洋葱模型:

  1. 进入阶段(before_model):按注册顺序执行

  2. 包裹阶段(wrap_model_call):外层 → 内层

  3. 退出阶段(after_model):按注册顺序的逆序执行

python

agent = create_agent( model="gpt-4", middleware=[ LoggingMiddleware(), # ① 先记录日志 RetryMiddleware(), # ② 再添加重试 PIIRedactionMiddleware() # ③ 最后脱敏 ] )

执行顺序:Logging.before_modelRetry.before_modelPII.before_model模型调用PII.after_modelRetry.after_modelLogging.after_model


六、中间件 + LangGraph:在复杂工作流中使用

中间件并非仅限单 Agent 使用。create_agent返回的 Agent 本身是一个 LangGraph 图,可嵌入更大的工作流中,中间件钩子依然有效。

python

from langgraph.graph import StateGraph, START from langchain.agents import create_agent, AgentState # 创建带中间件的 Agent email_agent = create_agent( model="claude-sonnet-4-6", tools=[read_email, send_email], middleware=[HumanInTheLoopMiddleware(interrupt_on={"send_email": True})] ) # 嵌入更大的工作流 graph = ( StateGraph(AgentState) .add_node("classify", classify_node) # 分类节点 .add_node("email_agent", email_agent) # Agent 节点 .add_edge(START, "classify") .add_conditional_edges("classify", route) # 动态路由到不同 Agent .compile() )

这种模式适合多 Agent 协作预处理-处理-后处理的流水线场景。


七、总结与最佳实践

何时使用中间件?

  • 生产级 Agent:需要日志、重试、监控、降级

  • 复杂上下文管理:动态提示词、对话摘要、PII 脱敏

  • 安全与合规:工具权限控制、人工审批、数据隐私

  • 多租户或个性化:根据用户角色动态调整模型和工具

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/31 4:32:00

我用AI做的3/100件事之废旧手机变英语磨耳朵神器

我用AI做的3/100件事之废旧手机变英语磨耳朵神器 背景:从废旧手机到学习工具你有没有一台旧手机躺在抽屉里吃灰?我有一台2018年的华为P20,屏幕有划痕,电池续航只剩半天,但运行Android系统毫无问题。我一直在想&#xf…

作者头像 李华
网站建设 2026/7/31 4:31:11

C++11核心特性实战指南:从auto到智能指针的现代编程

1. 项目概述:为什么C11值得你投入时间?如果你还在用着老旧的C98标准,或者对C的印象还停留在“复杂”、“难用”、“内存管理噩梦”的阶段,那C11对你来说,可能是一次认知上的彻底刷新。我刚开始接触C11时,感…

作者头像 李华
网站建设 2026/7/31 4:26:35

DIY铅酸电池均衡器:TL431+MOS管方案解决电瓶车续航衰减

1. 项目缘起:从一次“趴窝”说起我的那辆老电瓶车,最近是越来越不中用了。明明充电器显示绿灯已满,刚骑出去没几公里,电量表就“唰”地一下掉到红线,然后直接“趴窝”在路中间,推车推到怀疑人生。相信不少骑…

作者头像 李华
网站建设 2026/7/31 4:26:05

小波分析与分形几何在车型识别中的应用与优化

1. 项目概述:当小波分析遇上分形几何在智能交通系统的前端感知层,车型识别一直是个既基础又关键的环节。去年我在参与某城市智慧停车项目时,发现传统基于轮廓特征的识别方法在复杂光照和遮挡场景下误判率高达23%。经过三个月算法迭代&#xf…

作者头像 李华
网站建设 2026/7/31 4:24:42

InSAR数据处理与绘图自动化:GMT+Shell+Matlab工具链实战指南

1. 项目概述:InSAR数据处理与绘图的“瑞士军刀”集如果你正在处理合成孔径雷达干涉测量(InSAR)数据,无论是做形变监测、沉降分析还是地质灾害评估,那你一定对从原始数据到最终出版级图件这个漫长流程中的“工具切换”深…

作者头像 李华
网站建设 2026/7/31 4:20:23

GeoJSON.io:5分钟掌握免费在线地理数据编辑的终极指南

GeoJSON.io:5分钟掌握免费在线地理数据编辑的终极指南 【免费下载链接】geojson.io A quick, simple tool for creating, viewing, and sharing spatial data 项目地址: https://gitcode.com/gh_mirrors/ge/geojson.io 你是否曾经因为需要处理地理数据而不得…

作者头像 李华