LangChain中间件教程及DeepAgents应用
一、中间件概述
1.1 什么是中间件
LangChain 中间件是一套拦截并扩展 Agent 执行流程的机制,它允许开发者在不修改 Agent 核心逻辑的前提下,为 Agent 注入横切能力(如重试、限流、安全校验、上下文管理等),是构建生产级 Agent 的核心工具。
中间件基于钩子(Hook)机制运行,可以在 Agent 执行的特定节点插入自定义逻辑,也可以包裹整个模型/工具调用过程,实现对执行流的完全控制。
1.2 中间件的分类
LangChain 中间件分为两大类:
- 预置通用中间件:官方提供的开箱即用组件,兼容所有 LLM 厂商,覆盖绝大多数通用场景,无需自行开发。
- 自定义中间件:通过标准 Hook 接口开发,满足业务定制化需求,支持扩展状态、上下文、流处理等能力。
1.3 核心价值
- 解耦 业务与横切逻辑:重试、限流、日志、安全等通用能力与业务逻辑分离,便于维护。
- 开箱即用:预置中间件经过生产验证,配置简单,快速落地。
- 高度可扩展:自定义 Hook 机制支持任意复杂的定制逻辑。
- 可组合性:多个中间件可串联使用,按顺序叠加能力。
二、预置通用中间件详解
所有通用中间件均可兼容 OpenAI、Anthropic、Google 等任意 LLM 提供商,按功能分为 6 大类。
2.1 上下文管理类
用于长对话场景下的 Token 控制与上下文优化,避免超出模型上下文窗口。
2.1.1 对话摘要中间件(summarizationMiddleware)
功能:当对话 Token 数接近阈值时,自动压缩历史消息生成摘要,仅保留最近 N 条完整消息,在保留上下文语义的同时控制 Token 总量。
适用场景:
- 长运行对话、多轮交互应用
- 需要保留完整对话语义的场景
- 模型上下文窗口有限的场景
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
model | string / BaseChatModel | 是 | - | 用于生成摘要的模型。支持模型标识字符串(如 'openai:gpt-5.4-mini')或模型实例。 |
trigger | object / object[] | 否 | 不自动触发 | 摘要触发条件: • 单对象:AND 逻辑,所有属性同时满足才触发 • 对象数组:OR 逻辑,任一条件满足即触发 每个条件可包含: • fraction:模型上下文窗口占比(0-1),依赖模型 profile 数据 • tokens:绝对 Token 数量阈值 • messages:消息条数阈值 |
keep | object | 否 | { messages: 20 } | 摘要后保留的上下文量,三选一: • fraction:保留模型上下文占比(0-1) • tokens:保留的绝对 Token 数 • messages:保留的最近消息条数 |
tokenCounter | function | 否 | 字符计数 | 自定义 Token 统计函数,用于更精准的阈值判断。 |
summaryPrompt | string | 否 | 内置模板 | 自定义摘要提示词模板,必须包含 {messages} 占位符。 |
trimTokensToSummarize | number | 否 | 4000 | 生成摘要前裁剪历史消息的最大 Token 上限,避免摘要模型自身超限。 |
summaryPrefix | string | 否 | 内置前缀 | 摘要消息的前缀文本,用于标识历史摘要。 |
maxTokensBeforeSummary | number | 废弃 | - | 已废弃,改用 trigger: { tokens: 值 }。 |
messagesToKeep | number | 废弃 | - | 已废弃,改用 keep: { messages: 值 }。 |
代码示例:
import { createAgent, summarizationMiddleware } from "langchain";
// 单条件触发
const agent = createAgent({
model: "gpt-5.5",
tools: [weatherTool, calculatorTool],
middleware: [
summarizationMiddleware({
model: "gpt-5.4-mini",
trigger: { tokens: 4000, messages: 10 },
keep: { messages: 20 },
}),
],
});
// 多条件(OR逻辑)+ 占比阈值
const agent3 = createAgent({
model: "gpt-5.5",
tools: [weatherTool, calculatorTool],
middleware: [
summarizationMiddleware({
model: "gpt-5.4-mini",
trigger: { fraction: 0.8 },
keep: { fraction: 0.3 },
}),
],
});
注意:摘要仅压缩文本内容,图片、音视频等多模态数据不会被压缩。多模态场景建议将媒体存入文件系统,仅传递引用链接。
2.1.2 上下文编辑中间件(contextEditingMiddleware)
功能:通过清理旧的工具调用输出来回收 Token,保留最近的工具结果,比全量摘要更轻量,对对话语义影响更小。
适用场景:
- 工具调用频繁的长对话
- 降低 Token 成本
- 仅需保留近期工具结果的场景
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
edits | ContextEdit[] | 否 | [new ClearToolUsesEdit()] | 上下文编辑策略数组,核心策略为 ClearToolUsesEdit |
ClearToolUsesEdit 子配置:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
triggerTokens | number | 否 | 100000 | 触发清理的对话 Token 阈值,超过该值则开始清理旧工具结果。 |
clearAtLeast | number | 否 | 0 | 单次清理最少回收的 Token 数;设为 0 表示按需清理。 |
keep | number | 否 | 3 | 必须保留的最近工具结果数量,永远不会被清理。 |
clearToolInputs | boolean | 否 | false | 是否同时清空 AI 消息中的工具调用参数;为 true 时参数会被替换为空对象。 |
excludeTools | string[] | 否 | [] | 排除清理的工具名称列表,列表内工具的输出永远保留。 |
placeholder | string | 否 | "[cleared]" | 工具输出被清理后的占位替换文本。 |
代码示例:
import { createAgent, contextEditingMiddleware, ClearToolUsesEdit } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [searchTool, calculatorTool, databaseTool],
middleware: [
contextEditingMiddleware({
edits: [
new ClearToolUsesEdit({
triggerTokens: 2000,
keep: 3,
clearToolInputs: false,
excludeTools: [],
placeholder: "[cleared]",
}),
],
}),
],
});
2.1.3 服务端工具搜索中间件(providerToolSearchMiddleware)
功能:将工具延迟到模型厂商的服务端搜索,不把所有工具 Schema 一次性塞给模型,减少上下文膨胀,提升工具选择准确率。
适用场景:
- 工具数量多(数十个以上)
- 减少上下文冗余
- 提升工具选择准确率
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
searchableTools | (string / StructuredToolInterface)[] | 否 | 仅标记工具生效 | 需要延迟加载的工具列表,支持工具名或工具实例。 补充:工具构造时设置 extras.defer_loading: true 也可自动延迟,无需在此处重复声明。 |
限制:仅支持具备服务端工具搜索能力的模型,如 Anthropic Claude 4+ 系列、OpenAI gpt-5.5+。
代码示例:
import { createAgent, providerToolSearchMiddleware } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const getWeather = tool(async () => "Sunny, 22C", {
name: "get_weather",
description: "Get the current weather for a city",
schema: z.object({ city: z.string() }),
});
const nicheTools = [lookupOrderStatus];
const agent = createAgent({
model: "anthropic:claude-opus-4-8",
tools: [getWeather, ...nicheTools],
middleware: [
providerToolSearchMiddleware({ searchableTools: nicheTools }),
],
});
2.2 成本与限流类
用于控制 API 调用量,防止 Agent 失控导致成本飙升。
2.2.1 模型调用限流中间件(modelCallLimitMiddleware)
功能:限制单轮或单线程内的模型调用次数,防止无限循环与成本失控。
适用场景:
- 生产环境成本管控
- 测试环境预算控制
- 防止 runaway agent
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
threadLimit | number | 否 | 无限制 | 单个对话线程(跨多次 invoke 调用)的总模型调用上限,必须配合 checkpointer 使用才能持久化计数。 |
runLimit | number | 否 | 无限制 | 单次用户请求(一次 invoke 周期)内的模型调用上限,每次新请求自动重置。 |
exitBehavior | string | 否 | "end" | 达到上限后的执行行为: • "end":优雅终止,返回结束消息 • "error":抛出异常,立即中断执行 |
代码示例:
import { createAgent, modelCallLimitMiddleware } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
const agent = createAgent({
model: "gpt-5.5",
checkpointer: new MemorySaver(), // 线程限流必需
tools: [],
middleware: [
modelCallLimitMiddleware({
threadLimit: 10,
runLimit: 5,
exitBehavior: "end",
}),
],
});
2.2.2 工具调用限流中间件(toolCallLimitMiddleware)
功能:控制工具调用频次,可全局生效或针对单个工具精细化限流。
适用场景:
- 限制高成本外部 API
- 保护数据库/搜索接口
- 防速率超限
- 防止 runaway agent 循环调用
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
toolName | string | 否 | 全局生效 | 指定单个工具的名称;不填则对所有工具全局生效。可多次实例化实现多工具分别限流。 |
threadLimit | number | 否 | 无限制 | 线程级工具调用上限,跨调用持久化,需 checkpointer 支持。 |
runLimit | number | 否 | 无限制 | 单次请求内工具调用上限,每轮对话重置。 ⚠️ threadLimit 和 runLimit 至少指定一个。 |
exitBehavior | string | 否 | "continue" | 达到上限后的行为: • "continue:拦截超限调用并返回错误消息,Agent 继续运行 • "error":抛出 ToolCallLimitExceededError 异常,立即终止 • "end":立即停止并返回工具消息+AI消息,仅单工具限流下可用 |
代码示例:
import { createAgent, toolCallLimitMiddleware } from "langchain";
const globalLimiter = toolCallLimitMiddleware({ threadLimit: 20, runLimit: 10 });
const searchLimiter = toolCallLimitMiddleware({ toolName: "search", threadLimit: 5, runLimit: 3 });
const strictLimiter = toolCallLimitMiddleware({ toolName: "scrape_webpage", runLimit: 2, exitBehavior: "error" });
const agent = createAgent({
model: "gpt-5.5",
tools: [searchTool, databaseTool, scraperTool],
middleware: [globalLimiter, searchLimiter, strictLimiter],
});
2.3 可靠性与容错类
提升 Agent 在网络波动、服务故障场景下的稳定性。
2.3.1 模型降级中间件(modelFallbackMiddleware)
功能:主模型调用失败时,自动按优先级顺序尝试备用模型,保障服务高可用。
适用场景:
- 高可用生产部署
- 跨厂商容灾
- 成本优化
核心配置参数:
调用形式特殊:直接传入多个模型字符串作为可变长参数,而非配置对象。
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
...models | string[] | 是 | - | 按优先级排列的备用模型标识。主模型失败后,按传入顺序依次尝试。 |
代码示例:
import { createAgent, modelFallbackMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
modelFallbackMiddleware(
"gpt-5.4-mini",
"claude-3-5-sonnet-20241022"
),
],
});
2.3.2 模型重试中间件(modelRetryMiddleware)
功能:模型调用失败时,按指数退避策略自动重试,应对网络抖动、限流、临时故障。
适用场景:
- 处理网络超时、速率限制
- 临时服务不可用等瞬时故障
- 提升模型调用成功率
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
maxRetries | number | 否 | 2 | 初始调用失败后的最大重试次数;总调用次数 = 1 + maxRetries。取值 ≥ 0。 |
retryOn | Error[] / (error: Error) => boolean | 否 | () => true | 重试触发条件: • 错误构造函数数组:仅对指定类型的错误重试 • 自定义函数:接收错误对象,返回 true 则重试 |
onFailure | 'error' / 'continue' / (error: Error) => string | 否 | "continue" | 所有重试耗尽后的兜底行为: • "continue":返回包含错误信息的 AIMessage,Agent 继续处理 • "error":重新抛出异常,终止执行 • 自定义函数:返回字符串作为 AIMessage 内容 |
backoffFactor | number | 否 | 2.0 | 指数退避乘数;第 n 次重试延迟 = initialDelayMs * (backoffFactor ** n)。设为 0 则为固定延迟。取值 ≥ 0。 |
initialDelayMs | number | 否 | 1000 | 第一次重试前的初始等待时间,单位毫秒。取值 ≥ 0。 |
maxDelayMs | number | 否 | 60000 | 重试间最大等待时间,防止指数退避无限增长。取值 ≥ 0。 |
jitter | boolean | 否 | true | 是否给延迟添加 ±25% 的随机抖动,避免惊群效应。 |
代码示例:
import { createAgent, modelRetryMiddleware } from "langchain";
// 基础用法
const agent = createAgent({
model: "gpt-5.5",
tools: [searchTool],
middleware: [modelRetryMiddleware()],
});
// 自定义错误过滤 + 固定延迟
const constantBackoff = modelRetryMiddleware({
maxRetries: 5,
backoffFactor: 0.0, // 无指数增长
initialDelayMs: 2000, // 固定2秒
retryOn: (error) => error.name === "RateLimitError",
});
2.3.3 工具重试中间件(toolRetryMiddleware)
功能:工具调用失败时自动指数退避重试,逻辑与模型重试一致,专为外部 API、数据库等网络依赖工具设计。
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
tools | (ClientTool / ServerTool / string)[] | 否 | 全部工具 | 指定应用重试逻辑的工具列表,支持工具实例或工具名;不填则对所有工具生效。 |
maxRetries | number | 否 | 2 | 初始调用后的最大重试次数。 |
retryOn | Error[] / (error: Error) => boolean | 否 | () => true | 重试触发条件,同模型重试。 |
onFailure | 'error' / 'continue' /(error: Error) => string | 否 | "continue" | 重试耗尽后的行为: • "continue":返回带错误的 ToolMessage • "error":抛出异常终止 • 自定义函数:返回自定义错误文本 ⚠️ 废弃值:"raise" 对应 "error","return_message" 对应 "continue" |
backoffFactor | number | 否 | 2.0 | 指数退避乘数。 |
initialDelayMs | number | 否 | 1000 | 初始延迟毫秒数。 |
maxDelayMs | number | 否 | 60000 | 最大延迟上限。 |
jitter | boolean | 否 | true | 是否添加随机抖动。 |
代码示例:
import { createAgent, toolRetryMiddleware } from "langchain";
// 仅对特定工具生效 + 自定义错误文案
const formatError = (error: Error) =>
"Database temporarily unavailable. Please try again later.";
const retrySpecificTools = toolRetryMiddleware({
maxRetries: 4,
tools: ["search_database"],
onFailure: formatError,
});
2.4 安全合规类
2.4.1 人工介入中间件(humanInTheLoopMiddleware)
功能:在指定工具执行前暂停 Agent,等待人工审批、编辑或拒绝,为高风险操作增加人工把关。
适用场景:
- 高风险操作(数据库写入、财务交易)
- 合规强监管场景
- 需要人工引导的长任务
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
interruptOn | Record<string, object / false> | 是 | - | 按工具名配置中断规则: • 键:工具名称 • 值为 false:该工具不中断,直接执行 • 值为配置对象时: - allowedDecisions:允许的人工操作,可选 approve(批准)、edit(编辑参数)、reject(拒绝) |
⚠️ 必须配合 checkpointer 使用,用于持久化中断状态,支持跨会话恢复执行。
代码示例:
import { createAgent, humanInTheLoopMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [readEmailTool, sendEmailTool],
middleware: [
humanInTheLoopMiddleware({
interruptOn: {
sendEmailTool: {
allowedDecisions: ["approve", "edit", "reject"],
},
readEmailTool: false,
}
})
]
});
2.4.2 PII 检测中间件(piiMiddleware)
功能:检测对话中的个人身份信息(邮箱、信用卡、手机号等),支持多种脱敏处理策略。
适用场景:
- 医疗/金融合规场景
- 客服日志脱敏
- 敏感数据防护
核心配置参数:
调用形式:
piiMiddleware(piiType, options),第一个为位置参数,第二个为配置对象。
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
piiType(第1位位置参数) | string | 是 | - | PII 类型。内置类型:email、credit_card、ip、mac_address、url;也可自定义类型名配合 detector 使用。 |
strategy | string | 否 | "redact" | 检测到 PII 后的处理策略: • "block":抛出错误,阻断执行 • "redact":完整替换为 [REDACTED_类型名] • "mask":部分掩码(如信用卡保留后四位) • "hash":替换为确定性哈希,可跨会话关联但不可逆 |
detector | string / RegExp / (content: string) => PIIMatch[] | 否 | 内置检测器 | 自定义检测器,三种形式: • 字符串:正则表达式字符串 • RegExp 对象:正则实例,可指定匹配标志 • 自定义函数:接收文本,返回 PIIMatch[] 数组,支持复杂校验 |
applyToInput | boolean | 否 | true | 是否在模型调用前检查用户输入消息。 |
applyToOutput | boolean | 否 | false | 是否在模型调用后检查 AI 输出消息。 |
applyToToolResults | boolean | 否 | false | 是否检查工具执行后的返回结果。 |
PIIMatch 结构:
interface PIIMatch {
text: string; // 匹配到的文本
start: number; // 起始索引
end: number; // 结束索引
}
代码示例:
import { createAgent, piiMiddleware, type PIIMatch } from "langchain";
// 内置类型使用
const agent = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
piiMiddleware("email", { strategy: "redact", applyToInput: true }),
piiMiddleware("credit_card", { strategy: "mask", applyToInput: true }),
],
});
// 自定义检测器(正则方式)
const agent2 = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
piiMiddleware("api_key", {
detector: "sk-[a-zA-Z0-9]{32}",
strategy: "block",
}),
],
});
2.5 能力增强类
2.5.1 待办清单中间件(todoListMiddleware)
功能:为 Agent 自动注入 write_todos 工具和配套系统提示,赋予任务规划与进度跟踪能力。
适用场景:
- 复杂多步骤任务
- 长运行操作
- 需要可视化进度的场景
配置参数:无配置参数,使用默认值即可。
代码示例:
import { createAgent, todoListMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [readFile, writeFile, runTests],
middleware: [todoListMiddleware()],
});
2.5.2 LLM 工具选择器中间件(llmToolSelectorMiddleware)
功能:调用主模型前,先用一个轻量模型筛选出当前查询相关的工具,减少主模型的工具列表长度,降低 Token 消耗并提升准确率。
适用场景:
- 工具数量多(10+)
- 降低 Token 消耗
- 提升模型聚焦度与准确率
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
model | string / BaseChatModel | 否 | Agent 主模型 | 执行工具选择的模型,建议使用轻量小模型以降低成本。 |
systemPrompt | string | 否 | 内置提示 | 工具选择模型的系统提示词,用于指导筛选逻辑。 |
maxTools | number | 否 | 无限制 | 最多选中的工具数量;超过时仅取前 N 个。 |
alwaysInclude | string[] | 否 | [] | 强制包含的工具名列表,不计入 maxTools 限额。 |
代码示例:
import { createAgent, llmToolSelectorMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [tool1, tool2, tool3, tool4, tool5],
middleware: [
llmToolSelectorMiddleware({
model: "gpt-5.4-mini",
maxTools: 3,
alwaysInclude: ["search"],
}),
],
});
2.6 测试调试类
LLM 工具模拟器中间件(toolEmulatorMiddleware)
功能:用 LLM 生成模拟的工具返回结果,不执行真实工具,用于开发调试与原型验证。
适用场景:
- 开发阶段调试 Agent 逻辑
- 外部工具不可用时的开发
- 低成本原型验证
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
tools | (string / ClientTool / ServerTool)[] | 否 | 全部工具 | 指定要模拟的工具: • 不填/undefined:模拟所有工具 • 空数组 []:不模拟任何工具 • 非空数组:仅模拟列表内的工具 |
model | string / BaseChatModel | 否 | Agent 主模型 | 生成模拟工具响应的模型。 |
代码示例:
import { createAgent, toolEmulatorMiddleware } from "langchain";
// 仅模拟指定工具
const agent2 = createAgent({
model: "gpt-5.5",
tools: [getWeather, sendEmail],
middleware: [
toolEmulatorMiddleware({
tools: ["get_weather"],
}),
],
});
三、自定义中间件开发指南
当预置中间件无法满足业务需求时,可通过 createMiddleware 函数基于 Hook 机制开发自定义中间件。
3.1 两种 Hook 范式
中间件提供两类 Hook,分别对应不同的使用场景:
3.1.1 Node-style 钩子(节点式)
在 Agent 执行的特定节点顺序执行,适合日志、校验、状态更新等无侵入逻辑。
| 钩子 | 触发时机 |
|---|---|
beforeAgent | Agent 启动前(单次调用执行一次) |
beforeModel | 每次模型调用前 |
afterModel | 每次模型响应后 |
afterAgent | Agent 结束后(单次调用执行一次) |
示例:日志中间件
import { createMiddleware } from "langchain";
const loggingMiddleware = createMiddleware({
name: "LoggingMiddleware",
beforeModel: (state) => {
console.log(`调用模型,当前消息数: ${state.messages.length}`);
},
afterModel: (state) => {
const lastMsg = state.messages[state.messages.length - 1];
console.log(`模型返回: ${lastMsg.content}`);
},
});
3.1.2 Wrap-style 钩子(包裹式)
环绕包裹每次模型/工具调用,可以控制是否执行、执行次数、修改入参出参,适合重试、缓存、请求改写等控制流逻辑。
| 钩子 | 触发时机 |
|---|---|
wrapModelCall | 包裹每次模型调用 |
wrapToolCall | 包裹每次工具调用 |
示例:自定义重试中间件
import { createMiddleware } from "langchain";
const createRetryMiddleware = (maxRetries: number = 3) => {
return createMiddleware({
name: "RetryMiddleware",
wrapModelCall: async (request, handler) => {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await handler(request);
} catch (e) {
if (attempt === maxRetries - 1) throw e;
console.log(`第 ${attempt + 1} 次重试,错误: ${e}`);
}
}
throw new Error("Unreachable");
},
});
};
3.2 基础开发步骤
- 使用
createMiddleware函数创建中间件,指定name作为唯一标识。 - 根据需求选择 Node-style 或 Wrap-style 钩子,实现对应逻辑。
- 如需扩展状态或上下文,定义
stateSchema或contextSchema。 - 将中间件加入
createAgent的middleware数组中。
3.3 状态与上下文管理
3.3.1 自定义状态 Schema
中间件可以扩展 Agent 状态,在多个钩子间共享数据。使用 stateSchema 定义字段,以下划线 _ 开头的字段为私有字段,不会在最终结果中返回。
import { createMiddleware } from "langchain";
import * as z from "zod";
const callCounterMiddleware = createMiddleware({
name: "CallCounterMiddleware",
stateSchema: z.object({
modelCallCount: z.number().default(0),
_internalFlag: z.boolean().default(false), // 私有字段,结果不返回
}),
afterModel: (state) => {
return { modelCallCount: state.modelCallCount + 1 };
},
});
3.3.2 自定义上下文 Context
上下文是单次调用的只读元数据,不会持久化,适合传递用户ID、租户信息、配置项等。通过 contextSchema 定义,在钩子中通过 request.runtime.context 访问。
import { createAgent, createMiddleware, HumanMessage } from "langchain";
import * as z from "zod";
const contextSchema = z.object({
userId: z.string(),
tenantId: z.string(),
});
const userContextMiddleware = createMiddleware({
name: "UserContextMiddleware",
contextSchema,
wrapModelCall: (request, handler) => {
const { userId, tenantId } = request.runtime.context;
const contextText = `User ID: ${userId}, Tenant: ${tenantId}`;
const newSystemMessage = request.systemMessage.concat(contextText);
return handler({
...request,
systemMessage: newSystemMessage,
});
},
});
3.4 多中间件执行顺序
当配置多个中间件时,遵循洋葱模型:
before*钩子:按数组顺序正序执行wrap*钩子:数组第一个中间件在最外层,嵌套包裹后续中间件after*钩子:按数组顺序逆序执行
执行流程示意(middleware1 → middleware2 → middleware3):
beforeAgent 1 → beforeAgent 2 → beforeAgent 3
↓
beforeModel 1 → beforeModel 2 → beforeModel 3
↓
wrapModel 1 ── wrapModel 2 ── wrapModel 3 ── 模型调用
↓
afterModel 3 → afterModel 2 → afterModel 1
↓
afterAgent 3 → afterAgent 2 → afterAgent 1
3.5 提前终止与跳转
在 Node-style 钩子中可以通过返回 jumpTo 提前跳转执行节点:
'end':直接跳转到 Agent 结束'tools':跳转到工具执行节点'model':跳转到模型调用节点
示例:内容拦截中间件
import { createAgent, createMiddleware, AIMessage } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
middleware: [
createMiddleware({
name: "BlockedContentMiddleware",
beforeModel: {
canJumpTo: ["end"],
hook: (state) => {
if (state.messages.at(-1)?.content.includes("BLOCKED")) {
return {
messages: [new AIMessage("I cannot respond to that request.")],
jumpTo: "end" as const,
};
}
return;
},
},
}),
],
});
3.6 常用自定义场景示例
动态修改系统提示
import { createMiddleware, SystemMessage, createAgent } from "langchain";
const addContextMiddleware = createMiddleware({
name: "AddContextMiddleware",
wrapModelCall: async (request, handler) => {
return handler({
...request,
systemMessage: request.systemMessage.concat(`Additional context.`),
});
},
});
动态模型选择
import { createMiddleware, initChatModel } from "langchain";
const models = {
complex: await initChatModel("claude-sonnet-4-6"),
simple: await initChatModel("claude-haiku-4-5-20251001"),
};
const dynamicModelMiddleware = createMiddleware({
name: "DynamicModelMiddleware",
wrapModelCall: (request, handler) => {
const modifiedRequest = { ...request };
modifiedRequest.model = request.messages.length > 10 ? models.complex : models.simple;
return handler(modifiedRequest);
},
});
工具调用监控
import { createMiddleware } from "langchain";
const toolMonitoringMiddleware = createMiddleware({
name: "ToolMonitoringMiddleware",
wrapToolCall: (request, handler) => {
console.log(`Executing tool: ${request.toolCall.name}`);
console.log(`Arguments: ${JSON.stringify(request.toolCall.args)}`);
try {
const result = handler(request);
console.log("Tool completed successfully");
return result;
} catch (e) {
console.log(`Tool failed: ${e}`);
throw e;
}
},
});
3.7 开发最佳实践
- 单一职责:每个中间件只做一件事,便于复用和测试。
- 错误容错:中间件异常不应导致 Agent 崩溃,做好异常捕获。
- 选型合适的 Hook:顺序逻辑用 Node-style,控制流用 Wrap-style。
- 文档化状态:清晰说明自定义状态字段的含义。
- 独立单元测试:先单独测试中间件逻辑,再集成到 Agent。
- 合理排序:核心管控类中间件放在数组前面。
- 优先使用预置:能用预置中间件满足的场景,不重复造轮子。
四、在 Deep Agents 中应用中间件
Deep Agents 是基于 LangChain + LangGraph 构建的高级 Agent 框架,专注于复杂多步骤任务。它内置了一套核心中间件,同时完全兼容 LangChain 所有预置和自定义中间件。
4.1 Deep Agents 内置核心中间件
以下中间件是 Deep Agents 默认集成的基础能力,属于框架的核心骨架,不可移除但支持配置。
4.1.1 文件系统中间件(createFilesystemMiddleware)
功能:为 Agent 提供虚拟文件系统能力,是上下文管理、长时记忆、代码执行的基础载体。
内置工具:ls、read_file、write_file、edit_file、glob、grep 等。
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
backend | Backend 实例 | 否 | StateBackend | 存储后端: • StateBackend:状态存储,短期有效,仅当前线程内可见 • StoreBackend:持久化存储,跨线程共享,需配合 store 实例 • CompositeBackend:混合后端,按路径前缀路由到不同后端 |
systemPrompt | string | 否 | 内置提示 | 自定义文件系统相关的系统提示。 |
customToolDescriptions | Record<string, string> | 否 | - | 自定义文件系统工具的描述,引导模型正确使用。 |
代码示例(混合存储后端) :
import { createAgent } from "langchain";
import { createFilesystemMiddleware, CompositeBackend, StateBackend, StoreBackend } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph-checkpoint";
const store = new InMemoryStore();
const agent = createAgent({
model: "claude-sonnet-4-6",
store,
middleware: [
createFilesystemMiddleware({
backend: new CompositeBackend(
new StateBackend(),
{ "/memories/": new StoreBackend() } // /memories/ 路径持久化
),
}),
],
});
注:
createDeepAgent默认已包含文件系统中间件,无需手动引入,仅需自定义配置时传入即可。
4.1.2 子代理中间件(createSubAgentMiddleware)
功能:赋予主代理生成子代理的能力,通过 task 工具委派子任务,实现上下文隔离与并行处理。
特性:
- 内置
general-purpose通用子代理,继承主代理的所有工具 - 支持自定义子代理,可单独配置模型、工具、中间件
- 子代理在独立上下文窗口中运行,仅返回最终结果
核心配置参数:
| 参数名 | 类型 | 必填 | 默认值 | 详细说明 |
|---|---|---|---|---|
defaultModel | string | 是 | - | 子代理默认使用的模型,子代理未单独指定 model 时生效。 |
defaultTools | Tool[] | 否 | [] | 所有子代理默认继承的工具列表。 |
subagents | SubAgent[] | 否 | [] | 自定义子代理数组,每个子代理包含: • name:子代理名称 • description:功能描述 • systemPrompt:专属系统提示 • tools:可用工具 • model:可选,单独指定模型 • middleware:可选,专属中间件 |
代码示例:
import { createAgent } from "langchain";
import { createSubAgentMiddleware } from "deepagents";
const agent = createAgent({
model: "claude-sonnet-4-6",
middleware: [
createSubAgentMiddleware({
defaultModel: "claude-sonnet-4-6",
subagents: [
{
name: "weather",
description: "查询城市天气的子代理",
systemPrompt: "使用 get_weather 工具获取天气",
tools: [getWeather],
},
],
}),
],
});
4.2 挂载外部中间件的方法
createDeepAgent 支持 middleware 参数,可直接传入 LangChain 预置中间件或自定义中间件,用法与普通 Agent 完全一致。
完整示例:
import { createDeepAgent } from "deepagents";
import {
toolRetryMiddleware,
piiMiddleware,
todoListMiddleware,
summarizationMiddleware
} from "langchain";
const agent = await createDeepAgent({
model: "openai:gpt-5.5",
tools: [searchTool, databaseTool],
middleware: [
// 任务规划
todoListMiddleware(),
// 对话摘要
summarizationMiddleware({ model: "gpt-5.4-mini", trigger: { fraction: 0.8 } }),
// 工具重试
toolRetryMiddleware({ maxRetries: 3 }),
// PII 脱敏
piiMiddleware("email", { strategy: "redact" }),
],
systemPrompt: "你是一个高效的助手,按步骤完成任务",
});
4.3 使用注意事项
- 核心中间件不可移除:Filesystem、Subagent 是 Deep Agents 的基础骨架,无法通过配置移除。若需隐藏对应工具,可通过
harness profile的excluded_tools配置。 - 执行顺序:用户传入的中间件会与内置中间件合并,遵循标准洋葱模型执行。
- 子代理 继承:子代理默认不继承主代理的所有中间件,如需子代理也具备对应能力,需在子代理配置中单独声明。
- 避免重复配置:Deep Agents 已内置上下文管理、提示词缓存等能力,挂载同类中间件时注意避免重复。
五、整体最佳实践
- 按需组合:根据业务场景选择合适的中间件组合,避免过度配置增加不必要的开销。
- 顺序优先:安全、限流类中间件放在最前面,确保在执行核心逻辑前完成校验。
- 测试验证:上线前充分测试中间件的边界行为,如限流触发、重试耗尽、异常兜底等。
- 监控 埋点:结合日志中间件或自定义中间件,添加关键指标埋点,便于排查问题。
- 版本兼容:关注 LangChain 版本变更,及时替换已废弃的参数和 API。