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 时,triggerkeepfraction 条件(如下所示)依赖聊天模型的 profile data。如果数据不可用,请使用其他条件或手动指定:
const customProfile: ModelProfile = {
    maxInputTokens: 100_000,
    // ...
}
model = await initChatModel("...", {
    profile: customProfile,
});
model
string | BaseChatModel
required
用于生成摘要的模型。可以是模型标识符字符串(例如 'openai:gpt-5.4-mini'),也可以是 BaseChatModel 实例。
trigger
object | object[]
触发总结的条件。可以是:
  • 单个条件对象(必须满足所有属性,即 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):要保留的近期消息数量
tokenCounter
function
自定义 token 计数函数。默认使用基于字符的计数。
summaryPrompt
string
用于总结的自定义 prompt 模板。如果未指定,则使用内置模板。模板应包含 {messages} 占位符,系统会在此插入对话历史。
trimTokensToSummarize
number
default:"4000"
生成摘要时包含的最大 token 数。总结前会修剪消息,使其符合此限制。
summaryPrefix
string
要添加到摘要消息的前缀。如果未提供,则使用默认前缀。
maxTokensBeforeSummary
number
deprecated
已弃用: 请改用 trigger: { tokens: value }。这是触发 summarization 的 token 阈值。
messagesToKeep
number
deprecated
已弃用: 请改用 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 的长时间运行对话。
Human-in-the-loop middleware 需要 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.4",
  tools: [readEmailTool, sendEmailTool],
  middleware: [
    humanInTheLoopMiddleware({
      interruptOn: {
        sendEmailTool: {
          allowedDecisions: ["approve", "edit", "reject"],
        },
        readEmailTool: false,
      }
    })
  ]
});
如需完整示例、配置选项和集成模式,请参阅 Human-in-the-loop 文档
观看这个视频指南,了解 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 的行为。
threadLimit
number
一个 thread 中所有运行的最大模型调用次数。默认不限制。
runLimit
number
单次调用的最大模型调用次数。默认不限制。
exitBehavior
string
default:"end"
达到限制时的行为。选项:'end'(优雅终止)或 'error'(抛出异常)

Tool call limit

通过限制工具调用次数来控制 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 的行为。
toolName
string
要限制的特定工具名称。如果未提供,限制将全局应用于所有工具
threadLimit
number
一个 thread(对话)中所有运行的最大工具调用次数。它会在相同 thread ID 的多次调用之间保留。需要 checkpointer 维护状态。undefined 表示不设置 thread 限制。
runLimit
number
单次调用(一次用户消息到响应的循环)的最大工具调用次数。每条新用户消息都会重置。undefined 表示不设置运行限制。注意: 必须至少指定 threadLimitrunLimit 之一。
exitBehavior
string
default:"continue"
达到限制时的行为:
  • '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 模型:
...models
string[]
required
主模型失败时要按顺序尝试的一个或多个 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 的三种方式:
  1. Regex pattern string:简单模式匹配
  2. RegExp object:更精细地控制 regex flag
  3. 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 对象
  • 需要模式匹配之外的验证逻辑时使用自定义函数
  • 自定义函数可让你完全控制检测逻辑,并实现复杂的验证规则
piiType
string
required
要检测的 PII 类型。可以是内置类型(emailcredit_cardipmac_addressurl),也可以是自定义类型名称。
strategy
string
default:"redact"
如何处理检测到的 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。
applyToInput
boolean
default:"true"
在模型调用前检查用户消息
applyToOutput
boolean
default:"false"
在模型调用后检查 AI messages
applyToToolResults
boolean
default:"false"
执行后检查工具结果消息

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 tool selector

