跳到主要内容LangChain Agent 中间件详解:提升可靠性与可控性 | 极客日志PythonAI
LangChain Agent 中间件详解:提升可靠性与可控性
介绍 LangChain Agent 中间件机制,涵盖内置中间件如对话总结、人工介入、限流、重试及降级功能,并详解基于装饰器和类的自定义中间件开发方法。通过钩子(Hook)与执行点概念,结合 AgentState 和 Runtime 对象,帮助开发者构建高可靠、可控的大模型应用。
竹影清风27 浏览 前言
在构建复杂的 LangChain Agent 时,我们常常面临上下文超限、成本失控、工具调用失败、敏感信息泄露等问题。LangChain 提供了一套生产就绪的预构建中间件,像乐高积木一样,让我们轻松为 Agent 添加对话总结、人工审核、调用限流、自动重试等能力。
一、中间件是什么?
中间件(Middleware)是 LangChain Agent 执行流程中的钩子函数,可以在模型调用前、工具执行前后、状态更新时插入自定义逻辑。预构建中间件覆盖了从成本控制到安全合规的常见场景,且支持灵活配置。
所有中间件通过 create_agent 的 middleware 参数传入:
from langchain.agents import create_agent
agent = create_agent(
model="gpt-4.1",
tools=[...],
middleware=[Middleware1(...), Middleware2(...)]
)
二、通用中间件详解(Provider-agnostic)
langchain 为我们提供了多个常用的现成的中间件,我们可以根据任务选择使用。这里讲解一些基础中间件,复杂中间件将在后续内容中讲解。
2.1 对话总结(SummarizationMiddleware)
- 场景:长对话易超 Token 限制,自动总结旧消息,保留最新上下文。
- 配置:
- trigger:触发总结的条件(如 token 数≥4000 或消息数≥6)
- keep:总结后保留的内容(如保留最近 20 条消息)
- model:用于生成总结的模型(通常用更便宜的模型)
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
agent = create_agent(
model="gpt-4.1",
tools=[weather_tool, calculator_tool],
middleware=[
SummarizationMiddleware(
model="gpt-4.1-mini",
trigger=[("tokens", 4000), ("messages", 6)],
keep=("messages", 20)
)
]
)
2.2 人工介入(HumanInTheLoopMiddleware)
- 场景:高风险操作(如发送邮件、修改数据库)需人工审批。
- interrupt_on:指定哪些工具需要人工介入,及允许的决策(approve/edit/reject)
- 必须搭配 checkpointer(如 InMemorySaver)实现状态暂停/恢复
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="gpt-4.1",
tools=[read_email_tool, send_email_tool],
checkpointer=InMemorySaver(),
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"send_email_tool": {"allowed_decisions": ["approve", "edit", "reject"]},
"read_email_tool": False
}
)
]
)
2.3 模型调用限流(ModelCallLimitMiddleware)
- 场景:防止 Agent 无限循环或 API 费用失控。
- thread_limit:整个会话的大模型最大调用次数
- run_limit:单次用户请求内的最大调用次数
- exit_behavior:超出限制时,是"end"(优雅终止)还是"error"(抛异常)
from langchain.agents.middleware import ModelCallLimitMiddleware
agent = create_agent(
model="gpt-4.1",
checkpointer=InMemorySaver(),
tools=[],
middleware=[
ModelCallLimitMiddleware(
thread_limit=10,
run_limit=5,
exit_behavior="end"
)
]
)
2.4 工具调用限流(ToolCallLimitMiddleware)
- 场景:针对特定工具设置调用上限(如搜索引擎、数据库查询)。
- tool_name:指定工具名称(不指定则全局限制)
- thread_limit / run_limit:同模型限流
- exit_behavior:支持"continue"(返回错误让 Agent 继续)、"error"、"end"
from langchain.agents.middleware import ToolCallLimitMiddleware
agent = create_agent(
model="gpt-4.1",
tools=[search_tool, db_tool],
middleware=[
ToolCallLimitMiddleware(thread_limit=20, run_limit=10),
ToolCallLimitMiddleware(tool_name="search", thread_limit=5, run_limit=3)
]
)
2.5 模型降级(ModelFallbackMiddleware)
场景:主模型故障时自动切换到备用模型,提升可靠性。配置的备用模型支持字符串或 BaseChatModel 实例。
from langchain.agents.middleware import ModelFallbackMiddleware
agent = create_agent(
model="gpt-4.1",
tools=[],
middleware=[
ModelFallbackMiddleware(
"gpt-4.1-mini",
"claude-3-5-sonnet-20241022"
)
]
)
2.6 工具重试(ToolRetryMiddleware)
- 场景:工具调用因网络波动失败时,自动指数退避重试。
- max_retries:最大重试次数
- retry_on:指定哪些异常需重试(如 ConnectionError)
- on_failure:重试耗尽后,"return_message"(返回错误消息)或"raise"(抛异常)
from langchain.agents.middleware import ToolRetryMiddleware
agent = create_agent(
model="gpt-4.1",
tools=[api_tool],
middleware=[
ToolRetryMiddleware(
max_retries=3,
backoff_factor=2.0,
retry_on=(ConnectionError, TimeoutError),
on_failure="return_message"
)
]
)
2.7 模型重试(ModelRetryMiddleware)
- 场景:模型 API 调用失败(如限流、超时)时自动重试。
配置:与工具重试类似,支持自定义异常过滤和失败处理。
from langchain.agents.middleware import ModelRetryMiddleware
agent = create_agent(
model="gpt-4.1",
tools=[],
middleware=[
ModelRetryMiddleware(
max_retries=4,
retry_on=lambda e: hasattr(e, "status_code") and e.status_code == 429,
on_failure="continue"
)
]
)
三、自定义中间件
上述是 langchain 官方提供的一些通用的中间件,这些中间件会在固定的流程节点执行固定的程序。我们也可以定义开发自己的中间件,无非确定两个点:在哪个节点(位置),执行什么程序。langchain 提供了两种实现方式:基于装饰器(快速简洁)和基于类(功能强大)的方式定义我们的中间件。
3.1 核心概念:钩子(Hook)与执行点
- 钩子(Hook):代理执行流程中预定义的位置,钩子就是执行点,中间件可以在这里挂载代码(钩子函数)。LangChain 中间件主要提供两类钩子:
- 节点式钩子(Node-style):在固定的顺序点运行,如'模型调用前'、'模型调用后'。多个中间件的同类型节点式钩子会按添加顺序依次执行。
- 包装式钩子(Wrap-style):包裹整个调用过程(如一次模型调用),可以完全控制是否执行、执行几次以及如何处理结果。
- 状态(AgentState):一个字典,存储当前代理运行的全部上下文,包括消息列表、中间变量等。中间件可以通过读取和修改状态来影响后续流程。
静态运行时上下文(Runtime):一个对象,提供代理运行时的环境信息,如当前线程 ID、用户上下文等。
3.2 基于装饰器的中间件
装饰器方式适用于只需要一个钩子的简单中间件。LangChain 提供了多个装饰器,分别对应不同的执行点。
3.2.1 节点式装饰器
- 返回值说明
- 返回 None:正常流程,继续执行下一个中间件或实际处理器。
- 返回一个字典:该字典会与当前状态合并(state.update(returned_dict)),可用于添加或修改状态中的字段。特殊键 'jump_to' 可以强制跳转到指定节点(如 'end' 提前结束代理)。
中间件返回的 message 列表,跟工具是一样的,可以兼具同时删除消息,和添加新消息到 messages 列表后面(默认)。
from langchain.agents.middleware import after_model
from langchain.messages import AIMessage
@after_model(can_jump_to=["end"])
def block_sensitive_output(state, runtime):
last_msg = state["messages"][-1]
if "password" in last_msg.content.lower():
return {"messages": [AIMessage("I cannot reveal that information.")], "jump_to": "end"}
return None
这些装饰器定义的函数会在特定的执行点(位置、钩子)被调用,不能控制是否调用下游中间件或实际处理器,只能读取/修改状态。
| 装饰器 | 执行时机 | 函数签名 | 典型用途 |
|---|
| @before_agent | 整个代理调用开始时(仅一次) | (state: AgentState, runtime: Runtime) -> dict | None |
| @before_model | 每次模型调用之前 | (state: AgentState, runtime: Runtime) -> dict | None |
| @after_model | 每次模型调用之后 | (state: AgentState, runtime: Runtime) -> dict | None |
| @after_agent | 整个代理调用结束时(最多一次) | (state: AgentState, runtime: Runtime) -> dict | None |
3.2.2 包装式装饰器
包装式装饰器,我们可以包裹实际的调用处理程序(handler),完全控制其执行。
| 装饰器 | 作用范围 | 函数签名 | 典型用途 |
|---|
| @wrap_model_call | 每次模型调用 | (request: ModelRequest, handler: Callable) -> ModelResponse | 重试、缓存、动态模型切换 |
| @wrap_tool_call | 每次工具调用 | (request: ToolRequest, handler: Callable) -> ToolResponse | 重试、模拟、权限检查 |
| @dynamic_prompt | 生成动态系统提示词 | (request: ModelRequest) -> str | 个性化提示词、根据上下文调整系统消息 |
- request:包含调用所需的信息,如 request.messages(消息列表)、request.runtime(运行时)、request.model(当前模型)等。
- handler:下一个中间件或实际处理器的可调用对象。调用 handler(request) 会继续执行包装链,最终返回响应。
from langchain.agents.middleware import wrap_model_call
import time
@wrap_model_call
def retry_with_backoff(request, handler):
max_retries = 3
for attempt in range(max_retries):
try:
return handler(request)
except Exception as e:
if attempt == max_retries - 1:
raise
wait = (2 ** attempt)
time.sleep(wait)
print(f"Retry {attempt+1}/{max_retries} after {wait}s")
- 装饰器函数本身会作为中间件对象,直接传入 middleware 列表。
- 多个中间件的执行顺序:节点式钩子按列表顺序执行;包装式钩子则按列表顺序从外到内包装(即列表最后一个包装器最先接触 handler,最内层执行)。
3.3 基于类的中间件
当中间件需要多个钩子、复杂配置或复用性时,应继承 AgentMiddleware 基类。
3.3.1 节点式钩子方法
在子类中重写以下方法即可,那这样一个类中间件实例化对象就包含了多个钩子
from langchain.agents.middleware import AgentMiddleware
class MyMiddleware(AgentMiddleware):
def before_agent(self, state, runtime):
pass
def before_model(self, state, runtime):
pass
def after_model(self, state, runtime):
pass
def after_agent(self, state, runtime):
pass
3.3.2 包装式钩子方法
重写 wrap_model_call 和 wrap_tool_call 方法,包装式方法中,你必须显式调用 handler(request) 来继续执行链,否则下游中间件和实际调用将被跳过。你可以调用多次(重试),也可以根据条件不调用(短路)
class MyMiddleware(AgentMiddleware):
def wrap_model_call(self, request, handler):
response = handler(request)
return response
def wrap_tool_call(self, request, handler):
pass
3.3.3 类中间件的初始化
可以通过 init 接收配置参数,然后保存为实例变量,在钩子方法中使用。
class RetryMiddleware(AgentMiddleware):
def __init__(self, max_retries=3):
self.max_retries = max_retries
super().__init__()
四、深入理解 AgentState 和 Runtime
4.1 AgentState
agent 全局维护的状态对象,它是一个 TypedDict,至少包含以下字段:
- messages:List[BaseMessage],当前对话的所有消息(包括人类消息、AI 消息、工具消息等)。
- intermediate_steps:记录工具执行的历史。
- 还可能包含其他自定义字段(如 todos、jump_to 等)。
中间件可以通过返回字典来更新状态,例如添加新字段或修改现有字段。但需注意:某些字段(如 messages)的修改需要遵循不可变原则或正确追加。
4.2 Runtime
- runtime.context:一个字典,包含了调用 agent.invoke(…, config={"configurable": {...}}) 时传入的自定义上下文数据。
- runtime.thread_id:当前线程 ID,可用于区分不同会话。
相关免费在线工具
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online