LangChain 和 Deep Agents 为常见用例提供预置 middleware。每个 middleware 都可用于生产环境,并且可以根据你的具体需求配置。
Provider-agnostic middleware
以下 middleware 可配合任意 LLM 提供商使用:
| Middleware | 描述 |
|---|
| Summarization | 接近 token 限制时自动总结对话历史。 |
| Human-in-the-loop | 暂停执行,等待人工批准工具调用。 |
| Model call limit | 限制模型调用次数,避免成本过高。 |
| Tool call limit | 通过限制调用次数来控制工具执行。 |
| Model fallback | 主模型失败时自动回退到备用模型。 |
| PII detection | 检测并处理个人身份信息 (PII)。 |
| To-do list | 为 agent 提供任务规划和跟踪能力。 |
| LLM tool selector | 调用主模型前,使用 LLM 选择相关工具。 |
| Tool retry | 使用指数退避自动重试失败的工具调用。 |
| Model retry | 使用指数退避自动重试失败的模型调用。 |
| LLM tool emulator | 使用 LLM 模拟工具执行,便于测试。 |
| Context editing | 通过修剪或清除工具使用来管理对话上下文。 |
| Filesystem | 为 agent 提供用于存储上下文和长期记忆的文件系统。 |
| Subagent middleware | 添加生成 subagent 的能力。 |
Summarization
接近 token 限制时自动总结对话历史,保留近期消息并压缩较早的上下文。Summarization 适用于以下场景:
- 超出上下文窗口的长时间运行对话。
- 包含大量历史记录的多轮对话。
- 需要保留完整对话上下文的应用。
Summarization 是面向文本的上下文压缩。它不会调整图片、音频或视频 payload 的大小、对其降采样,或以其他方式压缩这些 payload。keep 保留的近期消息仍包含原始多模态块,而被总结的较早多模态消息只由生成的文本摘要表示。对于大量使用图片的应用,请将媒体存储在文件系统或对象存储中,并通过消息历史传递 URL 或文件引用。
import { createAgent, summarizationMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [weatherTool, calculatorTool],
middleware: [
summarizationMiddleware({
model: "gpt-5.4-mini",
trigger: { tokens: 4000 },
keep: { messages: 20 },
}),
],
});
使用 langchain@1.1.0 时,trigger 和 keep 的 fraction 条件(如下所示)依赖聊天模型的 profile data。如果数据不可用,请使用其他条件或手动指定:const customProfile: ModelProfile = {
maxInputTokens: 100_000,
// ...
}
model = await initChatModel("...", {
profile: customProfile,
});
model
string | BaseChatModel
required
用于生成摘要的模型。可以是模型标识符字符串(例如 'openai:gpt-5.4-mini'),也可以是 BaseChatModel 实例。
触发总结的条件。可以是:
- 单个条件对象(必须满足所有属性,即 AND 逻辑)
- 条件对象数组(满足任一条件即可,即 OR 逻辑)
每个条件可以包含:
fraction (number):模型上下文大小的比例 (0-1)
tokens (number):绝对 token 数
messages (number):消息数
每个条件必须至少指定一个属性。如果未提供,summarization 不会自动触发。 keep
object
default:"{messages: 20}"
总结后要保留多少上下文。请仅指定以下一个条件:
fraction (number):要保留的模型上下文大小比例 (0-1)
tokens (number):要保留的绝对 token 数
messages (number):要保留的近期消息数量
自定义 token 计数函数。默认使用基于字符的计数。
用于总结的自定义 prompt 模板。如果未指定,则使用内置模板。模板应包含 {messages} 占位符,系统会在此插入对话历史。
生成摘要时包含的最大 token 数。总结前会修剪消息,使其符合此限制。
要添加到摘要消息的前缀。如果未提供,则使用默认前缀。
已弃用: 请改用 trigger: { tokens: value }。这是触发 summarization 的 token 阈值。
已弃用: 请改用 keep: { messages: value }。这是要保留的近期消息数量。
Summarization middleware 会监控消息 token 数,并在达到阈值时自动总结较早消息。触发条件 控制何时运行 summarization:
- 单个条件对象(必须满足指定条件)
- 条件数组(满足任一条件即可,即 OR 逻辑)
- 每个条件都可以使用
fraction(模型上下文大小比例)、tokens(绝对数量)或 messages(消息数量)
保留条件 控制要保留多少上下文(仅指定一个):
fraction:要保留的模型上下文大小比例
tokens:要保留的绝对 token 数
messages:要保留的近期消息数量
import { createAgent, summarizationMiddleware } from "langchain";
// 单个条件
const agent = createAgent({
model: "gpt-5.4",
tools: [weatherTool, calculatorTool],
middleware: [
summarizationMiddleware({
model: "gpt-5.4-mini",
trigger: { tokens: 4000, messages: 10 },
keep: { messages: 20 },
}),
],
});
// 多个条件
const agent2 = createAgent({
model: "gpt-5.4",
tools: [weatherTool, calculatorTool],
middleware: [
summarizationMiddleware({
model: "gpt-5.4-mini",
trigger: [
{ tokens: 3000, messages: 6 },
],
keep: { messages: 20 },
}),
],
});
// 使用比例限制
const agent3 = createAgent({
model: "gpt-5.4",
tools: [weatherTool, calculatorTool],
middleware: [
summarizationMiddleware({
model: "gpt-5.4-mini",
trigger: { fraction: 0.8 },
keep: { fraction: 0.3 },
}),
],
});
Human-in-the-loop
在工具调用执行前暂停 agent 执行,以便人工批准、编辑或拒绝工具调用。Human-in-the-loop 适用于以下场景:
- 需要人工批准的高风险操作(例如数据库写入、金融交易)。
- 必须由人工监督的合规工作流。
- 由人工反馈指导 agent 的长时间运行对话。
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.4",
tools: [readEmailTool, sendEmailTool],
middleware: [
humanInTheLoopMiddleware({
interruptOn: {
sendEmailTool: {
allowedDecisions: ["approve", "edit", "reject"],
},
readEmailTool: false,
}
})
]
});
观看这个视频指南,了解 Human-in-the-loop middleware 的行为。
Model call limit
限制模型调用次数,防止无限循环或成本过高。Model call limit 适用于以下场景:
- 防止失控的 agent 发起过多 API 调用。
- 在生产部署中执行成本控制。
- 在特定调用预算内测试 agent 行为。
import { createAgent, modelCallLimitMiddleware } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
const agent = createAgent({
model: "gpt-5.4",
checkpointer: new MemorySaver(), // thread 限制需要此项
tools: [],
middleware: [
modelCallLimitMiddleware({
threadLimit: 10,
runLimit: 5,
exitBehavior: "end",
}),
],
});
观看这个视频指南,了解 Model Call Limit middleware 的行为。
一个 thread 中所有运行的最大模型调用次数。默认不限制。
达到限制时的行为。选项:'end'(优雅终止)或 'error'(抛出异常)
通过限制工具调用次数来控制 agent 执行,可以对所有工具全局限制,也可以针对特定工具限制。Tool call limit 适用于以下场景:
- 防止过度调用成本较高的外部 API。
- 限制 web 搜索或数据库查询。
- 对特定工具的使用执行速率限制。
- 防止失控的 agent 循环。
import { createAgent, toolCallLimitMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [searchTool, databaseTool],
middleware: [
toolCallLimitMiddleware({ threadLimit: 20, runLimit: 10 }),
toolCallLimitMiddleware({
toolName: "search",
threadLimit: 5,
runLimit: 3,
}),
],
});
观看这个视频指南,了解 Tool Call Limit middleware 的行为。
要限制的特定工具名称。如果未提供,限制将全局应用于所有工具。
一个 thread(对话)中所有运行的最大工具调用次数。它会在相同 thread ID 的多次调用之间保留。需要 checkpointer 维护状态。undefined 表示不设置 thread 限制。
单次调用(一次用户消息到响应的循环)的最大工具调用次数。每条新用户消息都会重置。undefined 表示不设置运行限制。注意: 必须至少指定 threadLimit 或 runLimit 之一。
达到限制时的行为:
'continue'(默认):用错误消息阻止超限工具调用,让其他工具和模型继续。模型会根据错误消息决定何时结束。
'error':抛出 ToolCallLimitExceededError 异常,立即停止执行
'end':用超限工具调用对应的 ToolMessage 和 AI message 立即停止执行。仅在限制单个工具时有效;如果其他工具仍有待处理调用,则抛出错误。
使用以下方式指定限制:
- Thread limit:一个对话中所有运行的最大调用次数(需要 checkpointer)
- Run limit:单次调用的最大调用次数(每轮重置)
退出行为:
'continue'(默认):用错误消息阻止超限调用,agent 继续运行
'error':立即引发异常
'end':用 ToolMessage + AI message 停止(仅限单工具场景)
import { 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.4",
tools: [searchTool, databaseTool, scraperTool],
middleware: [globalLimiter, searchLimiter, databaseLimiter, strictLimiter],
});
Model fallback
主模型失败时自动回退到备用模型。Model fallback 适用于以下场景:
- 构建能处理模型中断的弹性 agent。
- 通过回退到更便宜的模型来优化成本。
- 在 OpenAI、Anthropic 等提供商之间提供冗余。
import { createAgent, modelFallbackMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [],
middleware: [
modelFallbackMiddleware(
"gpt-5.4-mini",
"claude-3-5-sonnet-20241022"
),
],
});
该 middleware 接受可变数量的字符串参数,按顺序表示 fallback 模型:主模型失败时要按顺序尝试的一个或多个 fallback 模型字符串modelFallbackMiddleware(
"first-fallback-model",
"second-fallback-model",
// ... more models
)
PII detection
使用可配置策略检测并处理对话中的个人身份信息 (PII)。PII detection 适用于以下场景:
- 有合规要求的医疗和金融应用。
- 需要清理日志的客服 agent。
- 任何处理敏感用户数据的应用。
import { createAgent, piiMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [],
middleware: [
piiMiddleware("email", { strategy: "redact", applyToInput: true }),
piiMiddleware("credit_card", { strategy: "mask", applyToInput: true }),
],
});
Custom PII types
你可以通过提供 detector 参数创建自定义 PII 类型。这样可以检测内置类型之外、与你的用例相关的模式。
创建自定义 detector 的三种方式:
-
Regex pattern string:简单模式匹配
-
RegExp object:更精细地控制 regex flag
-
Custom function:包含验证的复杂检测逻辑
import { createAgent, piiMiddleware, type PIIMatch } from "langchain";
// 方法 1:regex pattern string
const agent1 = createAgent({
model: "gpt-5.4",
tools: [],
middleware: [
piiMiddleware("api_key", {
detector: "sk-[a-zA-Z0-9]{32}",
strategy: "block",
}),
],
});
// 方法 2:RegExp object
const agent2 = createAgent({
model: "gpt-5.4",
tools: [],
middleware: [
piiMiddleware("phone_number", {
detector: /\+?\d{1,3}[\s.-]?\d{3,4}[\s.-]?\d{4}/,
strategy: "mask",
}),
],
});
// 方法 3:自定义 detector 函数
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.4",
tools: [],
middleware: [
piiMiddleware("ssn", {
detector: detectSSN,
strategy: "hash",
}),
],
});
自定义 detector 函数签名:
detector 函数必须接受字符串(content)并返回匹配项:
返回 PIIMatch 对象数组:
interface PIIMatch {
text: string; // 匹配到的文本
start: number; // content 中的起始索引
end: number; // content 中的结束索引
}
function detector(content: string): PIIMatch[] {
return [
{ text: "matched_text", start: 0, end: 12 },
// ... 更多匹配项
];
}
对于自定义 detector:
- 对简单模式使用 regex 字符串
- 需要 flag(例如不区分大小写匹配)时使用 RegExp 对象
- 需要模式匹配之外的验证逻辑时使用自定义函数
- 自定义函数可让你完全控制检测逻辑,并实现复杂的验证规则
要检测的 PII 类型。可以是内置类型(email、credit_card、ip、mac_address、url),也可以是自定义类型名称。
如何处理检测到的 PII。选项:
'block':检测到时抛出错误
'redact':替换为 [REDACTED_TYPE]
'mask':部分遮盖(例如 ****-****-****-1234)
'hash':替换为确定性 hash(例如 <email_hash:a1b2c3d4>)
detector
RegExp | string | function
自定义 detector。可以是:
RegExp:用于匹配的 regex pattern
string:regex pattern 字符串(例如 "sk-[a-zA-Z0-9]{32}")
function:自定义 detector 函数 (content: string) => PIIMatch[]
如果未提供,则使用该 PII 类型的内置 detector。
To-do list
为 agent 提供面向复杂多步骤任务的任务规划和跟踪能力。To-do list 适用于以下场景:
- 需要协调多个工具的复杂多步骤任务。
- 进度可见性很重要的长时间运行操作。
此 middleware 会自动为 agent 提供 write_todos 工具和 system prompts,以指导有效的任务规划。
import { createAgent, todoListMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [readFile, writeFile, runTests],
middleware: [todoListMiddleware()],
});
观看这个视频指南,了解 To-do List middleware 的行为。
没有可用的配置选项(使用默认值)。
在调用主模型前,使用 LLM 智能选择相关工具。LLM tool selector 适用于以下场景:
- 拥有大量工具(10+)且每个查询通常只需要其中少数工具的 agent。
- 通过过滤无关工具减少 token 使用量。
- 提升模型专注度和准确性。
此 middleware 使用结构化输出询问 LLM 哪些工具与当前查询最相关。结构化输出 schema 定义可用的工具名称和描述。模型提供商通常会在后台将这些结构化输出信息添加到 system prompt 中。
import { createAgent, llmToolSelectorMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [tool1, tool2, tool3, tool4, tool5, ...],
middleware: [
llmToolSelectorMiddleware({
model: "gpt-5.4-mini",
maxTools: 3,
alwaysInclude: ["search"],
}),
],
});
用于选择工具的模型。可以是模型标识符字符串(例如 'openai:gpt-5.4-mini'),也可以是 BaseChatModel 实例。默认使用 agent 的主模型。
给选择模型的指令。如果未指定,则使用内置 prompt。
可选择的最大工具数。如果模型选择了更多工具,则只使用前 maxTools 个。如果未指定,则不限制。
无论选择结果如何都始终包含的工具名称。这些工具不计入 maxTools 限制。
使用可配置的指数退避自动重试失败的工具调用。Tool retry 适用于以下场景:
- 处理外部 API 调用中的瞬时失败。
- 提升依赖网络的工具的可靠性。
- 构建能优雅处理临时错误的弹性 agent。
API reference: toolRetryMiddleware
import { createAgent, toolRetryMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [searchTool, databaseTool],
middleware: [
toolRetryMiddleware({
maxRetries: 3,
backoffFactor: 2.0,
initialDelayMs: 1000,
}),
],
});
初始调用后的最大重试次数(默认总共尝试 3 次)。必须 >= 0。
tools
(ClientTool | ServerTool | string)[]
可选的工具或工具名称数组,用于指定应用重试逻辑的工具。可以是 BaseTool 实例列表,也可以是工具名称字符串。如果为 undefined,则应用于所有工具。
retryOn
((error: Error) => boolean) | (new (...args: any[]) => Error)[]
default:"() => true"
可以是要重试的错误构造函数数组,也可以是接收错误并在应重试时返回 true 的函数。默认对所有错误重试。
onFailure
'error' | 'continue' | ((error: Error) => string)
default:"continue"
所有重试都耗尽时的行为。选项:
'continue'(默认):返回包含错误详情的 ToolMessage,允许 LLM 处理失败并尝试恢复
'error':重新引发异常,停止 agent 执行
- 自定义函数:接收异常并返回
ToolMessage 内容字符串的函数,可用于自定义错误格式
已弃用的值: 'raise'(请改用 'error')和 'return_message'(请改用 'continue')。这些已弃用值仍可工作,但会显示警告。 指数退避的乘数。每次重试等待 initialDelayMs * (backoffFactor ** retryNumber) 毫秒。设置为 0.0 可使用固定延迟。必须 >= 0。
第一次重试前的初始延迟,单位为毫秒。必须 >= 0。
两次重试之间的最大延迟,单位为毫秒(限制指数退避增长)。必须 >= 0。
是否向延迟添加随机 jitter(±25%),以避免 thundering herd
该 middleware 会使用指数退避自动重试失败的工具调用。关键配置:
maxRetries:重试次数(默认:2)
backoffFactor:指数退避乘数(默认:2.0)
initialDelayMs:起始延迟,单位为毫秒(默认:1000ms)
maxDelayMs:延迟增长上限(默认:60000ms)
jitter:添加随机变化(默认:true)
失败处理:
onFailure: "continue"(默认):返回错误消息
onFailure: "error":重新引发异常
- 自定义函数:返回错误消息的函数
import { createAgent, toolRetryMiddleware } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
// 使用默认设置的基本用法(2 次重试,指数退避)
const agent = createAgent({
model: "gpt-5.4",
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", // 重新引发异常,而不是返回消息
});
Model retry
使用可配置的指数退避自动重试失败的模型调用。Model retry 适用于以下场景:
- 处理模型 API 调用中的瞬时失败。
- 提升依赖网络的模型请求的可靠性。
- 构建能优雅处理临时模型错误的弹性 agent。
API reference: modelRetryMiddleware
import { createAgent, modelRetryMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [searchTool, databaseTool],
middleware: [
modelRetryMiddleware({
maxRetries: 3,
backoffFactor: 2.0,
initialDelayMs: 1000,
}),
],
});
初始调用后的最大重试次数(默认总共尝试 3 次)。必须 >= 0。
retryOn
((error: Error) => boolean) | (new (...args: any[]) => Error)[]
default:"() => true"
可以是要重试的错误构造函数数组,也可以是接收错误并在应重试时返回 true 的函数。默认对所有错误重试。
onFailure
'error' | 'continue' | ((error: Error) => string)
default:"continue"
所有重试都耗尽时的行为。选项:
'continue'(默认):返回包含错误详情的 AIMessage,允许 agent 尝试优雅处理失败
'error':重新引发异常,停止 agent 执行
- 自定义函数:接收异常并返回
AIMessage 内容字符串的函数,可用于自定义错误格式
指数退避的乘数。每次重试等待 initialDelayMs * (backoffFactor ** retryNumber) 毫秒。设置为 0.0 可使用固定延迟。必须 >= 0。
第一次重试前的初始延迟,单位为毫秒。必须 >= 0。
两次重试之间的最大延迟,单位为毫秒(限制指数退避增长)。必须 >= 0。
是否向延迟添加随机 jitter(±25%),以避免 thundering herd
该 middleware 会使用指数退避自动重试失败的模型调用。import { createAgent, modelRetryMiddleware } from "langchain";
// 使用默认设置的基本用法(2 次重试,指数退避)
const agent = createAgent({
model: "gpt-5.4",
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 status code
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", // 重新引发异常,而不是返回消息
});
使用 LLM 模拟工具执行以便测试,用 AI 生成的响应替代实际工具调用。LLM tool emulator 适用于以下场景:
- 不执行真实工具也能测试 agent 行为。
- 在外部工具不可用或成本较高时开发 agent。
- 在实现实际工具前,为 agent 工作流制作原型。
import { createAgent, toolEmulatorMiddleware } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [getWeather, searchDatabase, sendEmail],
middleware: [
toolEmulatorMiddleware(), // 模拟所有工具
],
});
tools
(string | ClientTool | ServerTool)[]
要模拟的工具名称(string)或工具实例列表。如果为 undefined(默认),则模拟所有工具。如果为空数组 [],则不模拟任何工具。如果是包含工具名称或实例的数组,则只模拟这些工具。
用于生成模拟工具响应的模型。可以是模型标识符字符串(例如 'google_genai:gemini-3.5-flash'),也可以是 BaseChatModel 实例。如果未指定,则默认使用 agent 的模型。
该 middleware 使用 LLM 为工具调用生成合理的响应,而不是执行实际工具。import { 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.4",
tools: [getWeather, sendEmail],
middleware: [toolEmulatorMiddleware()],
});
// 按名称模拟特定工具
const agent2 = createAgent({
model: "gpt-5.4",
tools: [getWeather, sendEmail],
middleware: [
toolEmulatorMiddleware({
tools: ["get_weather"],
}),
],
});
// 通过传入工具实例模拟特定工具
const agent3 = createAgent({
model: "gpt-5.4",
tools: [getWeather, sendEmail],
middleware: [
toolEmulatorMiddleware({
tools: [getWeather],
}),
],
});
// 使用自定义模型进行模拟
const agent5 = createAgent({
model: "gpt-5.4",
tools: [getWeather, sendEmail],
middleware: [
toolEmulatorMiddleware({
model: "claude-sonnet-4-6",
}),
],
});
Context editing
达到 token 限制时,通过清除较早的工具调用输出来管理对话上下文,同时保留近期结果。这有助于在包含大量工具调用的长对话中保持上下文窗口可控。Context editing 适用于以下场景:
- 包含大量工具调用并超出 token 限制的长对话
- 通过移除不再相关的较早工具输出降低 token 成本
- 在上下文中只保留最近 N 个工具结果
import { createAgent, contextEditingMiddleware, ClearToolUsesEdit } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [],
middleware: [
contextEditingMiddleware({
edits: [
new ClearToolUsesEdit({
triggerTokens: 100000,
keep: 3,
}),
],
}),
],
});
edits
ContextEdit[]
default:"[new ClearToolUsesEdit()]"
ClearToolUsesEdit options:触发编辑的 token 数。当对话超过此 token 数时,较早的工具输出会被清除。
编辑运行时至少回收的 token 数。如果设置为 0,则按需尽可能清除。
必须保留的最近工具结果数量。这些结果永远不会被清除。
是否清除 AI message 上原始工具调用参数。为 true 时,工具调用参数会被替换为空对象。
要排除在清除之外的工具名称列表。这些工具的输出永远不会被清除。
placeholder
string
default:"[cleared]"
为已清除工具输出插入的占位文本。它会替换原始工具消息内容。
达到 token 限制时,该 middleware 会应用上下文编辑策略。最常见的策略是 ClearToolUsesEdit,它会清除较早的工具结果,同时保留近期结果。工作方式:
- 监控对话中的 token 数
- 达到阈值时,清除较早的工具输出
- 保留最近 N 个工具结果
- 可选保留工具调用参数作为上下文
import { createAgent, contextEditingMiddleware, ClearToolUsesEdit } from "langchain";
const agent = createAgent({
model: "gpt-5.4",
tools: [searchTool, calculatorTool, databaseTool],
middleware: [
contextEditingMiddleware({
edits: [
new ClearToolUsesEdit({
triggerTokens: 2000,
keep: 3,
clearToolInputs: false,
excludeTools: [],
placeholder: "[cleared]",
}),
],
}),
],
});
Filesystem middleware
上下文工程是构建有效 agent 的主要挑战。使用会返回可变长度结果的工具(例如 web_search 和 RAG)时尤其困难,因为较长的工具结果会快速填满上下文窗口。
Deep Agents 的 FilesystemMiddleware 提供四个工具,用于与短期记忆和长期记忆交互:
ls:列出文件系统中的文件
read_file:读取整个文件,或读取文件中的指定行数
write_file:向文件系统写入新文件
edit_file:编辑文件系统中的现有文件
import { createAgent } from "langchain";
import { createFilesystemMiddleware } from "deepagents";
// createDeepAgent 默认包含 FilesystemMiddleware
// 构建自定义 agent 时可以自定义它
const agent = createAgent({
model: "claude-sonnet-4-6",
middleware: [
createFilesystemMiddleware({
backend: undefined, // 可选:自定义 backend(默认为 StateBackend)
systemPrompt: "Write to the filesystem when...", // 可选:自定义 system prompt 覆盖
customToolDescriptions: {
ls: "Use the ls tool when...",
read_file: "Use the read_file tool to...",
}, // 可选:filesystem 工具的自定义描述
}),
],
});
Short-term vs. long-term filesystem
默认情况下,这些工具会写入 graph state 中的本地 “filesystem”。要启用跨 thread 的持久存储,请配置 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...", // 可选:自定义 system prompt 覆盖
customToolDescriptions: {
ls: "Use the ls tool when...",
read_file: "Use the read_file tool to...",
}, // 可选:filesystem 工具的自定义描述
}),
],
});
当你为 /memories/ 配置带 StoreBackend 的 CompositeBackend 时,所有以 /memories/ 为前缀的文件都会保存到持久存储中,并在不同 thread 之间保留。没有此前缀的文件会留在临时状态存储中。
Subagent
将任务交给 subagent 可以隔离上下文,让主(supervisor)agent 的上下文窗口保持干净,同时仍能深入处理任务。
Deep Agents 的 subagents middleware 允许你通过 task 工具提供 subagent。
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.4",
middleware: [],
},
],
}),
],
});
subagent 由 name、description、system prompt 和 tools 定义。你也可以为 subagent 提供自定义 model 或额外的 middleware。如果你想给 subagent 一个额外的状态键,与主 agent 共享,这会特别有用。
对于更复杂的用例,也可以将自己的预置 LangGraph graph 作为 subagent 提供。
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.4",
middleware: [],
};
const agent = createAgent({
model: "claude-sonnet-4-6",
middleware: [
createSubAgentMiddleware({
defaultModel: "claude-sonnet-4-6",
defaultTools: [],
subagents: [weatherSubagent],
}),
],
});
除了用户定义的 subagent,主 agent 始终可以访问 general-purpose subagent。该 subagent 拥有与主 agent 相同的指令,以及主 agent 可访问的所有工具。general-purpose subagent 的主要用途是上下文隔离,主 agent 可以将复杂任务委派给它,并获得简洁答案,而不会把中间工具调用的冗余内容带回主上下文。
Provider-specific middleware
这些 middleware 针对特定 LLM 提供商进行了优化。完整详情和示例,请参阅各提供商文档。
Anthropic
面向 Claude 模型的 prompt caching、bash tool、text editor、memory 和 file search middleware。