热闻岛
返回全网热点

Middleware:LangChain 里最容易被忽视的企业级能力

2天前16 阅读
Middleware:LangChain 里最容易被忽视的企业级能力配图
Agent 想上线,必须有 Middleware。它不是锦上添花,而是生产系统的安全带。 01 Middleware 是 Agent 的“拦截器” 裸 Agent 的逻辑很简单:模型思考,决定调工具,工具返回,模型继续。 这个链路能跑 De
Middleware:LangChain 里最容易被忽视的企业级能力配图

Agent 想上线,必须有 Middleware。它不是锦上添花,而是生产系统的安全带。

01 Middleware 是 Agent 的“拦截器”

裸 Agent 的逻辑很简单:模型思考,决定调工具,工具返回,模型继续。

这个链路能跑 Demo。

但生产环境不够。

生产环境要回答这些问题:谁在调用?能不能调用?花了多少钱?失败怎么办?结果能不能出?敏感数据有没有泄露?

这些问题不应该散落在业务代码里。它们应该统一进入 Middleware。

一句话:Middleware 不负责让模型变聪明,它负责让模型变可控。

Middleware:LangChain 里最容易被忽视的企业级能力配图

02 为什么它是企业级能力

真正的 Agent 不是“会聊天”。

真正的 Agent 是“会按规则执行任务”。

用户身份要校验。

工具权限要校验。

模型调用要限流。

失败要重试。

高风险动作要人工审批。

输出要检查。

每一步要能追踪。

这些都不是业务函数本身的职责。

业务函数只负责“做事”。Middleware 负责“管事”。

03 六个 Hook:看懂就掌握一半

LangChain Middleware 有两种风格。

一种是 Node-style。它像流程节点,按顺序执行。

另一种是 Wrap-style。它像包装器,包住模型调用或工具调用。

Middleware:LangChain 里最容易被忽视的企业级能力配图

Node-style:适合顺序动作

before_agent:整个 Agent 开始前执行一次。

before_model:每次模型调用前执行。

after_model:每次模型返回后执行。

after_agent:整个 Agent 结束后执行一次。

这类 Hook 适合做日志、校验、计数、状态更新、提前终止。

Wrap-style:适合控制调用

wrap_model_call:包住模型调用。

wrap_tool_call:包住工具调用。

这类 Hook 适合做重试、缓存、模型降级、工具权限、超时兜底。

04 源码入口:AgentMiddleware

源码里,Middleware 的核心抽象就是 AgentMiddleware。

它不是一个神秘对象。它就是一个基类。

你继承它,然后选择实现某几个方法。

实现 before_model,就能在模型调用前插手。

实现 wrap_model_call,就能包住模型调用。

实现 wrap_tool_call,就能包住工具调用。

实现 after_agent,就能在 Agent 结束后统一落日志。

源码设计的关键点是:你不需要改 Agent 主循环。你只要写 Middleware。

Middleware:LangChain 里最容易被忽视的企业级能力配图

05 ModelRequest:模型调用前的“请求包”

wrap_model_call 拿到的不是一串字符串。

它拿到的是 ModelRequest。

这个对象里放着模型调用需要的一切。

model:当前要调用的模型。

messages:当前上下文消息。

system_message:系统指令。

tools:当前可用工具。

tool_choice:工具选择策略。

response_format:结构化输出配置。

state:Agent 当前状态。

runtime:运行时上下文。

这就是为什么 Middleware 能做动态 Prompt、动态模型选择、动态工具裁剪。

因为它拿到的不是结果,而是“即将发给模型的完整请求”。

源码里的 request.override(...) 很关键:它不是直接改老请求,而是生成一个修改后的新请求。这样更安全,也更容易组合。

06 ModelResponse 与 Command:结果如何回写状态

模型返回后,源码会把结果包装成 ModelResponse。

里面通常有两类东西。

result:模型返回的消息。

structured_response:结构化输出结果。

如果 Middleware 不只想改返回结果,还想更新状态,就要用 ExtendedModelResponse。

它比普通响应多了一个 Command。

Command 的作用很直接:告诉图运行时,往 AgentState 里更新什么。

比如模型调用次数、token 用量、风险标记、审计标签,都可以这样写回去。

理解这个点:Middleware 不只是“看一眼”。它可以读请求、改请求、拦响应、改状态。

07 ToolCallRequest:工具调用也能被拦截

wrap_tool_call 拿到的是 ToolCallRequest。

它包含这次工具调用的工具名、参数、工具对象、state 和 runtime。

这给了企业系统非常重要的控制点。

调数据库前,先验权限。

发邮件前,先人工审批。

