LangChain1.0智能体开发:中间件(Middleware)

阅读本文您将获得:

  • 智能体中间件的作用
  • 智能体中间件的使用方法
  • LangChain内置的中间件
  • 如何自定义中间件
  • 中间件的执行顺序
  • 最佳实践经验

1、智能体中间件

中间件能够控制和定制化智能体每一步的执行过程 中间件提供了一种更严格地控制智能体内部运作的方式。 核心的智能体循环包括调用模型、让模型选择要执行的工具,以及当模型不再调用工具时结束循环:


中间件会在上述每个步骤的前后暴露钩子函数(hooks)。

2、中间件能做什么

  • 运行监控
    通过日志记录、数据分析和调试来跟踪智能体行为
  • 任务适配
    提示词转换、工具选择和输出格式化
  • 流程控制
    添加重试、备用方案和提前终止逻辑
  • 强制规范
    应用速率限制、安全防护和个人身份信息(PII)检测

3、基本用法

在创建Agent时,将中间件列表传递给create_agent接口的middleware参数:

python 复制代码
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware, HumanInTheLoopMiddleware

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[SummarizationMiddleware(), HumanInTheLoopMiddleware()],
)

4、内置中间件

  • 任务适配
    4.1 SummarizationMiddleware(摘要中间件)
    4.2 AnthropicPromptCachingMiddleware(Anthropic提示词缓存中间件)
    4.3 LLMToolSelectorMiddleware(LLM工具选择中间件)
    4.4 ContextEditingMiddleware(上下文编辑中间件)
  • 流程控制
    4.2 HumanInTheLoopMiddleware(人工介入中间件)
    4.6 ModelFallbackMiddleware(模型回退中间件)
    4.8 TodoListMiddleware(待办事项中间件)
    4.10 ToolRetryMiddleware(工具重试中间件)
    4.11 LLMToolEmulator(LLM工具模拟器)
  • 强制规范
    4.4 ModelCallLimitMiddleware(模型调用限制中间件)
    4.5 ToolCallLimitMiddleware(工具调用限制中间件)
    4.7 PIIMiddleware(PII检测中间件)

5、自定义中间件

有两种方式创建中间件:

  • 基于装饰器(Decorator-based)------ 适用于单钩子中间件,快捷且简单
  • 基于类(Class-based)------ 适用于包含多个钩子的复杂中间件,功能更强大

5.1 基于装饰器创建中间件

对于仅需单个钩子函数(hook)的简单中间件而言,装饰器(decorator)是添加功能的最快方式。

python 复制代码
from langchain.agents.middleware import before_model, after_model, wrap_model_call
from langchain.agents.middleware import AgentState, ModelRequest, ModelResponse, dynamic_prompt
from langchain.messages import AIMessage
from langchain.agents import create_agent
from langgraph.runtime import Runtime
from typing import Any, Callable


# Node-style: logging before model calls
@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

# Node-style: validation after model calls
@after_model(can_jump_to=["end"])
def validate_output(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
    last_message = state["messages"][-1]
    if "BLOCKED" in last_message.content:
        return {
            "messages": [AIMessage("I cannot respond to that request.")],
            "jump_to": "end"
        }
    return None

# Wrap-style: retry logic
@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}")

# Wrap-style: dynamic prompts
@dynamic_prompt
def personalized_prompt(request: ModelRequest) -> str:
    user_id = request.runtime.context.get("user_id", "guest")
    return f"You are a helpful assistant for user {user_id}. Be concise and friendly."

# Use decorators in agent
agent = create_agent(
    model="gpt-4o",
    middleware=[log_before_model, validate_output, retry_model, personalized_prompt],
    tools=[...],
)

可用的装饰器:

  • 节点式(在特定执行节点运行):
    @before_agent------ 智能体启动前(每次调用执行一次)
    @before_model------ 每次调用模型前
    @after_model------ 每次接收模型响应后
    @after_agent------ 智能体执行完成后(每次调用执行一次)
  • 封装式(拦截并控制执行流程):
    @wrap_model_call------ 围绕每次模型调用(全程拦截)
    @wrap_tool_call------ 围绕每次工具调用(全程拦截)
  • 便捷装饰器:
    @dynamic_prompt------ 生成动态系统提示词(等同于能修改提示词的@wrap_model_call装饰器)

5.2 基于类创建中间件

