LangChain框架之Middleware-用钩子控制Agent运行过程

    |     2026年8月27日   |   AI大模型应用, LangChain框架   |     0 条评论   |    29

上篇你分清了 State / Store / Context——三种「记住」各管一段。可还有横切需求:邮箱别进模型、别让工具死循环烧钱、历史太长要摘要、发信前要人审。这些不该靠「多写几个 tool」碰运气。这篇讲 Middleware:在 Agent 循环的钩子上嵌入预定义(以及可自定义)逻辑。


小明想「偷偷」改 Agent 行为

私厨上线后,合规同学说:

用户消息里的邮箱必须脱敏,不能原样进模型。

运维又说:

有人故意让 Agent 连调工具 50 次,账单炸了。

小明第一反应:在 chat() 里写 if、在工具里写计数器。改了三处,还有漏网。

他去找老张:”有没有挂在框架上、每次调模型前后都会跑的拦截器?”

老张说:”有。Middleware 在智能体运行各过程预留 hook,方便嵌入自定义操作。可以自己写,也可以先用 LangChain Prebuilt。”


什么是 Middleware

agent.invoke
  → middleware before_*
  → 调用模型
  → middleware after_*
     ├─ 有 tool_calls → 执行工具 → 再回 before_*
     └─ 无 tool_calls → 返回

“它不是另一套 Runtime,而是插在标准循环上的横切逻辑:安全、限流、摘要、HITL……

挂载就一行列表:”

agent = create_agent(
  model,
  tools=[...],
  middleware=[
    PIIMiddleware("email", strategy="redact", apply_to_input=True),
  ],
)
中间件(节选) 作用 本课
PIIMiddleware 检测/脱敏 PII Demo A
ModelCallLimitMiddleware 限制模型调用次数 Demo B
SummarizationMiddleware 历史过长自动摘要 Demo C
HumanInTheLoopMiddleware 工具前人工审批 Day12 对照
ToolRetry / ModelFallback 等 重试、降级 认知级

官方清单:https://docs.langchain.com/oss/python/langchain/middleware/built-in

Tool 改 State/Store Middleware
时机 模型选中工具时 每次模型/工具步骤前后
典型用途 读写记忆 脱敏、限流、摘要、人审
是否依赖模型选型 是 否(框架强制执行)

“高级用法里,导图点到动态修改请求参数(如 RAG 的 @dynamic_prompt 每次检索后改 Prompt)——本质也是钩子里改发给模型的内容。本篇先把 Prebuilt 跑通;自定义 before_model 深挖可后置。”


代码拆解:三个 Prebuilt + HITL 对照

1. Demo A:PII 脱敏

def build_pii_agent():
  return create_agent(
    get_chat_model(),
    tools=[],
    system_prompt="你是简洁助教。用户让你复述信息时,按收到的文本如实复述。",
    middleware=[
      PIIMiddleware("email", strategy="redact", apply_to_input=True),
    ],
  )

main.py 对比「进模型前」与回复:

raw = "我的邮箱是 alice@example.com,请原样复述邮箱。"
result = agent.invoke({"messages": [{"role": "user", "content": raw}]})
human = result["messages"][0]
print("进入模型的 HumanMessage:", human.content)

“期望:HumanMessage 里出现 [REDACTED_EMAIL] 一类占位。这就是开启中间件前后的行为差——验收点。”

2. Demo B:模型调用上限

def build_limit_agent():
  return create_agent(
    get_chat_model(),
    tools=TOOLS,
    system_prompt="你是算术助教。凡加减必须调用 add 工具,不要心算。",
    checkpointer=InMemorySaver(),
    middleware=[
      ModelCallLimitMiddleware(run_limit=1, exit_behavior="end"),
    ],
  )

“故意出题:必须两次调用 add。run_limit=1 只允许单次 invoke 内 1 次模型调用,多步任务会被截断并优雅 end,避免死循环烧钱。
thread_limit 跨多次 invoke 累计,通常要配 checkpointer。”

3. Demo C:自动摘要

SummarizationMiddleware(
  model=model,
  trigger=("messages", 6),
  keep=("messages", 2),
)

“同一 thread_id 多轮后触发摘要,压缩旧消息、保留最近若干条。教学用低阈值;生产常用 (\"tokens\", N)。这和 Memory 篇的「总结策略」是同一块肌肉。”

4. HITL 对照(认知即可)

HumanInTheLoopMiddleware(
  interrupt_on={
    "send_email": {"allowed_decisions": ["approve", "edit", "reject"]},
    "read_email": False,
  }
)

“读信自动放行,发信必须人审。需要 checkpointer + Command(resume=...)。本篇知道:危险工具可以挂 HITL 中间件。”

小明复述:”中间件是钩子列表;PII 改输入,Limit 卡次数,Summarize 压历史;发信用人审。”


总结

老张说:”第十篇只办一件事——给 Agent 循环装上可插拔钩子。”

“三个核心理解:

  1. Middleware = 运行过程中的 hook —— 不是新 Runtime,是横切增强
  2. 先用 Prebuilt —— PII / ModelCallLimit / Summarization 覆盖安全、成本、上下文
  3. 可组合、可进阶 —— 列表叠加;HITL、动态改 Prompt 在后续场景展开”

LangChain 支线进度:

… → Runtime
    ↓
Middleware(本篇:Prebuilt 钩子)
    ↓
多 Agent → Agentic RAG …

小明说:”横切能力有了。复杂流程若要研究员+写手+编辑,就该多 Agent 了。”

“对。下一篇:多 Agent 协作。”

能改工具结果,不如在框架钩子上统一改行为。Middleware 让安全与成本策略变成配置,而不是散落的 if。

转载请注明来源:LangChain框架之Middleware-用钩子控制Agent运行过程
本文链接地址:https://ai.zhousir.top/?p=3872
回复 取消