在调用主模型前,使用 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"],
    }),
  ],
});
model
string | BaseChatModel
用于选择工具的模型。可以是模型标识符字符串(例如 'openai:gpt-5.4-mini'),也可以是 BaseChatModel 实例。默认使用 agent 的主模型。
systemPrompt
string
给选择模型的指令。如果未指定,则使用内置 prompt。
maxTools
number
可选择的最大工具数。如果模型选择了更多工具,则只使用前 maxTools 个。如果未指定,则不限制。
alwaysInclude
string[]
无论选择结果如何都始终包含的工具名称。这些工具不计入 maxTools 限制。

Tool retry

使用可配置的指数退避自动重试失败的工具调用。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,
    }),
  ],
});
maxRetries
number
default:"2"
初始调用后的最大重试次数(默认总共尝试 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')。这些已弃用值仍可工作,但会显示警告。
backoffFactor
number
default:"2.0"
指数退避的乘数。每次重试等待 initialDelayMs * (backoffFactor ** retryNumber) 毫秒。设置为 0.0 可使用固定延迟。必须 >= 0。
initialDelayMs
number
default:"1000"
第一次重试前的初始延迟,单位为毫秒。必须 >= 0。
maxDelayMs
number
default:"60000"
两次重试之间的最大延迟,单位为毫秒(限制指数退避增长)。必须 >= 0。
jitter
boolean
default:"true"
是否向延迟添加随机 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,
    }),
  ],
});
maxRetries
number
default:"2"
初始调用后的最大重试次数(默认总共尝试 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 内容字符串的函数,可用于自定义错误格式
backoffFactor
number
default:"2.0"
指数退避的乘数。每次重试等待 initialDelayMs * (backoffFactor ** retryNumber) 毫秒。设置为 0.0 可使用固定延迟。必须 >= 0。
initialDelayMs
number
default:"1000"
第一次重试前的初始延迟,单位为毫秒。必须 >= 0。
maxDelayMs
number
default:"60000"
两次重试之间的最大延迟,单位为毫秒(限制指数退避增长)。必须 >= 0。
jitter
boolean
default:"true"
是否向延迟添加随机 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 tool emulator

使用 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(默认),则模拟所有工具。如果为空数组 [],则不模拟任何工具。如果是包含工具名称或实例的数组,则只模拟这些工具。
model
string | BaseChatModel
用于生成模拟工具响应的模型。可以是模型标识符字符串(例如 '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()]"
要应用的 ContextEdit 策略数组
ClearToolUsesEdit options:
triggerTokens
number
default:"100000"
触发编辑的 token 数。当对话超过此 token 数时,较早的工具输出会被清除。
clearAtLeast
number
default:"0"
编辑运行时至少回收的 token 数。如果设置为 0,则按需尽可能清除。
keep
number
default:"3"
必须保留的最近工具结果数量。这些结果永远不会被清除。
clearToolInputs
boolean
default:"false"
是否清除 AI message 上原始工具调用参数。为 true 时,工具调用参数会被替换为空对象。
excludeTools
string[]
default:"[]"
要排除在清除之外的工具名称列表。这些工具的输出永远不会被清除。
placeholder
string
default:"[cleared]"
为已清除工具输出插入的占位文本。它会替换原始工具消息内容。
达到 token 限制时,该 middleware 会应用上下文编辑策略。最常见的策略是 ClearToolUsesEdit,它会清除较早的工具结果,同时保留近期结果。工作方式:
  1. 监控对话中的 token 数
  2. 达到阈值时,清除较早的工具输出
  3. 保留最近 N 个工具结果
  4. 可选保留工具调用参数作为上下文
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 AgentsFilesystemMiddleware 提供四个工具,用于与短期记忆和长期记忆交互:
  • 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/ 配置带 StoreBackendCompositeBackend 时,所有以 /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 由 namedescriptionsystem prompttools 定义。你也可以为 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 提供商进行了优化。完整详情和示例,请参阅各提供商文档。
/images/providers/anthropic-icon.svg

Anthropic

面向 Claude 模型的 prompt caching、bash tool、text editor、memory 和 file search middleware。