预置中间件
针对常见智能体应用场景的预置中间件
LangChain 为常见用例提供了预置中间件。每个中间件均达到生产可用级别,并可根据您的具体需求进行配置。
NOTE
正在使用 Deep Agents(create_deep_agent / createDeepAgent)?中间件需改由自定义 API 添加。
与提供商无关的中间件
以下中间件适用于任何 LLM 提供商:
| 中间件 | 描述 |
|---|---|
| 工具重试 | 使用指数退避自动重试失败的工具调用。 |
| 模型重试 | 使用指数退避自动重试失败的模型调用。 |
| 模型降级 | 当主模型失败时自动降级到备用模型。 |
| 摘要 | 当接近 Token 限制时自动总结对话历史。 |
| 人在回路 | 暂停执行以等待人工审批工具调用。 |
| 模型调用限制 | 限制模型调用次数以防止成本过高。 |
| 工具调用限制 | 通过限制调用次数控制工具执行。 |
| PII 检测 | 检测并处理个人身份信息(PII)。 |
| 待办列表 | 为智能体配备任务规划与跟踪能力。 |
| LLM 工具选择器 | 在调用主模型前使用 LLM 选择相关工具。 |
| 提供商工具检索 | 将工具置于提供商服务端工具搜索之后,按需呈现。 |
| 文件系统 | 为智能体提供用于存储上下文和长期记忆的文件系统。 |
| 子智能体中间件 | 添加生成子智能体的能力。 |
| 上下文编辑 | 通过修剪或清除工具使用记录来管理对话上下文。 |
| LLM 工具模拟器 | 出于测试目的使用 LLM 模拟工具执行。 |
工具错误
工具重试
使用可配置的指数退避自动重试失败的工具调用。工具重试在以下场景中非常有用:
- 处理外部 API 调用中的瞬态故障。
- 提高依赖网络的工具的可靠性。
- 构建能够平稳处理临时错误的弹性智能体。
API 参考: toolRetryMiddleware
import { createAgent, toolRetryMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [searchTool, databaseTool],
middleware: [
toolRetryMiddleware({
maxRetries: 3,
backoffFactor: 2.0,
initialDelayMs: 1000,
}),
],
});配置选项
maxRetries
number(默认值:2)初始调用后的最大重试尝试次数(在默认设置下总共尝试 3 次)。必须 >= 0。
tools
(ClientTool | ServerTool | string)[]可选数组,指定要应用重试逻辑的工具或工具名称。可以是
BaseTool实例列表或工具名称字符串。如果为undefined,则应用于所有工具。retryOn
((error: Error) =\> boolean) | (new (...args: any[]) =\> Error)[](默认值:(error) => getRetryable(error) ?? true)可以是触发重试的错误构造函数数组,也可以是一个接收错误并在应当重试时返回
true的函数。在langchain>=1.5.9中,默认行为不再重试被标记为不可重试的错误。其他所有错误均会重试。onFailure
'error' | 'continue' | ((error: Error) =\> string)(默认值:continue)所有重试耗尽后的行为。选项:
'continue'(默认)- 返回包含错误详细信息的ToolMessage,允许 LLM 处理故障并尝试恢复'error'- 重新抛出异常,停止智能体执行- 自定义函数 - 接收异常并返回字符串作为
ToolMessage内容的函数,允许自定义错误格式已弃用值:
'raise'(请改用'error')和'return_message'(请改用'continue')。这些已弃用的值仍然有效,但会显示警告。backoffFactor
number(默认值:2.0)指数退避乘数。每次重试等待
initialDelayMs * (backoffFactor ** retryNumber)毫秒。设置为0.0表示固定延迟。必须 >= 0。initialDelayMs
number(默认值:1000)第一次重试前的初始延迟(毫秒)。必须 >= 0。
maxDelayMs
number(默认值:60000)重试之间的最大延迟(毫秒,限制指数退避增长的上限)。必须 >= 0。
jitter
boolean(默认值:true)是否向延迟中添加随机抖动(
±25%)以避免惊群效应
完整示例
该中间件使用指数退避自动重试失败的工具调用。
核心配置:
maxRetries- 重试尝试次数(默认值:2)backoffFactor- 指数退避乘数(默认值:2.0)initialDelayMs- 起始延迟毫秒数(默认值:1000ms)maxDelayMs- 延迟增长上限(默认值:60000ms)jitter- 添加随机变化(默认值:true)失败处理:
onFailure: "continue"(默认)- 返回错误消息onFailure: "error"- 重新抛出异常- 自定义函数 - 返回错误消息的函数
typescriptimport { createAgent, toolRetryMiddleware } from "langchain"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; // 使用默认设置的基础用法(2 次重试,指数退避) const agent = createAgent({ model: "gpt-5.5", tools: [searchTool, databaseTool], middleware: [toolRetryMiddleware()], }); // 仅重试特定异常 const retry = toolRetryMiddleware({ maxRetries: 4, retryOn: [TimeoutError, NetworkError], backoffFactor: 1.5, }); // 自定义异常过滤 function shouldRetry(error: Error): boolean { // 仅对 5xx 错误进行重试 if (error.name === "HTTPError" && "statusCode" in error) { const statusCode = (error as any).statusCode; return 500 <= statusCode && statusCode < 600; } return false; } const retryWithFilter = toolRetryMiddleware({ maxRetries: 3, retryOn: shouldRetry, }); // 应用于特定工具并自定义错误处理 const formatError = (error: Error) => "Database temporarily unavailable. Please try again later."; const retrySpecificTools = toolRetryMiddleware({ maxRetries: 4, tools: ["search_database"], onFailure: formatError, }); // 使用 BaseTool 实例应用于特定工具 const searchDatabase = tool( async ({ query }) => { // 搜索实现 return results; }, { name: "search_database", description: "Search the database", schema: z.object({ query: z.string() }), } ); const retryWithToolInstance = toolRetryMiddleware({ maxRetries: 4, tools: [searchDatabase], // 传入 BaseTool 实例 }); // 固定退避(无指数增长) const constantBackoff = toolRetryMiddleware({ maxRetries: 5, backoffFactor: 0.0, // 无指数增长 initialDelayMs: 2000, // 始终等待 2 秒 }); // 失败时抛出异常 const strictRetry = toolRetryMiddleware({ maxRetries: 2, onFailure: "error", // 重新抛出异常而不是返回消息 });
将错误标记为可重试
NOTE
需要 @langchain/core>=1.2.8 和 langchain>=1.5.9。
在抛出错误之前对其进行标记,重试中间件将会遵循该裁定。这可以避免在以完全相同方式重复发生的故障上浪费重试次数,例如无效输入或凭据被拒绝。
使用来自 @langchain/core/errors 的 stampRetryable:
import { stampRetryable } from "@langchain/core/errors";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const lookupRecord = tool(
async ({ id }) => {
const response = await fetch(`https://api.example.com/records/${id}`);
if (response.status === 422) {
// 使用相同的标识符重试依然会以相同方式失败
throw stampRetryable(new Error("Malformed record identifier"), false);
}
if (response.status === 503) {
throw stampRetryable(new Error("Record service unavailable"), true);
}
return response.json();
},
{
name: "lookup_record",
description: "Look up a record by identifier",
schema: z.object({ id: z.string() }),
}
);对于不可能在下一次尝试中成功的故障传入 false,对于瞬态故障传入 true。您未标记的错误仍会被重试,因此现有工具将保持其当前行为。
标记错误不会改变其类型或形状,因此针对该错误的 instanceof 检查仍可正常工作。要读取标记结果,请调用 getRetryable(error),当错误从未被标记时,它将返回 true、false 或 undefined。
聊天模型集成已经标记了它们能识别的故障,因此您无需自行标记这些故障。以下故障将在第一次尝试时直接失败,而不会消耗重试次数:
- 身份验证失败(Authentication failures):API 密钥缺失、无效或已过期。
- 权限被拒绝(Permission denied):凭据有效但无权访问所请求的资源。
- 未知模型(Unknown model):模型标识符未被提供商识别。
- 上下文窗口溢出(Context window overflow):输入超出模型可接受的长度。
- 无效的工具结果(Invalid tool results):格式错误的工具结果块。
- 有效负载过大(Payload too large):请求体因大小问题被提供商拒绝。
- 配额耗尽(Exhausted quota):计费或用量达到上限,与速率限制(rate limit)不同。
- 取消调用(Cancelled calls):通过中止信号(abort signal)停止的请求。
速率限制(Rate limits)、超时(timeouts)和服务端错误(server errors)保持可重试。任何提供商无法识别的内容均保持未标记状态,并像以前一样进行重试。
模型重试
使用可配置的指数退避自动重试失败的模型调用。模型重试在以下场景中非常有用:
- 处理模型 API 调用中的瞬态故障。
- 提高依赖网络的模型请求的可靠性。
- 构建能够平稳处理临时模型错误的弹性智能体。
API 参考: modelRetryMiddleware
import { createAgent, modelRetryMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [searchTool, databaseTool],
middleware: [
modelRetryMiddleware({
maxRetries: 3,
backoffFactor: 2.0,
initialDelayMs: 1000,
}),
],
});配置选项
maxRetries
number(默认值:2)初始调用后的最大重试尝试次数(在默认设置下总共尝试 3 次)。必须 >= 0。
retryOn
((error: Error) =\> boolean) | (new (...args: any[]) =\> Error)[](默认值:(error) => getRetryable(error) ?? true)可以是触发重试的错误构造函数数组,也可以是一个接收错误并在应当重试时返回
true的函数。在langchain>=1.5.9中,默认行为不再重试被标记为不可重试的错误。其他所有错误均会重试。onFailure
'error' | 'continue' | ((error: Error) =\> string)(默认值:continue)所有重试耗尽后的行为。选项:
'continue'(默认)- 返回包含错误详细信息的AIMessage,允许智能体平稳地处理故障'error'- 重新抛出异常,停止智能体执行- 自定义函数 - 接收异常并返回字符串作为
AIMessage内容的函数,允许自定义错误格式backoffFactor
number(默认值:2.0)指数退避乘数。每次重试等待
initialDelayMs * (backoffFactor ** retryNumber)毫秒。设置为0.0表示固定延迟。必须 >= 0。initialDelayMs
number(默认值:1000)第一次重试前的初始延迟(毫秒)。必须 >= 0。
maxDelayMs
number(默认值:60000)重试之间的最大延迟(毫秒,限制指数退避增长的上限)。必须 >= 0。
jitter
boolean(默认值:true)是否向延迟中添加随机抖动(
±25%)以避免惊群效应
完整示例
该中间件使用指数退避自动重试失败的模型调用。
typescriptimport { createAgent, modelRetryMiddleware } from "langchain"; // 使用默认设置的基础用法(2 次重试,指数退避) const agent = createAgent({ model: "gpt-5.5", tools: [searchTool], middleware: [modelRetryMiddleware()], }); class TimeoutError extends Error { // ... } class NetworkError extends Error { // ... } // 仅重试特定异常 const retry = modelRetryMiddleware({ maxRetries: 4, retryOn: [TimeoutError, NetworkError], backoffFactor: 1.5, }); // 自定义异常过滤 function shouldRetry(error: Error): boolean { // 仅对速率限制错误进行重试 if (error.name === "RateLimitError") { return true; } // 或者检查特定的 HTTP 状态码 if (error.name === "HTTPError" && "statusCode" in error) { const statusCode = (error as any).statusCode; return statusCode === 429 || statusCode === 503; } return false; } const retryWithFilter = modelRetryMiddleware({ maxRetries: 3, retryOn: shouldRetry, }); // 返回错误消息而不是抛出异常 const retryContinue = modelRetryMiddleware({ maxRetries: 4, onFailure: "continue", // 返回包含错误的 AIMessage 而不是抛出异常 }); // 自定义错误消息格式化 const formatError = (error: Error) => `Model call failed: ${error.message}. Please try again later.`; const retryWithFormatter = modelRetryMiddleware({ maxRetries: 4, onFailure: formatError, }); // 固定退避(无指数增长) const constantBackoff = modelRetryMiddleware({ maxRetries: 5, backoffFactor: 0.0, // 无指数增长 initialDelayMs: 2000, // 始终等待 2 秒 }); // 失败时抛出异常 const strictRetry = modelRetryMiddleware({ maxRetries: 2, onFailure: "error", // 重新抛出异常而不是返回消息 });
模型降级
当主模型失败时,自动降级到备用模型。模型降级在以下场景中非常有用:
- 构建能够应对模型服务中断的弹性智能体。
- 通过降级到更廉价的模型进行成本优化。
- 跨 OpenAI、Anthropic 等实现提供商冗余。
import { createAgent, modelFallbackMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
modelFallbackMiddleware(
"gpt-5.4-mini",
"claude-sonnet-4-6"
),
],
});配置选项
该中间件接受可变数量的字符串参数,按顺序表示备用模型:
...models
string[]必填当主模型失败时,按顺序尝试的一个或多个备用模型字符串
typescriptmodelFallbackMiddleware( "first-fallback-model", "second-fallback-model", // ... 更多模型 )
摘要
当接近 Token 限制时自动总结对话历史,在压缩更早的上下文的同时保留最近的消息。摘要在以下场景中非常有用:
- 超出上下文窗口的长运行对话。
- 具有大量历史记录的多轮对话。
- 需要保留完整对话上下文的应用程序。
NOTE
摘要是一种面向文本的上下文压缩方式。它不会调整大小、降采样或以其他方式压缩图像/音频/视频有效负载。通过 keep 保留的最近消息仍包含其原始的多模态块,而经过摘要的较早多模态消息则仅由生成的文本摘要表示。对于图像密集型应用程序,请将媒体存储在文件系统或对象存储中,并通过消息历史传递 URL 或文件引用。
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 },
keep: { messages: 20 },
}),
],
});配置选项
TIP
如果使用
langchain@1.1.0,trigger和keep的fraction条件(如下所示)依赖于聊天模型的 profile 数据。如果数据不可用,请使用其他条件或手动指定:typescriptconst customProfile: ModelProfile = { maxInputTokens: 100_000, // ... } model = await initChatModel("...", { profile: customProfile, });model
string | BaseChatModel必填用于生成摘要的模型。可以是模型标识符字符串(例如
'openai:gpt-5.4-mini')或BaseChatModel实例。trigger
object | object[]触发摘要的条件。可以是:
单个条件(AND 逻辑): 单个对象,其中所有属性必须同时满足。
typescript// 当 tokens >= 4000 且 messages >= 10 时触发 trigger: { tokens: 4000, messages: 10 }多个条件(OR 逻辑): 条件对象数组。当满足任何一个对象的条件时即触发摘要。
typescript// 当 tokens >= 3000 或 messages >= 6 时触发 trigger: [{ tokens: 3000 }, { messages: 6 }]每个条件可以包含:
fraction(number):模型上下文大小的比例(0-1)tokens(number):绝对 Token 数量messages(number):消息数量每个条件必须至少指定一个属性。如果未提供,摘要将不会自动触发。
keep
object(默认值:{messages: 20})摘要后要保留的上下文量。必须且只能指定以下之一:
fraction(number):要保留的模型上下文大小比例(0-1)tokens(number):要保留的绝对 Token 数量messages(number):要保留的最近消息数量tokenCounter
function自定义 Token 计数函数。默认为基于字符的计数。
summaryPrompt
string用于摘要的自定义提示词模板。如果未指定,则使用内置模板。该模板应包含
{messages}占位符,对话历史将插入其中。trimTokensToSummarize
number(默认值:4000)生成摘要时包含的最大 Token 数量。在摘要之前,消息将被修剪以适应此限制。
summaryPrefix
string要添加到摘要消息的前缀。如果未提供,将使用默认前缀。
maxTokensBeforeSummary
number已弃用已弃用: 请改用
trigger: { tokens: value }。触发摘要的 Token 阈值。messagesToKeep
number已弃用已弃用: 请改用
keep: { messages: value }。要保留的最近消息数量。
完整示例
摘要中间件监控消息 Token 数量,并在达到阈值时自动对较早的消息进行摘要。
触发条件(Trigger conditions) 控制何时运行摘要:
- 单个阈值在该阈值满足时触发
- 包含多个阈值的触发子句仅在所有阈值均满足时触发(AND 逻辑)
- 触发条件列表在满足任何一项时触发(OR 逻辑)
- 每个阈值可以使用
fraction(模型上下文大小的比例)、tokens(绝对数量)或messages(消息数量)保留条件(Keep condition) 控制要保留多少上下文(必须且只能指定其中一个):
fraction- 要保留的模型上下文大小比例tokens- 要保留的绝对 Token 数量messages- 要保留的最近消息数量typescriptimport { createAgent, summarizationMiddleware } from "langchain"; // 单个条件(AND 逻辑):当 tokens >= 4000 且 messages >= 10 时触发 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 逻辑):当 tokens >= 3000 或 messages >= 6 时触发 const agent2 = createAgent({ model: "gpt-5.5", tools: [weatherTool, calculatorTool], middleware: [ summarizationMiddleware({ model: "gpt-5.4-mini", trigger: [ { tokens: 3000 }, { messages: 6 }, ], keep: { messages: 20 }, }), ], }); // 使用比例限制 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 }, }), ], });
人在回路
在工具调用执行前暂停智能体执行,以便人工审批、编辑或拒绝工具调用。人在回路在以下场景中非常有用:
- 需要人工审批的高风险操作(例如数据库写入、金融交易)。
- 强制要求人工监督的合规工作流。
- 人工反馈用于指导智能体的长时间运行对话。
该中间件默认每个模型轮次(model turn)暂停一次。设置 interruptMode: "per_call" 可针对每个工具调用暂停一次,每个中断通过其 ID 进行应答。参见设置中断模式。
WARNING
人在回路中间件需要一个检查点保存器(checkpointer)来跨中断维护状态。
import { createAgent, humanInTheLoopMiddleware } from "langchain";
function readEmailTool(emailId: string): string {
/** 根据邮件 ID 读取邮件的模拟函数。 */
return `Email content for ID: ${emailId}`;
}
function sendEmailTool(recipient: string, subject: string, body: string): string {
/** 发送邮件的模拟函数。 */
return `Email sent to ${recipient} with subject '${subject}'`;
}
const agent = createAgent({
model: "gpt-5.5",
tools: [readEmailTool, sendEmailTool],
middleware: [
humanInTheLoopMiddleware({
interruptOn: {
sendEmailTool: {
allowedDecisions: ["approve", "edit", "reject"],
},
readEmailTool: false,
}
})
]
});TIP
有关完整示例、配置选项和集成模式,请参见人在回路文档。
观看演示人在回路中间件行为的视频指南。
模型调用次数限制 (Model call limit)
限制模型调用次数,以防止死循环或产生过高成本。模型调用次数限制适用于以下场景:
- 防止失控的智能体发起过多 API 调用。
- 在生产环境部署中实施成本控制。
- 在特定的调用预算内测试智能体行为。
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",
}),
],
});观看此视频指南,了解模型调用次数限制中间件的行为演示。
配置选项 (Configuration options)
threadLimit
number单个线程内所有运行中允许的最大模型调用次数。默认为无限制。
runLimit
number单次调用允许的最大模型调用次数。默认为无限制。
exitBehavior
string(默认值:end)达到限制时的行为。可选值:
'end'(正常终止)或'error'(抛出异常)
工具调用次数限制 (Tool call limit)
通过限制工具调用次数来控制智能体执行,既支持全局限制所有工具,也支持针对特定工具进行限制。工具调用限制适用于以下场景:
- 防止对昂贵的外部 API 发起过多调用。
- 限制网络搜索或数据库查询次数。
- 对特定工具的使用实施速率限制。
- 防止智能体陷入失控循环。
import { createAgent, toolCallLimitMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [searchTool, databaseTool],
middleware: [
toolCallLimitMiddleware({ threadLimit: 20, runLimit: 10 }),
toolCallLimitMiddleware({
toolName: "search",
threadLimit: 5,
runLimit: 3,
}),
],
});观看此视频指南,了解工具调用限制中间件的行为演示。
配置选项 (Configuration options)
toolName
string要限制的特定工具名称。如果未提供,限制将全局应用于所有工具。
threadLimit
number单个线程(会话)内所有运行中允许的最大工具调用次数。在具有相同线程 ID 的多次调用之间保持持久化。需要检查点保存器(checkpointer)来维护状态。
undefined表示无线程限制。runLimit
number单次调用(单次用户消息 → 响应周期)允许的最大工具调用次数。每条新用户消息都会重置。
undefined表示无运行限制。注意: 必须指定
threadLimit或runLimit中的至少一个。exitBehavior
string(默认值:continue)达到限制时的行为:
'continue'(默认)- 使用错误消息阻止超额的工具调用,让其他工具和模型继续运行。模型根据错误消息决定何时结束。'error'- 抛出ToolCallLimitExceededError异常,立即停止执行'end'- 立即停止执行,并为超额的工具调用生成 ToolMessage 和 AI 消息。仅在限制单个工具时有效;如果其他工具还有待处理的调用,则会抛出错误。
完整示例 (Full example)
指定限制方式:
- 线程限制 (Thread limit) - 会话内所有运行的最大调用次数(需要 checkpointer)
- 运行限制 (Run limit) - 单次调用的最大调用次数(每轮重置)
退出行为:
'continue'(默认)- 使用错误消息阻止超额调用,智能体继续运行'error'- 立即引发异常'end'- 附带 ToolMessage + AI 消息停止(仅限单工具场景)typescriptimport { createAgent, toolCallLimitMiddleware } from "langchain"; const globalLimiter = toolCallLimitMiddleware({ threadLimit: 20, runLimit: 10 }); const searchLimiter = toolCallLimitMiddleware({ toolName: "search", threadLimit: 5, runLimit: 3 }); const databaseLimiter = toolCallLimitMiddleware({ toolName: "query_database", threadLimit: 10 }); const strictLimiter = toolCallLimitMiddleware({ toolName: "scrape_webpage", runLimit: 2, exitBehavior: "error" }); const agent = createAgent({ model: "gpt-5.5", tools: [searchTool, databaseTool, scraperTool], middleware: [globalLimiter, searchLimiter, databaseLimiter, strictLimiter], });
个人身份信息检测 (PII detection)
使用可配置的策略在会话中检测并处理个人身份信息(PII)。PII 检测适用于以下场景:
- 具有合规性要求的医疗保健和金融应用程序。
- 需要清理日志的客户服务智能体。
- 处理敏感用户数据的任何应用程序。
import { createAgent, piiMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
piiMiddleware("email", { strategy: "redact", applyToInput: true }),
piiMiddleware("credit_card", { strategy: "mask", applyToInput: true }),
],
});自定义 PII 类型 (Custom PII types)
你可以通过提供 detector 参数来创建自定义 PII 类型。这允许你在内置类型之外检测特定于用例的模式。
创建自定义检测器的三种方式:
正则表达式模式字符串 - 简单的模式匹配
RegExp 对象 - 对正则表达式标志进行更精细的控制
自定义函数 - 包含校验逻辑的复杂检测
import { createAgent, piiMiddleware, type PIIMatch } from "langchain";
// 方式 1:正则表达式模式字符串
const agent1 = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
piiMiddleware("api_key", {
detector: "sk-[a-zA-Z0-9]{32}",
strategy: "block",
}),
],
});
// 方式 2:RegExp 对象
const agent2 = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
piiMiddleware("phone_number", {
detector: /\+?\d{1,3}[\s.-]?\d{3,4}[\s.-]?\d{4}/,
strategy: "mask",
}),
],
});
// 方式 3:自定义检测器函数
function detectSSN(content: string): PIIMatch[] {
const matches: PIIMatch[] = [];
const pattern = /\d{3}-\d{2}-\d{4}/g;
let match: RegExpExecArray | null;
while ((match = pattern.exec(content)) !== null) {
const ssn = match[0];
// 校验:前 3 位数字不应为 000、666 或 900-999
const firstThree = parseInt(ssn.substring(0, 3), 10);
if (firstThree !== 0 && firstThree !== 666 && !(firstThree >= 900 && firstThree <= 999)) {
matches.push({
text: ssn,
start: match.index ?? 0,
end: (match.index ?? 0) + ssn.length,
});
}
}
return matches;
}
const agent3 = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
piiMiddleware("ssn", {
detector: detectSSN,
strategy: "hash",
}),
],
});自定义检测器函数签名:
检测器函数必须接受一个字符串(content)并返回匹配项:
返回 PIIMatch 对象数组:
interface PIIMatch {
text: string; // 匹配到的文本
start: number; // 在内容中的起始索引
end: number; // 在内容中的结束索引
}
function detector(content: string): PIIMatch[] {
return [
{ text: "matched_text", start: 0, end: 12 },
// ... 更多匹配项
];
}TIP
对于自定义检测器:
- 对于简单模式使用正则表达式字符串
- 当需要标志时(例如忽略大小写匹配)使用 RegExp 对象
- 当需要超出模式匹配之外的校验逻辑时使用自定义函数
- 自定义函数使你能够完全控制检测逻辑,并能实现复杂的校验规则
配置选项 (Configuration options)
piiType
string必填要检测的 PII 类型。可以是内置类型(
credit_card、ip、mac_address、url)或自定义类型名称。strategy
string(默认值:redact)处理检测到的 PII 的方式。可选值:
'block'- 检测到时抛出错误'redact'- 替换为[REDACTED_TYPE]'mask'- 部分掩码(例如****-****-****-1234)'hash'- 替换为确定性哈希(例如<email_hash:a1b2c3d4>)detector
RegExp | string | function自定义检测器。可以是:
RegExp- 用于匹配的正则表达式模式string- 正则表达式模式字符串(例如"sk-[a-zA-Z0-9]{32}")function- 自定义检测器函数(content: string) => PIIMatch[]如果未提供,则使用该 PII 类型的内置检测器。
applyToInput
boolean(默认值:true)在模型调用前检查用户消息
applyToOutput
boolean(默认值:false)在模型调用后检查 AI 消息
applyToToolResults
boolean(默认值:false)在执行后检查工具结果消息
任务清单 (To-do list)
为智能体配备针对复杂多步任务的任务规划与跟踪能力。任务清单适用于以下场景:
- 需要协调多个工具的复杂多步任务。
- 进度可见性至关重要的长时间运行操作。
NOTE
该中间件会自动为智能体提供 write_todos 工具和系统提示词,以引导有效的任务规划。
import { createAgent, todoListMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [readFile, writeFile, runTests],
middleware: [todoListMiddleware()],
});观看此视频指南,了解任务清单中间件的行为演示。
配置选项 (Configuration options)
没有可用的配置选项(使用默认值)。
LLM 工具选择器 (LLM tool selector)
在调用主模型之前,使用 LLM 智能筛选出相关工具。LLM 工具选择器适用于以下场景:
- 拥有众多工具(10 个以上),但每次查询大多数工具都不相关的智能体。
- 通过过滤不相关的工具来减少 Token 消耗。
- 提高模型的专注度和准确性。
该中间件使用结构化输出(structured output)询问 LLM 哪些工具与当前查询最相关。结构化输出的 Schema 定义了可用工具的名称和描述。模型提供商通常会在后台将此结构化输出信息添加到系统提示词中。
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"],
}),
],
});配置选项 (Configuration options)
model
string | BaseChatModel用于工具选择的模型。可以是模型标识符字符串(例如
'openai:gpt-5.4-mini')或BaseChatModel实例。默认为智能体的主模型。systemPrompt
string提供给选择模型的指令。如果未指定,则使用内置提示词。
maxTools
number最多选择的工具数量。如果模型选择了更多,则仅使用前 maxTools 个。如果未指定则无限制。
alwaysInclude
string[]无论选择结果如何都始终包含的工具名称。这些工具不计入 maxTools 限制。
提供商工具搜索 (Provider tool search)
将选定的工具延迟托管到模型提供商的服务端工具搜索(server-side tool search)之后,让模型按需发现它们,而不是预先接收每个工具的 Schema。提供商工具搜索适用于:
- 在使用众多工具时减少上下文膨胀。
- 通过仅呈现相关工具来提高工具选择的准确性。
NOTE
需要支持服务端工具搜索的模型:Anthropic(Claude Sonnet 4+/Opus 4+/Haiku 4.5+)或 OpenAI(gpt-5.5+)。其他提供商会抛出错误。
API 参考: providerToolSearchMiddleware
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 lookupOrderStatus = tool(async () => "OUT_FOR_DELIVERY", {
name: "lookup_order_status",
description: "Look up the current delivery status of a customer order by ID",
schema: z.object({ orderId: z.string() }),
});
const nicheTools = [lookupOrderStatus];
const agent = createAgent({
model: "anthropic:claude-opus-4-8",
tools: [getWeather, ...nicheTools],
middleware: [
providerToolSearchMiddleware({ searchableTools: nicheTools }),
],
});配置选项 (Configuration options)
searchableTools
(string | StructuredToolInterface)[]要延迟放到提供商工具搜索背后的工具,以名称或实例指定。被延迟的工具不会直接提供给模型,直到模型的搜索将其召回。使用
extras.defer_loading: true构建的工具无论是否设置此选项都会被延迟;如果省略searchableTools,则仅延迟那些预先标记的工具。
完整示例 (Full example)
该中间件将
searchableTools中包含的所有工具加入延迟加载和搜索。工具也可以在构建时通过设置extras.defer_loading: true来选择延迟加载:typescriptimport { createAgent, providerToolSearchMiddleware } from "langchain"; import { tool } from "@langchain/core/tools"; import { z } from "zod"; // 在构建时标记了 defer_loading,因此会自动延迟加载 —— // 无需在 searchableTools 中列出。 const sendEmail = tool(async () => "sent", { name: "send_email", description: "Send an email", schema: z.object({ to: z.string() }), extras: { defer_loading: true }, }); const agent = createAgent({ model: "anthropic:claude-opus-4-8", tools: [sendEmail], middleware: [providerToolSearchMiddleware()], });
文件系统中间件 (Filesystem middleware)
上下文工程(Context engineering)是构建高效智能体的主要挑战之一。当使用返回可变长度结果的工具(例如 web_search 和 RAG)时,这尤其困难,因为过长的工具结果会迅速填满你的上下文窗口。
来自 Deep Agents 的 FilesystemMiddleware 提供了四个用于与短期和长期记忆交互的工具:
ls:列出文件系统中的文件read_file:读取整个文件或文件中的特定行数write_file:向文件系统写入新文件edit_file:编辑文件系统中的现有文件
import { createAgent } from "langchain";
import { createFilesystemMiddleware } from "deepagents";
// FilesystemMiddleware 默认包含在 createDeepAgent 中
// 如果构建自定义智能体,你可以对其进行自定义
const agent = createAgent({
model: "claude-sonnet-4-6",
middleware: [
createFilesystemMiddleware({
backend: undefined, // 可选:自定义后端(默认为 StateBackend)
systemPrompt: "Write to the filesystem when...", // 可选:覆盖自定义系统提示词
customToolDescriptions: {
ls: "Use the ls tool when...",
read_file: "Use the read_file tool to...",
}, // 可选:文件系统工具的自定义描述
}),
],
});短期与长期文件系统 (Short-term vs. long-term filesystem)
默认情况下,这些工具写入图状态中的本地“文件系统”。要实现跨线程的持久化存储,可以配置一个 CompositeBackend,将特定路径(如 /memories/)路由到 StoreBackend。
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() }
),
systemPrompt: "Write to the filesystem when...", // 可选:覆盖自定义系统提示词
customToolDescriptions: {
ls: "Use the ls tool when...",
read_file: "Use the read_file tool to...",
}, // 可选:文件系统工具的自定义描述
}),
],
});当你为 /memories/ 配置带有 StoreBackend 的 CompositeBackend 时,任何带有 /memories/ 前缀的文件都会保存到持久化存储中,并在不同线程之间持久存在。不带此前缀的文件则保留在瞬时状态存储中。
子智能体 (Subagent)
将任务移交给子智能体可以隔离上下文,在保持主(主管)智能体上下文窗口整洁的同时,仍能深入执行任务。
来自 Deep Agents 的子智能体中间件允许你通过 task 工具提供子智能体。
import { tool } from "langchain";
import { createAgent } from "langchain";
import { createSubAgentMiddleware } from "deepagents";
import { z } from "zod";
const getWeather = tool(
async ({ city }: { city: string }) => {
return `The weather in ${city} is sunny.`;
},
{
name: "get_weather",
description: "Get the weather in a city.",
schema: z.object({
city: z.string(),
}),
},
);
const agent = createAgent({
model: "claude-sonnet-4-6",
middleware: [
createSubAgentMiddleware({
defaultModel: "claude-sonnet-4-6",
defaultTools: [],
subagents: [
{
name: "weather",
description: "This subagent can get weather in cities.",
systemPrompt: "Use the get_weather tool to get the weather in a city.",
tools: [getWeather],
model: "gpt-5.5",
middleware: [],
},
],
}),
],
});子智能体由名称 (name)、描述 (description)、系统提示词 (system prompt) 和工具 (tools) 定义。你还可以为子智能体提供自定义模型 (model) 或附加中间件 (middleware)。这在你想为子智能体提供额外的状态键以与主智能体共享时特别有用。
对于更复杂的用例,你还可以提供自己预先构建的 LangGraph 图作为子智能体。
import { tool, createAgent } from "langchain";
import { createSubAgentMiddleware, type SubAgent } from "deepagents";
import { z } from "zod";
const getWeather = tool(
async ({ city }: { city: string }) => {
return `The weather in ${city} is sunny.`;
},
{
name: "get_weather",
description: "Get the weather in a city.",
schema: z.object({
city: z.string(),
}),
},
);
const weatherSubagent: SubAgent = {
name: "weather",
description: "This subagent can get weather in cities.",
systemPrompt: "Use the get_weather tool to get the weather in a city.",
tools: [getWeather],
model: "gpt-5.5",
middleware: [],
};
const agent = createAgent({
model: "claude-sonnet-4-6",
middleware: [
createSubAgentMiddleware({
defaultModel: "claude-sonnet-4-6",
defaultTools: [],
subagents: [weatherSubagent],
}),
],
});除了任何用户定义的子智能体之外,主智能体随时都可以访问一个 general-purpose(通用)子智能体。该子智能体拥有与主智能体相同的指令以及它可以访问的所有工具。general-purpose 子智能体的首要目的是上下文隔离 —— 主智能体可以将复杂的任务委派给该子智能体,并获得简洁的回答,而不会受到中间工具调用的膨胀干扰。
上下文编辑 (Context editing)
在达到 Token 上限时,通过清理较早的工具调用输出来管理会话上下文,同时保留最近的结果。这有助于在包含大量工具调用的长会话中将上下文窗口保持在可控范围内。上下文编辑适用于以下场景:
- 包含大量工具调用且超出 Token 限制的长会话
- 通过移除不再相关的较早工具输出以降低 Token 成本
- 在上下文中仅保留最近的 N 个工具结果
import { createAgent, contextEditingMiddleware, ClearToolUsesEdit } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [],
middleware: [
contextEditingMiddleware({
edits: [
new ClearToolUsesEdit({
triggerTokens: 100000,
keep: 3,
}),
],
}),
],
});配置选项 (Configuration options)
edits
ContextEdit[](默认值:[new ClearToolUsesEdit()])要应用的
ContextEdit策略数组triggerTokens
number(默认值:100000)触发编辑的 Token 数量。当会话超过此 Token 数量时,将清理较早的工具输出。
clearAtLeast
number(默认值:0)编辑运行时要回收的最小 Token 数量。如果设置为 0,则根据需要尽量清理。
keep
number(默认值:3)必须保留的最近工具结果的数量。这些结果绝不会被清理。
clearToolInputs
boolean(默认值:false)是否清理 AI 消息上原始的工具调用参数。当为
true时,工具调用参数将被替换为空对象。excludeTools
string[](默认值:[])要排除在清理范围之外的工具名称列表。这些工具的输出绝不会被清理。
placeholder
string(默认值:[cleared])为清理后的工具输出插入的占位符文本。这将替换原始的工具消息内容。
完整示例 (Full example)
该中间件在达到 Token 限制时应用上下文编辑策略。最常用的策略是
ClearToolUsesEdit,它在保留最近工具结果的同时清理较早的结果。工作原理:
- 监控会话中的 Token 数量
- 当达到阈值时,清理较早的工具输出
- 保留最近的 N 个工具结果
- 可选地保留工具调用参数以保留上下文
typescriptimport { 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]", }), ], }), ], });
LLM 工具仿真器 (LLM tool emulator)
出于测试目的使用 LLM 模拟工具执行,使用 AI 生成的响应替代实际的工具调用。LLM 工具仿真器适用于以下场景:
- 在不执行真实工具的情况下测试智能体行为。
- 在外部工具不可用或调用昂贵时开发智能体。
- 在实现实际工具之前为智能体工作流构建原型。
import { createAgent, toolEmulatorMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.5",
tools: [getWeather, searchDatabase, sendEmail],
middleware: [
toolEmulatorMiddleware(), // 仿真所有工具
],
});配置选项 (Configuration options)
tools
(string | ClientTool | ServerTool)[]要仿真的工具名称(字符串)或工具实例列表。如果为
undefined(默认值),将仿真所有工具。如果为空数组[],则不仿真任何工具。如果是包含工具名称/实例的数组,则仅仿真这些工具。model
string | BaseChatModel用于生成仿真工具响应的模型。可以是模型标识符字符串(例如
'google:gemini-3.6-flash')或BaseChatModel实例。如果未指定,则默认为智能体的模型。
完整示例 (Full example)
该中间件使用 LLM 为工具调用生成合理的响应,而不是执行实际工具。
typescriptimport { createAgent, toolEmulatorMiddleware, tool } from "langchain"; import * as z from "zod"; const getWeather = tool( async ({ location }) => `Weather in ${location}`, { name: "get_weather", description: "Get the current weather for a location", schema: z.object({ location: z.string() }), } ); const sendEmail = tool( async ({ to, subject, body }) => "Email sent", { name: "send_email", description: "Send an email", schema: z.object({ to: z.string(), subject: z.string(), body: z.string(), }), } ); // 仿真所有工具(默认行为) const agent = createAgent({ model: "gpt-5.5", tools: [getWeather, sendEmail], middleware: [toolEmulatorMiddleware()], }); // 按名称仿真特定工具 const agent2 = createAgent({ model: "gpt-5.5", tools: [getWeather, sendEmail], middleware: [ toolEmulatorMiddleware({ tools: ["get_weather"], }), ], }); // 通过传入工具实例仿真特定工具 const agent3 = createAgent({ model: "gpt-5.5", tools: [getWeather, sendEmail], middleware: [ toolEmulatorMiddleware({ tools: [getWeather], }), ], }); // 使用自定义模型进行仿真 const agent5 = createAgent({ model: "gpt-5.5", tools: [getWeather, sendEmail], middleware: [ toolEmulatorMiddleware({ model: "claude-sonnet-4-6", }), ], });
提供商特定中间件 (Provider-specific middleware)
这些中间件针对特定的 LLM 提供商进行了优化。有关完整详细信息和示例,请参阅各个提供商的文档。
适用于 Claude 模型的提示词缓存、bash 工具、文本编辑器、记忆和文件搜索中间件。
适用于 Amazon Bedrock 模型的提示词缓存中间件。
