LangChain v1第 13 篇

第 7 章:自定义 `AgentMiddleware`

只在预制 middleware 无法表达需求时自定义。常用钩子:beforeagent/afteragent 观察整次运行,beforemodel/aftermodel 修改或检查 state,wrapmodelcall 动态选择模型,wraptoolcall 拦截单次工具。

本站只展示学习文档。示例不会在构建或部署时执行;手动运行可能需要 API Key 并产生模型费用。

约 364 字·预计阅读 2 分钟

只在预制 middleware 无法表达需求时自定义。常用钩子:before_agent/after_agent 观察整次运行,before_model/after_model 修改或检查 state,wrap_model_call 动态选择模型,wrap_tool_call 拦截单次工具。

class AllowListedTools(AgentMiddleware):
    def wrap_tool_call(self, request, handler):
        if request.tool_call["name"] not in {"multiply"}:
            return ToolMessage(
                content="该工具不在本次允许列表中。",
                name=request.tool_call["name"],
                tool_call_id=request.tool_call["id"],
                status="error",
            )
        return handler(request)

如果调用方使用 ainvoke 或 astream,同步钩子不足以覆盖工具路径;同时实现 async def awrap_tool_call(self, request, handler),其中允许路径写 return await handler(request)。反过来,纯同步 invoke 使用 wrap_tool_call。这是本版 middleware 最容易遗漏的异步契约。

钩子 输入 适合做什么 不适合做什么
before_model(state, runtime) 当前 state 和 Runtime.context 轻量状态校验、添加受控上下文 长时间 I/O
after_model 新 AIMessage 已写入 state 审查工具调用、触发 HITL 重新实现工具循环
wrap_model_call(request, handler) 模型请求和继续函数 根据上下文选择模型、记录预算 悄悄改变业务输出契约
wrap_tool_call(request, handler) 单个 tool call allow-list、授权、统一工具错误 替代工具自身的输入验证

Middleware 仍不是安全边界的唯一层:工具函数必须验证身份和输入,服务端必须进行授权。运行 11_custom_middleware.py 会本地断言拒绝结果携带匹配的 tool call id,并真实调用允许的 multiply。

参考资源与示例代码