以下情况适合使用基于类创建中间件:

  • 需要多个钩子函数(hooks)
  • 复杂配置
  • 跨项目复用(初始化时配置)

两种类型的钩子:

  • 节点式钩子:在执行流程的特定节点运行。
    • before_agent------ 智能体启动前(每次调用执行一次)
    • before_model------ 每次调用模型前
    • after_model------ 每次接收模型响应后
    • after_agent------ 智能体执行完成后(每次调用最多执行一次)
  • 封装式钩子:当handler被调用时,拦截执行并控制。
    • wrap_model_call------ 围绕每次模型调用(全程拦截)
    • wrap_tool_call------ 围绕每次工具调用(全程拦截) 你可以决定handler的调用次数:零次(短路)、一次(正常流程)或多次(重试逻辑)。
python 复制代码
from langchain.agents.middleware import AgentMiddleware, AgentState
from langgraph.runtime import Runtime
from typing import Any

class LoggingMiddleware(AgentMiddleware):
    def before_model(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
        print(f"About to call model with {len(state['messages'])} messages")
        return None

    def after_model(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
        print(f"Model returned: {state['messages'][-1].content}")
        return None

6、中间件执行顺序

6.1 关键规则

  • before_* 钩子函数:按顺序执行(从第一个到最后一个)
  • after_* 钩子函数:按逆序执行(从最后一个到第一个)
  • wrap_* 钩子函数:嵌套执行(第一个中间件包裹所有其他中间件)

6.2 跳转功能

若要从中间件中提前退出,需返回一个包含jump_to的字典。

可用的跳转目标:

  • "end":跳转到智能体执行流程的末尾
  • "tools":跳转到工具节点
  • "model":跳转到模型节点(或第一个 before_model 钩子函数)

注意:当从before_model或after_model钩子函数中发起跳转时,跳转到"model"会导致所有before_model中间件重新运行。

若要启用跳转功能,需用 @hook_config(can_jump_to=[...]) 装饰你的钩子函数。

python 复制代码
from langchain.agents.middleware import AgentMiddleware, hook_config
from typing import Any

class ConditionalMiddleware(AgentMiddleware):
    @hook_config(can_jump_to=["end", "tools"])
    def after_model(self, state: AgentState, runtime) -> dict[str, Any] | None:
        if some_condition(state):
            return {"jump_to": "end"}
        return None

7、最佳实践经验总结

  • 保持中间件专注性 ------ 每个中间件应专注做好一件事
  • 优雅地处理错误 ------ 避免中间件错误导致智能体崩溃
  • 使用合适的钩子类型:
    • 节点式(Node-style)适用于顺序逻辑(如日志记录、验证)
    • 封装式(Wrap-style)适用于控制流(如重试、备用方案、缓存)
  • 清晰地文档化所有自定义状态属性
  • 集成前独立对中间件进行单元测试
  • 考虑执行顺序 ------ 将关键中间件放在列表首位
  • 尽可能使用内置中间件,避免重复造轮子。
相关推荐
是一碗螺丝粉13 小时前
LangChain 核心组件深度解析:模型与提示词模板
前端·langchain·aigc
两万五千个小时13 小时前
落地实现 Anthropic Multi-Agent Research System
人工智能·python·架构
用户48159301959113 小时前
揭秘GPT-4与LLaMA背后的加速黑科技:KV Cache、MQA、GQA、稀疏注意力与MoE全解析
人工智能
程序员柒叔13 小时前
Dify 流水线知识库(RAG Pipeline)深度分析
agent
用户51914958484513 小时前
Cisco SMA 暴露面检测工具 - 快速识别CVE-2025-20393风险
人工智能·aigc
碳基沙盒13 小时前
AI工具的“超级外挂”:从零手把手教你搭建私人 MCP 服务器
人工智能
马腾化云东13 小时前
Agent开发应知应会(langfuse):Langfuse Score概念详解和实战应用
人工智能·llm·ai编程
Baihai_IDP13 小时前
HackerNews 热榜第一名:AGI 的 A,原来代表的是 Ads(广告)
人工智能·程序员·llm
ma_king13 小时前
claude+tmux 团队模式使用
人工智能·claude
蓝桉_T13 小时前
Ollama 本地跑 DeepSeek-Coder V3 保姆级教程(Java 调用示例)
人工智能