Skip to content

中间件概览

本节解决什么问题

Middleware(中间件)是 LangChain 1.0 Agent 架构中的拦截器层。它允许你在 Agent 的请求-响应流程中插入自定义逻辑,而无需修改 Agent 的核心代码。

具体来说,Middleware 可以在多个时机介入:

  • 请求前(before_agent / before_model):修改用户输入、检测敏感信息、记录日志
  • 模型调用时(wrap_model_call):动态调整模型参数、过滤工具列表、注入上下文
  • 工具调用时(wrap_tool_call):拦截工具执行、参数审计、结果改写
  • 响应后(after_model / after_agent):处理模型输出、格式化结果、触发通知

这种设计实现了横切关注点(Cross-Cutting Concerns)的分离--安全、日志、审批等功能不再散落在业务代码中,而是集中到独立的 Middleware 模块。

先修知识

必须深刻理解,不能跳过:中间件是 Agent 循环的"洋葱层",不是请求拦截器

前端的请求拦截器(Axios interceptor、Express middleware)拦截的是一次 HTTP 请求。LangChain 的中间件拦截的是 Agent 的一次模型调用轮次。Agent 在循环中可能多次调用模型和工具,每次模型调用都会穿过中间件链。这意味着 wrap_model_call 在一次 agent.invoke() 中可能被执行多次。

前端类比

如果你用过 Express 或 Koa,这个模型会非常熟悉。Express 的 app.use() 链和 Koa 的 async (ctx, next) => {} 模式本质上就是洋葱模型。LangChain 的 Middleware 与 Koa 的实现最为接近:

javascript
// Koa 中间件 - 等价概念
app.use(async (ctx, next) => {
  console.log('请求前') // 前处理
  await next() // 调用下一层
  console.log('响应后') // 后处理
})

LangChain 的 handler(request) 等价于 Koa 的 await next(),都是"穿透到下一层"的调用。

原生语义

Koa 中间件处理的是 HTTP 请求-响应周期(一次请求一次响应)。LangChain 中间件处理的是 Agent 循环中的一个模型调用轮次。Agent 在一次 invoke 中可能经历多轮"模型推理 -> 工具调用 -> 模型推理"循环,每一轮模型调用都会穿过 wrap_model_call 中间件。理解这一点才能正确设计中间件的行为和副作用。

洋葱模型:Middleware 执行机制

Middleware 采用经典的洋葱模型(Onion Model)执行。每个 Middleware 像洋葱的一层皮,请求从外层向内层穿透,到达 Agent/LLM 核心后,响应再从内层向外层返回。每一层都有机会在请求和响应两个阶段分别执行逻辑。

关键特征:

阶段方向说明
请求阶段从上到下(外->内)按 middleware 列表的声明顺序执行
响应阶段从下到上(内->外)按 middleware 列表的逆序执行

这意味着列表中第一个 Middleware 最先接触请求,也最后接触响应--它拥有"全局视角"。

如何添加 Middleware

通过 create_agentmiddleware 参数传入 Middleware 列表:

python
import os
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.agents.middleware import PIIMiddleware, SummarizationMiddleware

model = init_chat_model(os.environ["LLM_MODEL"])

agent = create_agent(
    model=model,
    tools=[search, calculator],
    middleware=[
        PIIMiddleware("email", strategy="redact"),
        SummarizationMiddleware(
            model=model,
            trigger=("tokens", 4000),  # 超过 4000 token 时触发摘要
            keep=("messages", 20),     # 保留最近 20 条消息
        ),
    ],
)

middleware 接收一个列表,列表中的顺序就是执行顺序。Agent 创建后,Middleware 链即固定,不可在运行时动态修改。

如需根据环境动态配置,可以在创建前构建列表:

python
middlewares = []

if config.enable_logging:
    middlewares.append(LoggingMiddleware())

if config.enable_pii_detection:
    middlewares.append(PIIMiddleware("email", strategy="redact"))

agent = create_agent(
    model=model,
    tools=[search],
    middleware=middlewares,
)

旧版

SummarizationMiddleware(max_tokens_before_summary=500) 参数已弃用。使用 trigger=("tokens", N) 指定触发条件,keep=("messages", N) 指定保留策略。model 是必填参数。

python
# 旧版(已弃用)
SummarizationMiddleware(model="...", max_tokens_before_summary=500)

# 当前写法
SummarizationMiddleware(model=model, trigger=("tokens", 500), keep=("messages", 20))

Middleware 排序策略

排序直接影响行为正确性和性能。推荐的排序原则:

外层(最先执行)
  ├── 1. 日志 / 追踪         ← 记录原始请求,方便调试
  ├── 2. 安全检查(PII / 内容过滤)  ← 尽早拦截不合规请求
  ├── 3. 性能优化(缓存 / 摘要)    ← 减少后续层的处理量
  └── 4. 流程控制(人工审批)      ← 只在必要时介入
内层(最接近 Agent/LLM)

为什么这样排?

  • 日志在最外层:能够捕获完整的请求-响应生命周期,包括其他 Middleware 的处理时间
  • 安全检查靠前:尽早拦截包含敏感信息的请求,避免不必要的后续处理(如 LLM 调用)
  • 人工审批靠后:只有通过了所有自动化检查的请求,才需要人工介入,减少审批负担

