一、核心概念(文档原文通俗翻译)
- 自定义中间件是什么? 自己写的、可插入 Agent 执行流程的钩子函数 / 增强逻辑 ,不用改 Agent 主代码,就能在调用模型前 / 后 、调用工具前 / 后插入自定义逻辑。
- 作用日志打印、参数修改、结果过滤、权限校验、数据格式化、自定义监控等。
- 运行位置 插在 Agent 的推理 → 调用模型 → 执行工具 全流程中,非侵入式增强。
- 必须继承 所有自定义中间件都要继承官方基类:
from langchain.agents.middleware import AgentMiddleware
二、官方规定的固定结构(必须遵守)
文档明确要求:自定义中间件必须实现 __call__ 方法方法签名固定:
async def __call__(self, run, agent, input, **kwargs):
run:Agent 原始执行函数(必须调用它才能继续流程)agent:当前 Agent 对象input:用户输入**kwargs:其他上下文参数
执行流程(文档核心)
- 执行前置逻辑(调用 run 之前)
- 调用
await run(agent, input, **kwargs)→ 让 Agent 正常运行 - 执行后置逻辑(拿到结果后)
- 返回最终结果
三、官方示例 + 优化版代码(可直接运行)
1. 最简单的日志中间件(文档基础示例)
作用:在 Agent 运行前后打印日志
from langchain.agents.middleware import AgentMiddleware
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
# 自定义中间件:必须继承 AgentMiddleware
class LoggingMiddleware(AgentMiddleware):
# 固定方法名和参数
async def __call__(self, run, agent, input, **kwargs):
# 【前置】运行前逻辑
print(f"\n[日志中间件] 用户输入:{input}")
# 执行 Agent 原始流程(必须写!)
result = await run(agent, input,** kwargs)
# 【后置】运行后逻辑
print(f"[日志中间件] Agent 输出:{result}")
# 返回结果
return result
# 创建带自定义中间件的 Agent
agent = create_agent(
llm=ChatOpenAI(model="gpt-3.5-turbo"),
tools=[], # 无工具演示
middleware=[LoggingMiddleware()], # 直接插入
)
2. 输入过滤中间件(文档扩展场景)
作用:拦截敏感词、修改用户输入
class InputFilterMiddleware(AgentMiddleware):
def __init__(self, forbidden_words: list):
self.forbidden_words = forbidden_words
async def __call__(self, run, agent, input,** kwargs):
# 前置:检查敏感词
lower_input = input.lower()
for word in self.forbidden_words:
if word in lower_input:
return "❌ 输入包含敏感内容,已拦截"
# 无敏感词则正常执行
result = await run(agent, input, **kwargs)
return result
# 使用:拦截包含"密码""银行卡"的请求
agent = create_agent(
llm=ChatOpenAI(model="gpt-3.5-turbo"),
tools=[],
middleware=[InputFilterMiddleware(forbidden_words=["密码", "银行卡"])],
)
3. 结果修改中间件(文档高级用法)
作用:修改 Agent 最终返回结果
class ResultFormatMiddleware(AgentMiddleware):
async def __call__(self, run, agent, input,** kwargs):
# 先执行原流程
result = await run(agent, input, **kwargs)
# 后置:格式化结果
formatted = f"""
处理结果:{result}✅ 已通过自定义中间件格式化
"""
return formatted
四、官方支持的两种使用方式
方式 1:创建时直接传入(推荐)
agent = create_agent(
llm=model,
tools=tools,
middleware=[MyMiddleware()], # 列表形式,可多个按顺序执行
)
方式 2:动态添加
agent = create_agent(llm=model, tools=tools)
agent.middleware.append(MyMiddleware()) # 动态追加
五、多个中间件执行规则(文档重点)
- 顺序执行:列表里写在前面的先运行
- 洋葱模型 :
- 中间件 1 前置 → 中间件 2 前置
- Agent 核心执行
- 中间件 2 后置 → 中间件 1 后置
六、完整可运行模板(官方标准写法)
from langchain.agents.middleware import AgentMiddleware
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
# 自定义中间件(官方标准结构)
class CustomMiddleware(AgentMiddleware):
async def __call__(self, run, agent, input,** kwargs):
# ======================
# 【前置逻辑】写在这里
# ======================
print("→ 运行前:自定义处理输入")
# 执行 Agent 主逻辑(必须调用)
result = await run(agent, input, **kwargs)
# ======================
# 【后置逻辑】写在这里
# ======================
print("→ 运行后:自定义处理结果")
# 返回最终结果
return result
# 初始化
model = ChatOpenAI(model="gpt-3.5-turbo")
agent = create_agent(llm=model, tools=[], middleware=[CustomMiddleware()])
# 测试运行
# await agent.ainvoke("你好")
七、文档重点规则总结
- 必须继承
AgentMiddleware - 必须实现
async def __call__(self, run, agent, input, **kwargs) - 必须调用
await run(...)才能让 Agent 继续执行 - 支持同步 / 异步(官方推荐异步)
- 多个中间件按列表顺序执行
- 非侵入式,不修改原有 Agent 代码
总结
- 自定义中间件 = Agent 的前置 / 后置钩子
- 固定结构:继承 + 实现
__call__+ 调用run() - 用途:日志、过滤、修改、监控、权限控制等
- 完全遵循官方规范,可直接集成到生产环境