LangChain 源码剖析-自定义中间件详解(Custom middleware)
- 通过实现代理执行流程中特定点运行的钩子来构建自定义中间件。

Hook(钩子)
Node-style hooks(节点样式挂钩)
- 在特定执行点按顺序运行。用于日志记录、验证和状态更新。
before_agent - 在代理启动之前(每次调用一次)
before_model - 每次模型调用之前
after_model - 每个模型响应后
after_agent - 代理完成后(每次调用一次)
from langchain.agents.middleware import before_model, after_model, AgentState
from langchain.messages import AIMessage
from langgraph.runtime import Runtime
from typing import Any
@before_model(can_jump_to=["end"])
def check_message_limit(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
if len(state["messages"]) >= 50:
return {
"messages": [AIMessage("Conversation limit reached.")],
"jump_to": "end"
}
return None
@after_model
def log_response(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
print(f"Model returned: {
state['messages'][-1].content}")
return None
from langchain.agents.middleware import AgentMiddleware, AgentState, hook_config
from langchain.messages import AIMessage
from langgraph.runtime import Runtime
from typing import Any
class MessageLimitMiddleware(AgentMiddleware):
def __init__(self, max_messages: int = 50):
super().__init__()
self.max_messages = max_messages
@hook_config(can_jump_to=["end"])
def before_model(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
if len(state["messages"]) == self.max_messages:
return {
"messages": [AIMessage("Conversation limit reached.")],
"jump_to": "end"
}
return None
def after_model(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
print(f"Model returned: {
state['messages'][-1].content}")
return None
Wrap-style hooks(装饰器样式挂钩)
@wrap_model_call - 用自定义逻辑包装每个模型调用
@wrap_tool_call - 用自定义逻辑包装每个工具调用
Convenience(动态便利性)
@dynamic_prompt - 生成动态系统提示
from langchain.agents.middleware import (
before_model,
wrap_model_call,
AgentState,
ModelRequest,
ModelResponse,
)
from langchain.agents import create_agent
from langgraph.runtime import Runtime
from typing import Any, Callable
@before_model
def log_before_model(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
print(f"About to call model with {
len(state['messages'])} messages")
return None
@wrap_model_call
def retry_model(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
for attempt in range(3):
try:
return handler(request)
except Exception as e:
if attempt == 2:
raise
print(f"Retry {
attempt + 1}/3 after error: {
e}")
agent = create_agent(
model=