反面示例

python
# 错误的排序 - 先摘要再 PII 检测
middleware=[
    SummarizationMiddleware(...),  # 摘要过程可能引入 PII
    PIIMiddleware("email"),        # 此时检测可能遗漏摘要中的 PII
]

# 正确的排序
middleware=[
    PIIMiddleware("email"),        # 先检测原始输入
    SummarizationMiddleware(...),  # 再进行摘要
]

内置中间件全貌

LangChain 提供了 18 个内置中间件,覆盖安全合规、成本控制、流程管理、容错、工具增强等横切关注点:

核心安全与流程(3 个)

中间件功能适用场景
PIIMiddlewarePII 检测、脱敏、拦截合规要求、数据安全
SummarizationMiddleware自动摘要长对话控制 token 用量、降低成本
HumanInTheLoopMiddleware敏感操作人工审批高风险工具调用、合规审计

容错与重试(3 个)

中间件功能适用场景
ModelRetryMiddleware模型调用失败自动重试网络不稳定、API 限流
ToolRetryMiddleware工具执行失败自动重试工具偶发超时或错误
ModelFallbackMiddleware主模型失败时切换备用模型高可用要求、多 Provider 容灾

调用限制(2 个)

中间件功能适用场景
ModelCallLimitMiddleware限制模型调用次数上限防止无限循环、控制成本
ToolCallLimitMiddleware限制工具调用次数上限防止工具滥用

工具与上下文增强(6 个)

中间件功能适用场景
ContextEditingMiddleware编辑 / 裁剪上下文消息精细控制发送给模型的内容
LLMToolSelectorMiddleware用 LLM 动态选择可用工具工具数量多、按需加载
LLMToolEmulatorMiddleware用 LLM 模拟工具执行测试、无真实 API 时预演
ProviderToolSearchMiddleware从 Provider 搜索可用工具集成 Provider 工具生态
FilesystemMiddleware文件系统操作工具文件读写、目录管理
FileSearchMiddleware文件搜索工具大量文件中检索

高级能力(4 个)

中间件功能适用场景
SubagentMiddleware嵌套子 Agent复杂任务分解、专家委托
TodoListMiddleware自动维护待办列表多步任务进度追踪
ShellToolMiddlewareShell 命令执行工具系统运维、自动化脚本
RubricGradingMiddleware基于评分标准的质量评估 [beta]输出质量打分、自动评估

标注 [beta] 的中间件尚不稳定,API 可能在后续版本变更,生产环境谨慎使用。

详细的 PII / Summarization / HITL 用法请参考 内置中间件

自定义中间件

当内置 Middleware 无法满足需求时,可以继承 AgentMiddleware 基类创建自定义 Middleware:

python
from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse

class MyMiddleware(AgentMiddleware):
    def wrap_model_call(self, request: ModelRequest, handler):
        # 前处理:修改请求
        modified_request = self.preprocess(request)
        # 穿透到下一层(模型调用)
        response = handler(modified_request)
        # 后处理:修改响应
        return self.postprocess(response)

可用 Hooks

AgentMiddleware 提供以下 hook,按执行顺序排列:

Hook触发时机典型用途
before_agentAgent 执行开始(整个循环之前)初始化上下文、记录开始时间
before_model每次模型调用之前注入系统消息、修改工具列表
wrap_model_call包裹模型调用(可前后处理)修改请求 / 响应、计时、缓存
wrap_tool_call包裹工具调用(可前后处理)参数审计、结果改写
after_model每次模型调用之后输出过滤、格式化
after_agentAgent 执行结束(整个循环之后)清理资源、记录结束时间

详细用法请参考 自定义中间件

性能考量

每个 Middleware 都会在请求-响应路径上增加额外开销。以下是典型的延迟参考:

Middleware 类型典型延迟说明
日志记录< 1ms仅 I/O 写入
PII 正则检测1-10ms取决于正则复杂度和文本长度
对话摘要1-5s需要额外的 LLM 调用
人工审批不确定取决于人工响应时间

优化建议:

  1. 只添加必需的 Middleware:每多一层,请求链路就多一次函数调用开销
  2. 利用短路逻辑:在 Middleware 内部尽早判断是否需要处理,避免无意义的计算
  3. 异步日志:如果日志 Middleware 涉及网络 I/O(如发送到远程服务),使用异步写入避免阻塞主链路
  4. 监控 Middleware 耗时:在日志 Middleware 中记录每层的处理时间,定位性能瓶颈
python
import time

class TimingMiddleware(AgentMiddleware):
    def wrap_model_call(self, request, handler):
        start = time.perf_counter()
        response = handler(request)
        elapsed = time.perf_counter() - start
        print(f"内层处理耗时: {elapsed:.3f}s")
        return response

TimingMiddleware 放在不同位置,可以测量不同层级的耗时。

下一步

  • 内置中间件 - PII / Summarization / HITL 的完整 API、以及 Model Retry / Tool Retry / Model Fallback 等容错中间件
  • 自定义中间件 - 从零编写 Middleware,包括日志、限流、工具过滤等实用模式
  • Agent 实战指南 - 回顾 Agent 的完整用法

学习文档整合站点