查用户隐私前,先脱敏。

工具超时后,返回标准兜底 ToolMessage。

模型可以提出工具调用。

但真正能不能执行,应该由 Middleware 决定。

08 多个 Middleware 如何组合

企业项目不会只有一个 Middleware。

通常是一串。

比如:PII 脱敏、Prompt 版本、调用限额、模型重试、工具审批、审计日志。

顺序很重要。

Middleware:LangChain 里最容易被忽视的企业级能力配图

before_*:按列表顺序,从前到后。

wrap_*:像洋葱一样嵌套,第一个包住所有后面的。

after_*:反过来,从后到前。

所以关键规则要放前面。

比如预算、权限、安全。

业务小修饰可以放后面。

09 Agent jumps:中间件可以改变流程

Middleware 还可以让 Agent 提前跳转。

源码里有 jump_to 这个状态字段。

jump_to = end:直接结束。

jump_to = tools:跳到工具节点。

jump_to = model:回到模型节点。

这很适合做硬规则。

比如命中违规内容,直接结束。比如工具结果不完整,回模型重问。比如风险动作,先跳审批。

不要把所有判断都交给模型。规则明确的地方,用 Middleware 硬控。

10 内置 Middleware:常见能力不用从零写

LangChain 已经提供了一批内置 Middleware。

它们覆盖了生产 Agent 的高频问题。

Middleware:LangChain 里最容易被忽视的企业级能力配图

如果只是做摘要、PII、人工审批、重试、降级、调用次数限制,优先用内置。

自定义 Middleware 留给企业自己的规则。

11 企业项目怎么设计 Middleware Stack

不要一个 Middleware 管所有事。

一个 Middleware 只做一件事。

这样好测试,好替换,好排查。

Middleware:LangChain 里最容易被忽视的企业级能力配图

推荐分层

RequestMiddleware:生成 requestId,记录用户身份和入口参数。

PIIMiddleware:输入发给模型前先脱敏。

PromptMiddleware:按场景选择 system prompt 和版本。

BudgetMiddleware:限制模型调用次数、工具调用次数和 token 成本。

FallbackMiddleware:模型失败时切换备用模型。

ToolAuthMiddleware:工具执行前做权限和参数校验。

AuditMiddleware:把模型输入、工具参数、工具结果、最终答案写入日志。

这套分层做完,Agent 才像一个后端服务。

12 源码级总结:把链路压缩成一条线

create_agent 接收 middleware。

装配阶段识别 AgentMiddleware、state_schema、tools、transformers。

Node-style hook 编进 LangGraph 的执行节点。

Wrap-style hook 包住模型调用和工具调用。

ModelRequest / ToolCallRequest 带着 state 和 runtime 进入 hook。

handler 是真正执行模型或工具的入口。

hook 可以调用 handler,也可以重试、短路、替换请求。

返回 ModelResponse、ToolMessage 或 Command。

Command 通过 reducer 更新 AgentState。

Agent 继续循环,直到没有 tool_calls 或被 jump_to=end 结束。

所以 Middleware 的本质不是“额外功能”。它是 Agent Runtime 的控制面。

13 常见坑

坑一:所有逻辑写进一个大 Middleware

最后会变成第二个业务系统。

拆。日志是日志,权限是权限,预算是预算。

坑二:把 after_model 当安全出口

after_model 已经在模型返回之后。

如果你要防止敏感数据发给模型,要在 before_model 或 wrap_model_call 做。

坑三:wrap 里忘记调用 handler

不调用 handler,就是短路。

这可以用于缓存和拦截,但不能误用。

坑四:工具权限只写在工具函数里

太晚。

权限应该在 wrap_tool_call 里统一做。工具函数只负责业务执行。

坑五:没有记录中间状态

Agent 出错时,你必须知道错在哪。

是 Prompt 错、模型错、工具参数错、工具返回错,还是 Middleware 拦截错。

Middleware:LangChain 里最容易被忽视的企业级能力配图

14 总结

Middleware 是 LangChain 新版 Agent 里最像后端工程的部分。

它把横切能力从业务代码里抽出来。

它让 Agent 有规则。

它让模型调用可追踪。

它让工具调用可审计。

它让失败有兜底。

它让高风险动作能暂停。

最终结论:没有 Middleware 的 Agent,是会跑的 Demo;有 Middleware 的 Agent,才是能上线的系统。

要点速读

Agent 想上线,必须有 Middleware。它不是锦上添花,而是生产系统的安全带。 01 Middleware 是

  • Agent 想上线,必须有 Middleware
  • 它不是锦上添花,而是生产系统的安全带
  • 01 Middleware 是