LangChain提供了一些内置的中间件提供使用,避免重复造轮子,主要介绍官方提供中间件的介绍与使用。提供的中间件以功能进行区分,有以下几类
官方地址:https://docs.langchain.com/oss/python/langchain/middleware/built-in
对话管理与优化
Summarization(对话总结)
它是 LangChain 1.0 的核心中间件之一,专门解决长对话场景下的上下文管理问题。
当对话内容接近模型的 token 限制时,它会自动对较早的对话历史进行总结,在保留关键信息的同时压缩内容,确保智能体能够继续处理新的用户输入,避免因上下文过长而导致的调用失败或性能下降。
核心价值
- 上下文压缩:自动总结旧消息,释放宝贵的 token 空间,让对话可以持续进行。
- 信息保留:智能提取对话中的关键信息,避免重要内容在压缩过程中丢失。
- 对话连贯:通过总结历史,保持多轮对话的连贯性和上下文理解能力,让模型始终 “记得” 之前的讨论。
- 成本优化:减少不必要的 token 消耗,从而降低大模型 API 调用的成本。
工作原理
触发机制
它通过灵活的条件来控制何时执行总结操作,支持单一条件或多个条件组合(OR 逻辑):
Token 数量触发
当对话的总 token 数达到设定阈值时触发,使用
trigger=("tokens", value)。例如:
trigger=("tokens", 3000)表示当 token 数超过 3000 时执行总结。消息数量触发
当对话的消息数量达到设定阈值时触发,使用
trigger=("messages", value)。例如:
trigger=("messages", 50)表示当消息数超过 50 条时执行总结。上下文比例触发
当对话占用模型上下文窗口的比例达到设定值时触发,使用
trigger=("fraction", value)。例如:
trigger=("fraction", 0.8)表示当对话占用了 80% 的上下文窗口时执行总结。
保留策略
总结之后,如何保留关键信息,有以下几种策略:
消息保留
通过
keep=("messages", value)参数指定保留的消息数量,默认是 20 条。例如:
keep=("messages", 10)表示只保留最新的 10 条消息,更早的消息会被总结。Token 保留
通过
keep=("tokens", value)参数指定保留的 token 数量。例如:
keep=("tokens", 1000)表示只保留最新的 1000 个 token。比例保留
通过
keep=("fraction", value)参数按比例保留上下文。例如:
keep=("fraction", 0.2)表示保留最新的 20% 上下文。智能提取
使用指定的模型自动提取对话中的关键实体、用户意图和核心上下文信息,避免重要信息丢失。
总结生成
生成高质量的对话总结,并将其添加到消息历史中,替代被压缩的旧消息。
上下文维护
确保保留足够的上下文信息,以维持多轮对话的连贯性和模型的理解能力。
简单来说,触发机制决定了 “什么时候” 进行总结,而保留策略则决定了 “总结后如何保留信息”。两者结合,让 SummarizationMiddleware 能够智能地管理长对话的上下文,既保证了对话的连贯性,又避免了 token 超限的问题。1
参数说明
必需参数
| 参数名 | 类型 | 说明 | |
|---|---|---|---|
model |
string \ | BaseChatModel | 用于生成总结的模型,可以是模型标识符(如 "gpt-4o")或 BaseChatModel 实例。当使用 fraction 条件时,需要模型的 profile 数据(如 max_input_tokens),可手动指定或由系统自动获取。 |
可选参数
trigger(触发条件)
控制何时执行总结操作,支持三种条件类型,可组合使用:
fraction (float):模型上下文窗口的使用比例(0-1)tokens (int):绝对 token 数量messages (int):消息数量- 条件组合:
- 单一条件:所有属性必须满足(AND 逻辑)
- 条件列表:满足任一条件即可(OR 逻辑)
- 注意:使用
fraction时,需要模型的profile数据。
keep(保留策略)
控制总结后保留的上下文数量,必须且只能指定一种方式:
fraction (float):保留模型上下文窗口的比例(0-1)tokens (int):保留的绝对 token 数量messages (int):保留的最近消息数量(默认 20 条)- 注意:使用
fraction时,需要模型的profile数据。
trim_tokens_to_summarize
- 生成总结前,将待总结的消息修剪到的最大 token 数量
- 默认值:4000
- 作用:避免总结时输入过长,影响生成效率和质量
summary_prefix
- 添加到总结消息的前缀文本
- 作用:标识总结消息的来源或性质,便于调试和区分
token_counter
- 用于计算对话消息 token 数量的函数
- 默认:使用 LangChain 内置的
count_tokens_approximately - 自定义:可提供接受消息列表并返回 token 数的函数,用于精确计数场景
summary_prompt
- 用于生成对话总结的提示模板
- 默认:使用内置的 “Context Extraction Assistant” 模板
- 自定义:模板中需包含
{messages}占位符,可定制总结的风格、侧重点和详细程度
关键使用要点
fraction条件依赖:无论是trigger还是keep,使用fraction时都需要模型的profile数据(如max_input_tokens),否则建议使用tokens或messages。- 触发与保留的配合:
trigger决定 “何时总结”,keep决定 “总结后留多少”,两者需根据模型上下文窗口大小合理配置。 - 可扩展性:通过
summary_prompt和token_counter等参数,可针对特定业务场景定制总结逻辑,提升上下文管理的精准度。
代码示例
1 | from langchain.agents import create_agent |
其他代码示例
自定义总结提示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 自定义总结提示模板
custom_summary_prompt = """
请总结以下对话内容,重点关注:
1. 用户的主要问题和需求
2. 已经提供的解决方案
3. 尚未解决的关键问题
4. 重要的上下文信息
对话内容:
{messages}
"""
custom_summarization = SummarizationMiddleware(
model="gpt-4o-mini",
trigger=[("tokens", 4000)],
keep=("messages", 15),
summary_prompt=custom_summary_prompt
)
多条件触发配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 多条件触发示例
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
# 基于多个条件触发总结的智能体
agent = create_agent(
model="gpt-4o",
tools=[weather_tool, calculator_tool],
middleware=[
SummarizationMiddleware(
model="gpt-4o-mini",
# OR逻辑:只要满足“token数量”或“消息数量”条件即可触发总结
trigger=[("tokens", 4000), ("messages", 10)],
keep=("messages", 20),
),
]
)
基于比例的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 基于模型上下文比例的配置
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
# 基于模型上下文窗口比例的智能体
agent = create_agent(
model="gpt-4o",
tools=[weather_tool, calculator_tool],
middleware=[
SummarizationMiddleware(
model="gpt-4o-mini",
# 当使用80%的上下文窗口时触发总结
trigger=[("fraction", 0.8)],
# 保留30%的上下文窗口内容
keep=("fraction", 0.3),
),
]
)
最佳实践
✅ 推荐做法
- 轻量模型总结:使用轻量级模型(如 gpt-4o-mini)进行总结,在保证质量的同时降低成本和延迟。
- 合理触发条件:避免过于频繁的总结,根据对话场景和模型上下文窗口大小,设置合适的
trigger阈值。 - 保留最近消息:保留足够的最近消息(通过
keep参数),确保多轮对话的连贯性和上下文理解。 - 自定义提示模板:根据具体业务场景定制
summary_prompt,明确总结的重点和风格,提升信息提取的精准度。 - 监控与调整:持续监控总结质量和效果,根据实际对话情况及时调整
trigger、keep等参数。
⚠️ 注意事项
- 避免过低 trigger 阈值:过低的触发阈值会导致总结过于频繁,影响系统性能和响应速度。
- 避免过大 keep 值:过大的
keep值可能导致总结后上下文仍接近 token 限制,再次触发总结,形成循环。 - 保持模型一致性:总结模型与主模型的能力和理解方式应保持一致,避免因模型差异导致理解偏差。
- 防范信息丢失:总结过程中可能丢失关键细节,需通过合理的提示和保留策略降低风险。
- 动态调整 keep 参数:在长对话场景中,根据对话复杂度和信息密度,适当调整
keep参数,平衡上下文连贯性和 token 消耗。
适用场景推荐
| 场景分类 | 核心适用场景 | 典型子场景 | 推荐配置 | 配置说明 |
|---|---|---|---|---|
| 1. 客户服务与支持 | 适用于需要处理复杂客户问题的场景,特别是当客户问题需要多轮沟通才能解决时 | - 长时间的故障排除和问题解决过程 - 需要收集和汇总大量客户信息的服务流程 - 多步骤的产品使用指导和教程 - 处理包含大量上下文信息的客户投诉 |
keep=("messages", 20-30),使用针对性的客户服务总结提示模板 |
保留 20-30 条最新消息,确保客服能清晰掌握问题脉络;总结模板重点提取用户诉求、已采取措施和待办事项,提升服务效率。 |
| 2. 教育和学习辅助 | 适用于长期学习过程中的连续对话,特别是当学习内容需要分步骤讲解时 | - 在线课程中的问答互动环节 - 作业辅导和解题思路讲解 - 编程教学和代码调试辅助 - 外语学习中的对话练习和语法讲解 |
keep=("messages", 15-25),使用注重知识点保留的总结模板 |
保留 15-25 条最新消息,维持学习连贯性;总结模板重点提取关键知识点、解题步骤和易错点,帮助学生巩固记忆。 |
| 3. 技术支持和开发辅助 | 适用于复杂技术问题的解决过程,特别是当问题需要多轮排查和讨论时 | - 软件调试和故障排除对话 - 系统架构和设计讨论 - 代码审查和优化建议 - API 使用和集成咨询 |
使用自定义 token 计数器,保留更多技术细节的总结模板 | 自定义 token 计数器确保精确统计;总结模板重点提取错误信息、代码片段、架构决策和解决方案,方便技术人员回溯问题。 |
| 4. 内容创作和研究辅助 | 适用于需要持续讨论和迭代的创作过程,特别是需要保持思路连贯的场景 | - 文章、报告和书籍写作过程 - 创意构思和头脑风暴会话 - 研究资料收集和分析 - 数据分析和洞察挖掘对话 |
较高的 keep 值(25-40),使用注重创意和思路保留的总结模板 | 保留 25-40 条最新消息,确保创作思路不中断;总结模板重点提取核心观点、创意灵感和研究结论,辅助内容迭代。 |
| 5. 多角色和复杂业务流程 | 适用于需要多个角色协作或遵循复杂业务流程的对话场景 | - 多步骤的审批流程和表单填写辅助 - 需要多人协作的项目规划 - 跨部门协作的业务流程处理 - 包含多个阶段的咨询服务 |
根据业务复杂度调整参数,使用结构化的总结模板突出关键决策点 | 根据流程复杂度动态调整 keep 值;总结模板采用结构化输出,清晰列出各阶段决策、参与角色和待办事项,保障流程顺畅。 |
场景选择关键考量因素
- 对话长度:预计对话轮次超过 15-20 轮时,使用 SummarizationMiddleware 的收益会更加明显。
- 信息密度:当对话包含大量需要保留的关键信息时,能有效避免信息丢失。
- 成本控制:在需要优化 API 调用成本、减少不必要 token 消耗的场景中表现突出。
- 上下文管理:在需要在有限 token 内维持对话连贯性的场景中,是理想的解决方案。
- 多轮交互:对于需要记住早期对话内容的复杂任务,能显著提升智能体的理解能力。
Context editing(上下文编辑)
ContextEditingMiddleware 是 LangChain 1.0 中的上下文编辑中间件,专门用于在对话达到令牌限制时,清理旧的工具调用输出,同时保留最近的结果。
它的核心作用是:在包含大量工具调用的长对话中,保持上下文窗口的可管理性,通过智能删除不再相关的工具输出,来优化令牌使用并控制 API 调用成本。
核心价值
| 核心价值 | 具体说明 |
|---|---|
| 令牌管理 | 在长对话中精确控制令牌使用,避免超出模型上下文窗口限制,防止对话中断。 |
| 成本优化 | 减少不必要的令牌消耗,直接降低大模型 API 的调用成本。 |
| 智能保留 | 自动识别并保留最近、最相关的工具调用结果,确保对话逻辑的连贯性。 |
| 上下文管理 | 保持上下文窗口的可管理性和相关性,让代理始终基于有效信息进行决策。 |
| 灵活配置 | 支持自定义触发条件(如令牌阈值)和清理策略,适应不同场景需求。 |
| 工具选择性 | 可以选择排除特定工具的输出不被清理,确保关键信息始终保留在上下文中。 |
工作原理
- 令牌监控与清理机制
ContextEditingMiddleware 主要通过 ClearToolUsesEdit 策略来监控对话的令牌计数并管理工具调用输出。当对话超过指定的令牌阈值时,它会自动清理旧的工具输出,同时保留最近的结果,以维持上下文的连续性。
特别适用的场景:
- 具有许多工具调用且超出令牌限制的长对话
- 通过移除不再相关的旧工具输出来降低令牌成本
- 在上下文中仅保留最近的 N 个工具结果
- 实时令牌监控
这是中间件的核心能力之一,确保系统能精准感知令牌使用情况:
- 持续跟踪:实时监控对话中的令牌使用情况
- 计算灵活:支持近似或精确的令牌计算方法
- 模型优化:基于不同模型的特性优化计数逻辑
- 阈值可配:支持自定义触发清理的令牌阈值参数
- 智能清理策略
在达到阈值后,中间件会执行一套智能的清理策略,确保上下文既精简又有效:
- 选择性删除:只删除旧的、不再相关的工具输出
- 保留最新:自动保留最新的 N 个工具调用结果
- 工具排除:支持排除特定工具的输出,使其不被清理
- 阈值定制:可定制清理的触发条件和保留数量
工作流程
监控对话令牌计数
核心任务:持续跟踪对话的令牌使用情况。
计算方式:根据配置的方法(
approximate近似或model精确)来计算令牌数。作用:为后续的清理决策提供数据基础。
触发阈值检测
核心任务:当令牌计数达到或超过
trigger参数设置的阈值时,触发上下文清理流程。作用:确保在对话超出模型上下文窗口限制前,主动进行干预。
清理旧工具输出
核心任务:删除超出保留数量的旧工具输出,但保留最近的 N 个结果(由
keep参数指定)。作用:在保证对话逻辑连贯的前提下,最大限度地减少令牌占用。
应用配置策略
核心任务:根据
clear_tool_inputs、exclude_tools和placeholder等参数执行相应操作。clear_tool_inputs:是否清理工具的输入信息。exclude_tools:指定哪些工具的输出不被清理。placeholder:用占位符替换被清理的内容,保持上下文结构。
作用:实现高度自定义的清理策略,满足不同场景的需求。
更新上下文窗口
核心任务:将优化后的上下文应用到对话中,确保令牌使用在可管理范围内。
作用:让代理能够基于精简后的上下文继续工作,避免因令牌超限而中断。
代码示例
中间件在达到令牌限制时应用上下文编辑策略。最常见的策略是ClearToolUserEdit,它清除旧的工具结果同时保留最近的结果。
工作原理:
- 监控对话中的令牌计数
- 当达到阈值(
trigger=2000)时,清除旧的工具输出 - 保留最近的
keep=3个工具结果 - 可选地保留工具调用参数(
clear_tool_inputs=False)以供上下文使用
1 | from langchain.agents import create_agent |
自定义触发阈值和保留策略
1 | # 自定义触发阈值和保留策略示例 |
排除特定工具和最小令牌回收
1 | # 排除特定工具和设置最小令牌回收示例 |
处理复杂多工具对话场景
1 | # 复杂多工具对话场景配置示例 |
参数说明
ContextEditingMiddleware
| 参数名 | 类型 | 默认值 | 作用 | 说明 |
|---|---|---|---|---|
| edits | list[ContextEdit] | [ClearToolUsesEdit()] |
指定要应用的 ContextEdit 策略列表,决定了上下文清理的具体行为。 |
可以传入多个策略,中间件会按顺序执行,以实现更复杂的上下文管理逻辑。 |
| token_count_method | string | "approximate" |
指定对话中令牌计数的方法,影响性能和准确性 | 可选值: - approximate(默认):使用近似算法快速估算令牌数,性能更高。- model:使用模型本身的精确计数方法,结果更准确但开销更大。在开发和测试阶段, approximate 通常足够;对精度要求极高的场景可切换为 model。 |
ClearToolUsesEdit
| 参数名 | 类型 | 默认值 | 作用 | 说明 |
|---|---|---|---|---|
| trigger | number | 100000 | 触发上下文编辑的令牌计数阈值 | 当对话总令牌数超过此值时,自动清理旧工具输出。 |
| clear_at_least | number | 0 | 编辑运行时至少回收的令牌数 | 设置为 0 时,会清除尽可能多的令牌;设置为大于 0 的值时,确保至少回收指定数量的令牌 示例: clear_at_least=5000 |
| keep | number | 3 | 必须保留的最近工具结果数量 | 保留最新的 N 个工具调用结果,这些结果永远不会被清理。 示例: keep=3 |
| clear_tool_inputs | bool | False | 是否清除 AI 消息上的工具调用参数 | 设为 True 时,工具调用参数会被替换为空对象,进一步节省令牌。 示例: clear_tool_inputs=True |
| exclude_tools | list[string] | () | 排除在清除之外的工具名称列表 | 指定的工具输出永远不会被清理,确保关键信息始终保留。 示例: exclude_tools=("get_weather",) |
| placeholder | string | “[cleared]” | 插入被清除工具输出的占位符文本 | 用占位符替换被清理的工具内容,保持上下文结构的完整性。 示例: placeholder="[cleared]" |
最佳实践
✅ 推荐做法
- 场景化配置:根据应用场景选择合适的触发阈值(
trigger),避免一刀切。 - 关键工具保护:为关键业务工具配置
exclude_tools参数,确保其输出永不被清理。 - 动态调整保留数:根据对话复杂度调整
keep参数,在上下文连贯性和令牌优化之间取得平衡。 - 提升可读性:使用有意义的
placeholder文本,让用户和开发者清楚哪些内容被清理。 - 持续监控:监控对话长度和令牌使用情况,及时调整配置以适应变化。
- 平衡优化:在信息保留和令牌优化之间找到平衡点,避免过度清理导致任务失败。
⚠️ 注意事项
- 避免频繁清理:不要设置过低的
trigger值,否则会导致上下文频繁被截断,影响对话逻辑。 - 防止上下文丢失:过度清理会导致关键历史信息丢失,使代理无法理解当前任务。
- 评估参数影响:开启
clear_tool_inputs前,需评估其对任务理解和后续工具调用的潜在影响。 - 选择计数方法:根据性能和精度需求,选择合适的
token_count_method(approximate或model)。 - 测试验证:在上线前,测试不同配置对对话质量和任务完成率的影响。
- 模型适配:根据不同模型的上下文窗口大小,调整令牌阈值。
🎯 适用场景
| 场景 | 核心价值 |
|---|---|
| 长对话系统 | 适用于需要长时间保持上下文的交互式系统,如客服机器人、个人助理。 |
| 多工具工作流 | 适用于频繁调用多个工具的复杂任务处理,如数据分析、报告生成。 |
| 资源优化 | 适用于需要严格控制令牌使用成本的应用场景,如高并发的企业级服务。 |
常见问题
| 问题 | 解答要点 |
|---|---|
如何确定合适的 trigger 值? |
基于模型最大令牌限制和对话复杂度设置,一般设为模型最大令牌限制的 60-80%,为后续对话预留空间。 |
clear_tool_inputs 参数应该如何选择? |
- 若工具调用参数对后续对话重要 → 设为 False- 若工具调用参数较大且后续无需参考 → 设为 True 以节省令牌 |
token_count_method 选择 approximate 还是 model? |
- approximate:计算更快,但精度稍低- model:与模型实际计数方式一致,更准确,但会增加计算开销 |
| 如何监控上下文编辑的效果? | 通过以下方式评估并调整参数: - 记录每次编辑前后的令牌数量变化 - 观察对话质量和任务完成率 - 监控 API 调用成本变化 |
人工干预与控制
Human-in-the-loop(关键决策)
HumanInTheLoopMiddleware,它是 LangChain 1.0 中的一个核心安全中间件,核心作用是为 AI 代理提供人工监督机制。
核心定义
当 AI 助手需要执行可能敏感或危险的操作时,这个中间件会自动暂停执行流程,等待人工审核和决策,确保所有重要操作都在人类的监督下进行。
- 安全守护:防止 AI 助手执行可能有害的操作。
- 人工监督:保持人类对关键决策的最终控制权。
- 灵活决策:支持批准、编辑、拒绝三种决策方式。
- 审计追踪:完整记录所有人工介入的决策过程。
简单来说,它就像 AI 执行重要操作前的 “安全闸口”,让人类始终掌握最终决定权,同时也为后续审计提供了完整记录。
在调用工具前,中间件会通过智能策略自动识别操作类型:
- 自动批准:安全的只读操作,如查询数据、读取文件等,无需人工干预即可执行。
- 需要审核:写操作、删除操作、系统配置变更等可能敏感或有风险的操作,会触发人工审核流程。
中间件定义了人类响应中断的三种内置方式
| 决策类型 | 描述 | 示例用例 |
|---|---|---|
| ✅ approve | 操作按原样批准并执行,不进行任何更改。 | 按原样发送电子邮件草稿 |
| ✏️ edit | 工具调用在修改后执行。 | 在发送电子邮件前更改收件人 |
| ❌ reject | 工具调用被拒绝,并在对话中添加解释。 | 拒绝电子邮件草稿并解释如何重写 |
代码示例
1 | # 基础人工介入中间件配置 |
处理人工介入响应代码示例
1 | # 执行代理并处理中断 |
参数说明
HumanInTheLoopMiddleware
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| interrupt_on | dict | 必填 | 工具名称 → 中断配置。 True=使用默认配置、False=跳过审批、dict=自定义 InterruptOnConfig |
InterruptOnConfig
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| allowed_decisions | list[str] | 可选 | 可选:”approve”、”edit”、”reject” |
| description | string 或 callable | None | 人类审批时显示的提示说明 |
| description_prefix | string | "Tool execution requires approval" |
自定义介入消息前缀 |
最佳实践
✅ 推荐做法
- 为写操作和删除操作启用人工介入,确保高风险操作可控。
- 为只读操作禁用人工介入,以提高执行效率。
- 使用描述性的前缀消息,清晰说明待审核的操作内容。
- 在生产环境中使用持久化的检查点存储,保证中断后可恢复。
- 为不同类型的操作设置合适的决策权限(如仅允许批准 / 拒绝,不允许编辑)。
❌ 避免做法
- 不要为所有操作都启用人工介入,这会严重影响用户体验和执行效率。
- 不要忽略检查点配置,否则中断后流程将无法恢复。
- 不要不提供清晰的决策反馈信息,否则人工审核时难以理解操作意图。
- 不要在生产环境中使用内存检查点(如
InMemorySaver),因为它不具备持久化能力,重启后会丢失状态。
适用场景推荐
| 应用场景 | 人工介入的核心作用 |
|---|---|
| ✉️ 邮件发送系统 | 确保收件人地址正确无误;审核邮件内容专业合规;确认附件完整且正确,避免发送失误。 |
| 💰 财务操作 | 确保转账金额和账户准确;保证交易符合公司政策;保留完整的授权和审计记录,防控资金风险。 |
| 🗄️ 数据库管理 | 防止删除操作影响生产数据;确认更新操作的条件正确;要求操作前有完整数据备份,保障可回滚。 |
| ⚙️ 系统配置 | 评估配置变更的必要性;验证变更不会影响系统稳定性;留存完整变更记录,便于审计和排查。 |
成本与性能管理
Model call limit(模型调用限制)
ModelCallLimitMiddleware,它是 LangChain 1.0 中的一个模型调用限制中间件,核心作用是通过限制模型调用次数,来防止无限循环和过度成本,帮助开发者控制 API 调用费用、合理利用系统资源,为 AI 应用提供经济保护机制。
核心价值
- 防止无限循环:阻止失控的 Agent 进行过多 API 调用,避免程序陷入死循环。
- 成本控制:在生产环境中强制执行成本控制,防止意外的高额费用支出。
- 测试预算:可以在设定的调用预算内测试 Agent 的行为,评估其在成本约束下的表现。
- 资源管理:合理分配模型调用资源,实现并发控制,避免资源耗尽。
- 异常保护:防止因调用次数过多导致的系统异常,提升应用稳定性。
工作原理
Thread 限制(线程级限制)
thread_limit:控制一个线程内所有运行的最大调用次数。作用范围:跨所有 Agent 执行的整个生命周期,适用于长时间运行的会话。
主要目的:防止在一个会话线程内累积过多的模型调用,避免长期成本失控。
Run 限制(单次调用限制)
run_limit:限制单次调用(如agent.invoke())的最大调用次数。作用范围:每次独立执行的 Agent 任务,有独立的计数器。
主要目的:防止单次任务执行过度调用,是最常用的限制类型。
退出行为(限制触发后的处理)
exit_behavior="end":优雅终止,让 Agent 完成当前步骤后结束。exit_behavior="error":直接抛出异常,中断执行。特点:提供灵活的错误处理策略,可根据业务需求选择不同的退出方式。
自动触发(限制的执行方式)
模型调用时自动检查计数,无需开发者手动干预。
提供透明化的限制机制,实时进行计数和监控。
简单来说,这个中间件通过线程级和单次调用级的双重限制,配合可配置的退出行为,在自动触发的机制下,为 AI 应用提供了一套既安全又灵活的调用成本控制方案。
执行流程
ModelCallLimitMiddleware 的核心执行流程,整体遵循初始化→前置检查→计数更新→超限处理的四步闭环逻辑,全程自动化执行,无需手动介入。
初始化计数器(准备阶段)
核心动作:为两个维度的限制分别创建独立的计数器—— 一个对应
thread_limit(线程级),一个对应run_limit(单次调用级)。关键意义:双计数器独立运作,确保线程级的长期会话计数、与单次
agent.invoke()的短期计数互不干扰,为后续精准限制打下基础。
模型调用前检查(核心校验阶段)
核心动作:在每一次模型调用发起前,都会触发阈值校验,同时检查
thread_limit和run_limit是否已达到设定的最大值。关键意义:这是 “防超限” 的核心关口,采用前置检查而非事后统计,能从源头避免无效调用,真正实现成本控制和循环阻断。
计数器更新(过程监控阶段)
核心动作:若前置检查通过(未达阈值),允许模型调用执行,同时同步更新
thread和run两个计数器,累计本次调用次数。关键意义:实时计数保证了限制的时效性,让每一次调用都被精准记录,避免出现 “漏记导致超限” 的情况。
限制处理(超限处置阶段)
核心动作:若前置检查发现任一阈值被触发,立即终止后续调用,并根据预先配置的
exit_behavior参数,执行对应的处置策略。关键意义:将处置逻辑与配置解耦,既可以选择
end实现优雅终止(保证系统稳定),也可以选择error抛出异常(便于测试排障),适配不同业务场景需求。
代码示例
1 | from langchain.agents import create_agent |
参数说明
| 参数名 | 含义 | 配置示例 | 默认值 | 计数方式 |
|---|---|---|---|---|
thread_limit |
线程内所有运行的最大模型调用次数(可选) | thread_limit=10(线程内最多 10 次调用) |
无限制 | 跨所有 agent.invoke() 的累积计数 |
run_limit |
单次调用的最大模型调用次数(可选) | run_limit=5(单次调用最多 5 次) |
无限制 | 每次 agent.invoke() 的独立计数 |
exit_behavior |
达到限制时的行为(可选) | exit_behavior="end"(优雅终止)exit_behavior="error"(抛出异常) |
"end" |
控制达到限制后的处理方式 |
参数组合建议
仅
run_limit适用场景:单次执行预算控制,防止单次调用过度。
特点:只限制单次
agent.invoke()的调用次数,适合单次任务明确、无需长期会话的场景。
仅
thread_limit适用场景:长时间会话的总预算控制。
特点:限制整个线程内所有
agent.invoke()的累积调用次数,适合多轮对话、长生命周期的 Agent 应用。
两者结合(
run_limit+thread_limit)适用场景:需要双重保护的生产环境。
特点:既控制单次调用次数,又限制线程内总调用次数,形成 “单次防失控 + 全局控成本” 的双重保障。
exit_behavior选择"end":适合用户体验优先的场景,优雅终止,避免直接报错影响用户体验。"error":适合严格管控的场景,直接抛出异常,便于开发和测试中快速定位超限问题。
仅运行限制
1 | # 仅限制单次执行的调用次数 |
在创建 Agent 时,通过 ModelCallLimitMiddleware 中间件,将单次 agent.invoke() 的最大模型调用次数限制为 3 次,从而防止单次任务过度调用模型。
错误处理模式
1 | # 使用错误抛出模式 |
在 ModelCallLimitMiddleware 中使用 exit_behavior="error" 模式,当单次执行的模型调用次数超过 run_limit=2 时,会主动抛出异常,方便开发者捕获并进行后续处理。
最佳实践
🏭 生产环境配置
run_limit:设置为 5–10 次,既能防止无限循环,又能保证正常任务完成。exit_behavior:使用"end",优雅终止,避免直接报错影响用户体验。- 监控与调优:监控达到限制的频率,根据实际使用情况动态调整参数,确保系统稳定和成本可控。
🧪 测试环境配置
run_limit:使用较低的值,用于测试 Agent 在受限情况下的行为。exit_behavior:使用"error",抛出异常便于快速定位问题,进行严格测试。- 验证重点:验证 Agent 在限制下的决策能力,测试不同限制值对任务完成度的影响。
💰 成本控制策略
- 按模型定价:根据模型成本设置
run_limit,对高成本模型(如 GPT-4o)使用更严格的限制。 - 长期控制:结合
thread_limit进行长期会话的总成本控制,避免单会话累积过高费用。 - 定期审查:定期审查和调整限制值,根据业务变化和使用模式优化配置。
常见问题
如何确定合适的限制值?(参数调优指南)
设置
run_limit或thread_limit并非固定数值,需结合业务与成本双维度综合评估,核心参考五大因素:| 参考维度 | 配置原则 | 示例 |
| :————- | :———————————————- | :—————————————————— |
| 任务复杂度 | 简单任务设低限,复杂任务适度放宽 | 简单问答设 2-3 次 |
| 模型成本 | 模型越昂贵,限制越严格 | GPT-4o 比 GPT-3.5 限制更窄 |
| 用户体验 | 确保核心任务能在限制内完成 | 避免因阈值过低导致任务失败 |
| 预算控制 | 以成本预算倒推最大调用次数 | 按单次会话预算计算可承受的调用量 |
| 测试调优 | 实测验证,动态调整 | 通过灰度测试找到 “成本 - 体验” 平衡点 |达到限制后如何处理?(异常处置方案)
处理逻辑完全由
exit_behavior参数控制,需根据应用场景选择,并配合前端友好提示:- 优雅终止(
exit_behavior="end")- 行为:Agent 停止后续调用,直接返回当前已完成的结果。
- 适用:生产环境、用户交互场景,避免抛出错误影响体验。
- 抛出异常(
exit_behavior="error")- 行为:直接触发异常,需上层代码通过
try-except捕获处理。 - 适用:测试环境、后台任务,便于精准定位超限问题。
- 行为:直接触发异常,需上层代码通过
- 进阶建议
- 前端:友好提示用户 “任务已达处理上限”,避免用户困惑。
- 策略:结合降级策略(如切换轻量模型)提供备选方案。
- 优雅终止(
thread_limit 和 run_limit 有什么区别?(核心功能区分)
两者是不同粒度的限制机制,核心差异体现在计数范围和适用场景,具体对比如下:
| 对比项 |
run_limit|thread_limit|
| :———- | :——————————————————————————- | :—————————————————————————————- |
| 计数范围 | 单次agent.invoke()内的独立计数,每次调用后重置 | 跨多个agent.invoke()的累积计数,线程生命周期内长期有效 |
| 核心目标 | 控制单次执行的成本与风险 | 控制长期会话的总成本 |
| 适用场景 | 独立任务、一次性查询 | 多轮对话、长周期运行的 Agent 服务 |
Tool call limit(工具调用限制)
ToolCallLimitMiddleware,它是 LangChain 1.0 中专门用于工具调用次数限制的中间件,核心作用是防止工具被过度调用,保障系统稳定和成本可控。
定位:专为工具调用设计的限制中间件。
核心功能:跟踪工具调用次数,并在代理执行期间强制执行限制。
计数级别:
线程级别:跨运行持久化计数,适合长期限制。
运行级别:每次调用独立计数,适合单次任务限制。
超限处理:可选择阻止工具调用、抛出异常或立即结束执行。
核心价值
- 工具保护:防止工具被过度调用或滥用,避免服务被恶意消耗。
- 资源优化:合理分配工具使用资源,避免资源被单一任务耗尽。
- 成本控制:管理工具调用产生的费用,避免因无限循环调用导致成本飙升。
- 性能保障:避免因工具调用过多导致系统性能下降、响应变慢。
- 灵活配置:支持线程级和运行级两种限制方式,适配不同场景需求。
代码示例
1 | from langchain.agents import create_agent |
参数说明
| 参数名 | 核心定义 | 关键说明 | 配置示例 |
|---|---|---|---|
| tool_name | 要限制的特定工具名称 | 若设为 None,则限制规则适用于所有工具(默认行为) |
tool_name="search"(仅限制搜索工具)tool_name=None(限制所有工具,默认) |
| thread_limit | 每个线程(会话)允许的最大工具调用次数 | 1. 支持跨运行持久化计数; 2. 此处的 thread 实际指会话,由 configurable.thread_id 标识;3. 与 ModelCallLimitMiddleware 的 thread_limit无关联;4. None 表示无线程级别限制 |
thread_limit=20(线程级限制 20 次调用)thread_limit=None(无线程级别限制) |
| run_limit | 每次运行允许的最大工具调用次数 | 1. 每次调用独立计数,不跨运行累计; 2. None 表示无运行级别限制 |
run_limit=10(运行级别限制 10 次调用)run_limit=None(无运行级别限制) |
| exit_behavior | 超出调用限制时的处理方式 | 有三种核心行为,且存在特殊 注意事项:当存在多个并行工具调用或其他待处理工具调用时, end 行为会抛出 NotImplementedError |
exit_behavior="continue"(阻止超出的工具,执行继续,默认)exit_behavior="error"(抛出 ToolCallLimitExceededError 异常)exit_behavior="end"(立即停止,返回 ToolMessage + AI 消息) |
超出限制时立即停止
1 | # 超出限制时立即结束执行 |
抛出异常处理
1 | # 严格限制并处理异常 |
组合限制配置
1 | # 同时设置线程级和运行级限制 |
最佳实践
✅ 推荐做法
- 按风险分级限制:根据工具的风险级别(如普通查询 vs 代码执行)设置不同的调用限制,高风险工具应更严格。
- 多层保护机制:结合
thread_limit(会话级)和run_limit(单次运行级),实现双重防护,避免单次滥用或长期累积滥用。 - 精准限制关键工具:对核心或高风险工具(如
execute_code),通过tool_name单独配置限制,而不是对所有工具一刀切。 - 选择合适的超限策略:根据业务场景选择
exit_behavior:continue:适合非关键工具,阻止超限调用但不中断流程。error:适合关键工具,抛出异常以便上层捕获和处理。end:适合严格场景,立即终止执行。
- 监控与优化:持续监控工具调用的频率、模式和效率,为优化限制策略提供数据支撑。
- 定期审查策略:随着业务和工具使用模式变化,定期调整和优化限制规则,确保其有效性和合理性。
⚠️ 注意事项
- 避免过度限制:过于严格的限制可能会影响 AI 智能体的功能和响应能力,需要在安全和可用性之间找到平衡。
- 合理设置层级关系:确保
run_limit(单次运行限制)不超过thread_limit(会话总限制),否则会导致逻辑矛盾。 - 处理并行调用:当存在多个并行工具调用或待处理的工具调用时,
end行为会抛出NotImplementedError,需要提前处理这种特殊情况。 - 考虑工具依赖:某些工具调用可能依赖于其他工具的结果,限制时要避免破坏这种依赖关系,导致任务失败。
- 测试策略影响:在生产环境前,充分测试不同
exit_behavior对业务流程和用户体验的影响。 - 保护统计信息:工具使用统计数据是优化限制策略的关键,需要妥善保护这些信息,防止泄露或篡改。
常见问题
核心参数区别:
thread_limitvsrun_limit这是关于两个核心限制参数的定义与适用场景的澄清:
thread_limit(会话级限制):具备跨运行持久化的特性,数据会在整个会话生命周期内累计,适用于管理长期会话的总调用量。run_limit(任务级限制):每次代理调用的计数都是独立的,不会跨任务累计,适用于控制单次任务的调用上限。最佳实践:两者可以同时设置,形成 “单次防爆发、长期防滥用” 的多层保护机制。
功能限制:
exit_behavior="end"的使用边界该问题明确了 “立即停止” 策略的技术局限性:
异常场景:当系统中存在多个并行工具调用,或有其他工具调用处于 “待处理” 状态时,使用
end会直接抛出NotImplementedError。解决方案:在上述复杂的并发场景下,官方建议改用
continue(阻止超限工具,流程继续)或error(抛出异常由上层捕获),以保证系统稳定性。
多工具配置:如何实现差异化限制
该问题解决了 “不同工具不同策略” 的配置难题:
核心方法:创建多个中间件实例。
具体操作:为每一类工具单独创建一个
ToolCallLimitMiddleware对象,通过tool_name参数指定目标工具,最后将所有实例放入middleware列表中,即可实现对不同工具的精细化管控。
阈值选择:如何确定合理的限制数值
该问题提供了设置具体数值的决策依据:
决策维度:需综合评估工具的成本、重要性和使用频率。
分级策略:
- 普通工具:成本低、风险小,可设置较高的限制值,不影响智能体的灵活性。
- 昂贵 / 危险工具(如付费 API、代码执行工具):必须设置更严格的限制值,以控制成本和安全风险。
可靠性与容错
Model fallback(模型回退)
ModelFallbackMiddleware,它是 LangChain 1.0 中用于实现模型故障转移的中间件,核心作用是提升 AI 应用的可靠性。
核心定义
- 作用:当主模型调用失败时,自动按顺序尝试备用模型,直到成功或所有模型都耗尽。
- 使用方式:主模型在
create_agent中指定,回退模型通过中间件参数传递。
核心价值
| 核心价值 | 说明 |
|---|---|
| 自动故障转移 | 主模型失败时自动切换到备用模型,无需人工干预 |
| 顺序回退 | 按你指定的顺序依次尝试多个备用模型 |
| 无缝集成 | 与 create_agent 完美配合,无需复杂改造 |
| 简化配置 | 仅需指定备用模型列表,配置成本低 |
| 高可靠性 | 确保模型服务连续性,避免单点故障 |
简单来说,这个中间件就像一个 “保险机制”,让你的 AI 应用在主模型出问题时,能自动切换到备用模型,保证服务不中断。
执行流程
当主模型调用失败时,ModelFallbackMiddleware 会自动触发,无需人工干预。它会按你预先指定的顺序,依次尝试备用模型,直到找到可用的模型,或者所有模型都尝试完毕。
🔑 关键执行步骤
| 步骤 | 说明 |
|---|---|
| 自动触发 | 当主模型调用失败(如超时、报错、限流)时,回退机制会自动激活,无需手动操作。 |
| 顺序尝试 | 按照你在中间件参数中指定的顺序,依次尝试备用模型列表中的每一个。 |
| 透明切换 | 整个过程对调用者(如你的应用代码)是完全透明的,不需要修改业务逻辑,调用方感知不到底层模型的切换。 |
简单来说,这个流程就像一个 “自动备胎” 系统:主模型出问题时,它会自动按顺序试下一个,直到找到能正常工作的,而且你完全不用改代码。
代码示例
1 | # 使用模型实例进行更精细的控制 |
这段代码展示了如何使用 ModelFallbackMiddleware 实现模型实例级别的故障转移:
- 首先导入并创建了三个不同的模型实例(GPT-4o、Claude 3 Sonnet、GPT-3.5-turbo),每个都有独立的参数配置。
- 然后将这些模型实例按顺序传入
ModelFallbackMiddleware,作为备用模型列表。 - 最后在
create_agent中指定主模型,并将回退中间件传入,实现当主模型失败时,自动按顺序尝试备用模型实例。
最佳实践
✅ 推荐做法
- 能力递减序列:按模型能力从高到低排列备用模型,优先保证效果。
- 控制数量:保持 2-4 个备用模型,避免过多导致延迟和成本上升。
- 混合厂商:混合使用不同提供商的模型(如 OpenAI、Anthropic),避免单一厂商故障导致整体不可用。
- 环境测试:在开发环境中充分测试回退链,确保在各种失败场景下都能正常工作。
- 监控指标:监控回退触发频率和成功率,及时发现潜在问题。
- 记录事件:记录回退事件,用于事后分析和优化。
⚠️ 注意事项
- 避免过长回退链:回退链过长会显著增加响应延迟,影响用户体验。
- 关注能力与成本:不同模型的能力和成本差异很大,需要在效果和成本之间做平衡。
- 处理格式差异:不同模型的输出格式可能不同,需要统一处理或兼容。
- 评估可用性:备用模型本身也需要具备高可用性和稳定性,否则回退意义不大。
- 防止回退风暴:大量并发回退可能导致系统性能下降,需要限流或熔断机制。
- 保护凭证:妥善保管 API 密钥和访问凭证,避免泄露带来的安全风险。
常见问题
| 问题 | 解答 |
|---|---|
| 回退机制会影响响应时间吗? | 只有在主模型失败时才触发回退,成功情况下无额外开销。失败时会增加尝试备用模型的时间,但这是为了确保服务可用性的必要代价。 |
| 如何选择合适的备用模型? | 建议按能力递减顺序排列,混合不同提供商的模型以增加可靠性。保持 2-4 个备用模型,避免过多导致延迟过长。 |
| 如何处理不同模型的响应差异? | ModelFallbackMiddleware 会尽量保持响应格式一致,但不同模型可能有细微差异。建议在应用层处理这些差异,或选择能力相近的模型作为备用。 |
| 可以同时使用多个中间件吗? | 可以,ModelFallbackMiddleware 可以与其他中间件(如 ToolCallLimitMiddleware、HumanInTheLoopMiddleware 等)一起使用,形成完整的中间件链。 |
Tool retry(工具重试)
ToolRetryMiddleware 是 LangChain 框架中的一个工具重试中间件,它的核心作用是:
- 自动重试失败的工具调用
- 支持可配置的退避策略
- 对特定异常进行重试
- 使用指数退避算法
- 提供灵活的失败处理机制
- 最终确保工具调用的可靠性和稳定性
核心价值
| 核心价值 | 详细说明 |
|---|---|
| 自动重试 | 智能识别可重试的错误(如网络超时、服务暂时不可用等),并自动发起重试,无需手动编写重试逻辑。 |
| 指数退避 | 每次重试的等待时间按指数增长(例如 1s → 2s → 4s → 8s),避免短时间内大量重试对服务造成过大压力,同时提高成功概率。 |
| 错误分类 | 能够区分可重试错误(如临时网络波动)和不可重试错误(如参数错误、权限不足),避免无效重试。 |
| 灵活配置 | 支持多种自定义参数,如最大重试次数、初始退避时间、最大退避时间等,以适应不同的业务场景和服务特性。 |
| 针对性处理 | 可以针对特定工具或特定错误类型进行精细化配置,例如对某些关键工具设置更严格的重试策略。 |
工作原理
ToolRetryMiddleware 的重试机制,它采用多层次重试策略,主要分为四个核心模块:
自动重试
当工具调用失败时,中间件会自动触发重试,主要针对以下场景:
网络超时重试:应对网络波动或服务响应慢的情况。
服务暂时不可用:如服务重启、过载等临时故障。
基于配置的错误类型:可指定哪些 HTTP 状态码或异常类型需要重试。
自定义条件的错误:支持通过自定义逻辑判断是否需要重试。
指数退避
为了避免频繁重试对服务造成压力,采用指数退避算法来控制重试间隔:
计算公式:每次重试等待时间 =
initial_delay * (backoff_factor ** retry_number)常量延迟:当
backoff_factor = 0.0时,每次等待时间相同。最大延迟:通过
max_delay参数限制最长等待时间,防止无限等待。抖动机制:
jitter参数会在计算出的等待时间上添加 ±25% 的随机变化,有效避免大量请求同时重试导致的 “雪崩效应”。
条件重试
提供了灵活的条件配置,让重试策略更具针对性:
异常类型元组配置:指定哪些异常类型需要重试,例如
(requests.exceptions.Timeout, ConnectionError)。自定义判断函数:支持传入一个函数,根据错误信息或返回结果动态决定是否重试。
工具范围限制:通过
tools参数,指定该重试策略只作用于特定的工具,避免全局影响。灵活的重试条件设置:可以组合多种条件,实现精细化控制。
定制化错误处理
当重试次数耗尽或遇到不可重试错误时,提供多种处理方式:
返回错误信息:将错误信息包装后返回,供上层逻辑处理。
直接抛出异常:将原始异常抛出,中断执行。
自定义错误格式化:支持自定义错误信息的格式和内容。
灵活的失败策略:可以根据业务需求,在失败时执行回调、记录日志或触发告警。
重试流程
错误捕获
作用:在工具调用过程中,拦截并捕获所有抛出的异常(如网络超时、服务不可用、参数错误等)。
目的:为后续的重试决策提供依据。
错误分类
作用:根据预设的规则(如异常类型、HTTP 状态码、自定义判断函数),判断当前错误是否属于可重试类型。
目的:区分临时故障(如网络波动)和永久性错误(如权限不足),避免无效重试。
重试决策
作用:结合错误分类结果、已重试次数、最大重试次数等配置,决定是否进行下一次重试。
目的:确保重试策略既有效又可控,防止无限循环。
延迟等待
作用:如果决定重试,根据指数退避算法(
initial_delay * (backoff_factor ** retry_number))计算等待时间,并可加入随机抖动(jitter)。目的:避免短时间内大量请求同时重试,减轻服务压力,防止 “雪崩效应”。
重试执行
作用:等待结束后,重新发起工具调用。
目的:尝试再次完成任务,提高整体成功率。
错误处理
作用:如果重试次数耗尽或遇到不可重试错误,根据
on_failure配置进行最终处理。常见处理方式:
- 返回结构化的错误信息
- 直接抛出原始异常
- 执行自定义的失败回调函数
目的:让上层业务逻辑能够优雅地处理失败情况。
这个流程确保了工具调用的可靠性和稳定性,同时通过精细化的策略配置,适应不同的业务场景。
代码示例
1 | # 基础工具重试中间件配置 |
特定异常重试示例
1 | # 仅对特定异常进行重试 |
自定义异常过滤示例
1 | # 使用自定义函数判断是否重试 |
特定工具重试示例
1 | # 仅对特定工具应用重试逻辑 |
常量退避和自定义失败处理示例
1 | # 常量退避(无指数增长) |
参数说明
| 参数名 | 类型 | 默认值 | 含义 | 示例与说明 |
|---|---|---|---|---|
| max_retries | number | 2 | 最大重试次数(初始调用后),即总共尝试次数 = 1 + max_retries |
max_retries=2 → 最多重试 2 次,总共 3 次尝试 |
| tools | list | None | 应用重试逻辑的工具列表(可选),为 None 时作用于所有工具 |
tools=["search_database"] → 只对 search_database 工具应用重试 |
| retry_on | tuple / callable | (Exception,) | 触发重试的异常类型或判断函数,为 None 时重试所有可重试异常 |
retry_on=(ConnectionError, TimeoutError) → 仅在这两种异常时重试 |
| on_failure | string/callable | “return_message” | 所有重试均失败时的处理行为 | on_failure="return_message" → 返回结构化的错误信息 |
| backoff_factor | number | 2.0 | 指数退避的乘数,决定等待时间的增长速度 | backoff_factor=2.0 → 每次重试等待时间翻倍 |
| initial_delay | number | 1.0 | 第一次重试前的初始延迟(秒) | initial_delay=1.0 → 第一次重试前等待 1 秒 |
| max_delay | number | 60 | 重试间隔的最大延迟(秒),防止等待时间无限增长 | max_delay=60.0 → 任何重试间隔都不会超过 60 秒 |
| jitter | bool | true | 是否添加 ±25% 的随机抖动,避免大量请求同时重试导致 “雪崩效应” | jitter=True → 启用随机抖动,让重试时间更分散 |
最佳实践
✅ 推荐做法
- 使用
retry_on参数,根据错误类型设置针对性重试策略,避免无效重试。 - 合理配置
max_retries,避免过度重试导致资源浪费。 - 使用
tools参数,限制重试范围到真正需要的工具,减少不必要的开销。 - 启用
jitter参数,避免大量请求同时重试导致的 “雪崩效应”。 - 根据业务场景选择合适的
on_failure行为,如返回友好提示或抛出异常。 - 设置合理的
initial_delay和max_delay,平衡重试成功率和响应时间。
⚠️ 注意事项
- 避免过度重试,
max_retries建议不超过 5 次,防止资源耗尽。 - 注意重试对用户体验和响应时间的影响,避免让用户等待过久。
- 启用
jitter参数,防止重试风暴,分散请求压力。 - 使用
retry_on参数,避免对所有错误都进行重试,只针对可恢复的异常。 - 根据业务场景选择合适的
on_failure行为,确保失败时的处理符合预期。 - 确保延迟参数(
initial_delay、max_delay)为非负值,避免逻辑错误。
🎯 适用场景
| 场景 | 说明 |
|---|---|
| 网络不稳定 | 网络连接不稳定环境下的 API 调用,可设置特定异常重试,提高成功率。 |
| 分布式系统 | 分布式系统中的暂时性服务故障,使用指数退避策略,避免对服务造成过大压力。 |
| 数据库操作 | 数据库操作和超时处理,设置合理的延迟,防止数据库被频繁请求压垮。 |
| 外部 API | 依赖外部 API 服务的应用,可自定义错误处理,返回更友好的用户提示。 |
| 高可用性 | 要求高可用性的系统,通过配置 max_retries 和 on_failure,保证系统稳定运行。 |
| 特定工具 | 需要针对特定工具进行重试的场景,使用 tools 参数精准控制重试范围。 |
常见问题
| 问题 | 解答 |
|---|---|
| 如何针对特定异常进行重试? | 使用 retry_on 参数设置异常类型元组或自定义判断函数,例如 retry_on=(Timeout, ConnectionError),只对这些异常进行重试。 |
| 如何自定义错误处理? | 通过 on_failure 参数配置自定义错误处理函数,该函数接收异常对象并返回格式化的错误信息。 |
| 如何配置固定延迟而非指数退避? | 将 backoff_factor 设置为 0.0,这样每次重试都会使用 initial_delay 指定的固定延迟时间。 |
| 如何限制只对特定工具进行重试? | 使用 tools 参数指定工具名称列表或 BaseTool 实例列表,例如 tools=["search_tool", database_tool]。 |
Model retry(模型重试)
模型调用失败时,自动以指数退避的方式重试,增强模型调用的可靠性。
功能
- 处理模型API调用中的瞬态故障。瞬态故障是指那些短暂出现且可能会自行恢复的错误,比如网络抖动、服务器短暂过载等情况导致的模型调用失败。通过模型重试机制,可以在这些瞬态故障发生后自动尝试重新调用模型,从而提高模型调用的成功率,避免因为短暂的故障而导致整个应用或任务的失败。
- 提高依赖网络的模型请求的可靠性。许多模型调用是通过网络进行的,网络的不稳定因素可能会导致模型请求失败。模型重试机制可以在网络请求失败后自动进行重试,从而减少因网络问题导致的模型请求失败次数,增强整个系统的稳定性和可靠性,确保模型请求能够在网络条件允许的情况下成功完成。
- 构建能够优雅地处理临时模型错误的弹性代理(或智能体)。在一些复杂的应用场景中,可能会涉及到多个模型调用或者连续的模型交互过程。模型重试机制可以帮助这些代理在遇到临时的模型错误时,不会直接崩溃或者停止工作,而是通过自动重试来尝试解决问题,从而使代理能够更加稳定、可靠地运行,提高系统的整体弹性和容错能力。
代码示例:
1 | from langchain.agents import create_agent |
配置选项
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| max_retries | number | 2 | 最大重试次数 |
| retry_on | tuple / callable | (Exception,) | 触发重试的异常 |
| on_failure | string/callable | “return_message” | 重试用尽时的行为 |
| backoff_factor | number | 2.0 | 指数退避系数 |
| initial_delay | number | 1.0 | 初始延迟 |
| max_delay | number | 60 | 最大延迟 |
| jitter | bool | true | 是否添加抖动 |
安全与隐私保护
PII detection(个人身份信息检测)
PIIMiddleware 是 LangChain 1.0 中专门用于个人隐私信息(PII)检测与保护的中间件。它可以智能识别文本中的敏感信息(如邮箱、信用卡号、IP 地址、MAC 地址、URL 等),并提供多种处理策略,同时支持自定义 PII 类型和检测器,确保在数据处理过程中充分保护用户隐私。
核心价值
| 核心价值 | 说明 |
|---|---|
| 隐私保护 | 自动识别并保护文本中的敏感信息,防止隐私泄露 |
| 合规支持 | 符合 GDPR、CCPA 等国际隐私法规要求,降低合规风险 |
| 灵活配置 | 支持自定义 PII 模式和检测器,适配不同业务场景 |
| 智能处理 | 提供多种处理策略:阻止(block)、脱敏(redact)、掩码(mask)、哈希(hash) |
| 精细控制 | 可分别控制输入、输出和工具结果的 PII 处理逻辑 |
简单来说,PIIMiddleware 就像一个 “隐私防火墙”,在你的 AI 应用与大模型交互的全链路中,自动识别并处理敏感信息,让你的应用既安全又合规。
代码示例
1 | from langchain.agents import create_agent |
检查AI输出和工具结果示例代码
1 | # 同时检查输入、输出和工具结果 |
参数说明
| 参数名 | 类型 | 默认值 | 说明 | ||
|---|---|---|---|---|---|
pii_type |
`Literal[“email”, “credit_card”, “ip”, “mac_address”, “url”] | str` | - | 要检测的 PII 类型,内置支持邮箱、信用卡号、IP 地址、MAC 地址、URL,也支持自定义字符串类型 | |
strategy |
Literal["block", "redact", "mask", "hash"] |
"redact" |
检测到 PII 时的处理策略:- block:抛出异常阻止流程- redact:替换为 [REDACTED_TYPE] 占位符- mask:部分掩码(如 ****-****-****-1234)- hash:替换为确定性哈希(如 <email_hash:a1b2c3d4>) |
||
detector |
`Callable[[str], list[PIIMatch]] | str | None` | None |
自定义检测器:- Callable:接收字符串,返回 PIIMatch 列表- str:正则表达式模式- None:使用 pii_type 对应的内置检测器 |
apply_to_input |
bool |
True |
是否在模型调用前检查用户输入消息 | ||
apply_to_output |
bool |
False |
是否在模型调用后检查 AI 输出消息 | ||
apply_to_tool_results |
bool |
False |
是否在工具执行后检查工具返回结果 |
还可以自定义PII类型,具体可想看官方文档:https://docs.langchain.com/oss/python/langchain/middleware/built-in#pii-detection
pii_type内置 PII 类型说明
| 内置类型 | 说明 |
|---|---|
"email" |
邮箱地址 |
"credit_card" |
信用卡号(带 Luhn 算法验证) |
"ip" |
IP 地址(带标准库验证) |
"mac_address" |
MAC 地址 |
"url" |
URLs(支持 http/https 和裸 URL) |
strategy策略选择指南
| 策略 | 保留身份? | 最佳用途 |
|---|---|---|
block |
N/A | 完全避免 PII,直接阻止包含敏感信息的请求 |
redact |
否 | 一般合规性场景、日志清理,用占位符替换敏感信息 |
mask |
否 | 需要人类可读性的场景(如客服 UI),对敏感信息进行部分掩码 |
hash |
是(匿名化) | 数据分析、调试场景,用哈希值替换以保留关联但不泄露原始信息 |
检测机制
| 检测方式 | 核心能力 |
|---|---|
| 内置检测器 | - 邮箱地址模式匹配 - 信用卡号验证(Luhn 算法) - IP 地址格式验证 - MAC 地址格式验证 - URL 模式识别 |
| 自定义检测 | - 正则表达式模式- 自定义检测函数- PIIMatch 对象返回- 置信度评分 |
简单来说,PIIMiddleware 提供了两种检测路径:
- 内置检测器:开箱即用,覆盖常见 PII 类型,且部分类型(如信用卡、IP)带有格式验证,保证检测准确性。
- 自定义检测:支持通过正则或自定义函数扩展检测能力,还能返回带置信度的 PIIMatch 对象,满足更复杂的业务需求。
处理流程
PIIMiddleware 处理个人隐私信息(PII)的四个核心步骤:
| 步骤 | 名称 | 核心动作 |
|---|---|---|
| 1 | 文本扫描 | 根据 apply_to_input、apply_to_output、apply_to_tool_results 的配置,对用户输入、AI 输出或工具结果中的文本进行扫描。 |
| 2 | PII 检测 | 使用内置检测器或自定义检测器,识别文本中符合 PII 模式的内容(如邮箱、信用卡号等)。 |
| 3 | 策略执行 | 根据配置的 strategy(block/redact/mask/hash),对检测到的 PII 执行相应的处理操作。 |
| 4 | 结果返回 | 返回处理后的文本(如脱敏、掩码后的内容),或在 block 策略下直接抛出异常,终止流程。 |
简单来说,这个流程就是:先扫描 → 再识别 → 再处理 → 最后返回结果,全程自动,对应用层透明,确保了隐私保护的全链路覆盖。
最佳实践
✅ 推荐做法
- 按需选择 PII 类型:根据业务场景,只检测必要的敏感信息类型,避免过度扫描。
- 策略匹配 PII 类型:对不同敏感程度的信息(如信用卡 vs 邮箱)采用不同的处理策略。
- 精细控制扫描范围:合理设置
apply_to_input/output/tool_results,只在必要的环节进行检测。 - 自定义检测器:用正则或自定义函数处理业务特有的 PII 模式(如工号、内部 ID)。
- 敏感操作使用 block:对高风险操作直接阻断,防止敏感信息泄露。
- 平衡隐私与可用性:在保护隐私的同时,确保处理后的数据仍能满足业务需求。
⚠️ 注意事项
- 避免过度脱敏:过度处理会导致数据失去价值,影响后续分析或业务流程。
- 关注自定义检测器性能:复杂的正则或函数可能增加延迟,需进行性能测试。
- 考虑多语言文本:不同语言的 PII 模式(如姓名、地址)可能不同,需针对性处理。
- 处理 block 异常:使用
block策略时,必须捕获并优雅处理抛出的异常。 - 确保正则准确性:错误的正则表达式会导致漏检或误检,需充分测试。
- 测试策略影响:在上线前,充分测试不同策略对业务流程和用户体验的影响。
🎯 适用场景
| 场景 | 应用说明 |
|---|---|
| 客户服务 | 保护聊天记录、邮件、工单系统中的用户隐私信息(如手机号、邮箱)。 |
| 数据分析 | 在用户数据、调研数据、反馈分析中,对敏感信息进行脱敏或哈希处理。 |
| 内容审核 | 对用户生成内容(UGC)、评论、帖子进行 PII 检测,防止隐私泄露。 |
常见问题
| 问题 | 解答 |
|---|---|
| 如何处理自定义 PII 类型? | 使用自定义检测器参数,传入正则表达式字符串或检测函数。示例:PIIMiddleware("api_key", detector=r"sk-[a-zA-Z0-9]{32}", strategy="block") |
| 不同策略如何选择? | - block:用于完全阻止敏感内容- redact:用于一般合规性脱敏- mask:用于保持部分可读性(如客服 UI)- hash:用于需要匿名化但保持一致性的场景(如分析、调试) |
| 如何同时检测多种 PII 类型? | 创建多个 PIIMiddleware 实例,每个实例处理不同的 PII 类型和策略,然后一起添加到 middleware 列表中。 |
apply_to_input/output/tool_results 参数如何设置? |
- apply_to_input=True:检查用户输入- apply_to_output=True:检查 AI 输出- apply_to_tool_results=True:检查工具结果根据业务需求选择需要检查的环节。 |
任务与工具管理
To-do list(待办事项列表)
TodoListMiddleware 是为 AI 智能体添加的任务规划超能力:当处理复杂任务时,它会自动创建任务列表、按步骤执行,并在完成后展示完整执行历史,让 AI 的工作过程更透明、更有条理。
用与不用的核心区别
| 场景 | 没有 TodoListMiddleware ❌ | 有了 TodoListMiddleware ✅ |
|---|---|---|
| 用户指令 | 用户:“帮我搭建一个电商网站” | 用户:“帮我搭建一个电商网站” |
| AI 响应 | AI 默默执行,用户完全不知道它在做什么 | AI:“我来帮您,让我先制定计划…”,然后按计划执行 |
| 任务完成后 | 不知道 AI 具体做了哪些步骤 | 展示完整的执行步骤和结果,过程透明 |
| 出错时 | 不知道执行到哪一步,难以排查问题 | 可以清晰定位到出错的任务节点,便于调试 |
简单来说,TodoListMiddleware 让 AI 从 “黑盒执行” 变成了 “透明规划 + 分步执行”,大大提升了复杂任务的可控性和可解释性。
如何工作
TodoListMiddleware 的四个核心工作步骤:
| 步骤 | 核心动作 | 详细说明 |
|---|---|---|
| 1 | 给智能体添加 “写清单” 工具 | 自动为 AI 添加一个 write_todos 工具,相当于给 AI 配备了一个 “记事本”,让它可以记录和管理任务。 |
| 2 | AI 学会 “做计划” | 通过系统提示引导 AI:“复杂任务要先写清单,完成一项勾一项”,让 AI 养成先规划后执行的习惯。 |
| 3 | 任务状态跟踪 | AI 每完成一个子任务,就会更新任务清单,并在最终结果中展示完整的执行历史,让过程可追溯。 |
| 4 | 结果一目了然 | 最终返回完整的任务清单,所有步骤和状态都清晰展示,让用户和开发者都能清楚看到 AI 的执行路径。 |
代码示例
1 | # 只需要这一行,AI就有了任务清单功能 |
参数说明
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
system_prompt |
str | 内置智能提示词 | 用于自定义提示词,指导 AI 如何使用任务清单功能。 默认值已足够智能,通常无需修改。 |
tool_description |
str | 内置清晰描述 | 用于自定义 write_todos 工具的描述,帮助 AI 理解该工具的作用。默认描述清晰,通常无需修改。 |
最佳实践
✅ 推荐使用场景
- 任务需要多步骤完成(如搭建网站、撰写论文、重构代码)
- 任务完成后,用户需要了解具体执行步骤
- 任务可能出错,需要定位到具体执行环节
- 需要展示 AI 的专业性和条理性
❌ 不需要使用场景
- 简单的一次性问答(如 “今天天气如何”)
- 用户不关心执行过程,只关心最终结果
- 任务非常简单,没有明确步骤
⚠️ 实际测试结果
| 功能 | 支持情况 | 说明 |
|---|---|---|
| 任务规划功能 | ✅ 支持 | AI 会自动创建任务清单并按步骤执行 |
| 状态跟踪 | ✅ 支持 | 任务完成后展示完整的执行历史 |
| 实时更新 | ❌ 不支持 | 不支持真正的流式实时进度更新 |
| 调用方式 | 🔄 支持 | 支持同步和异步调用,效果相同 |
常见问题
| 问题 | 解答 |
|---|---|
| 这个中间件会增加 AI 的响应时间吗? | 基本不会。AI 本来就要一步步思考,只是现在把这些步骤显式地记录和展示。实际上,写清单反而可能让 AI 执行更有条理。 |
| 我应该使用同步调用还是异步调用? | 对于 TodoListMiddleware,同步和异步调用的效果完全相同,都会返回任务完成后的 todos 数组。- agent.invoke():同步调用,适合简单的脚本- await agent.ainvoke():异步调用,适合需要并发处理的场景 |
TodoListMiddleware支持实时进度更新吗? |
目前不支持真正的实时流式更新。它主要提供任务规划、执行完成后的状态跟踪和历史记录查询功能。如果需要实时监控,可以考虑使用 LangGraph 的流式事件或其他专门的流式处理方案。 |
LLM tool selector(LLM工具选择器)
LLMToolSelectorMiddleware,它是 LangChain 中专门为智能工具选择设计的中间件。
LLMToolSelectorMiddleware 是一个用于智能工具选择的中间件,它的工作流程是:
- 使用大语言模型(LLM)智能地筛选出与当前查询最相关的工具。
- 再将筛选后的工具列表和查询交给主模型进行处理。
它特别适合以下场景:
- 代理(Agent)拥有大量工具(10+),但大部分工具对每个查询都不相关。
- 需要通过过滤不相关工具来减少令牌(Token)使用,从而降低 API 成本。
- 希望提高模型的专注度和准确性,避免因工具过多导致的错误选择。
它通过结构化输出的方式,向 LLM 询问哪些工具最适合当前查询。
核心价值
| 核心价值 | 具体作用 |
|---|---|
| 智能过滤 | 从大量工具中,精准筛选出最相关的一小部分。 |
| 减少令牌使用 | 通过过滤掉不相关的工具,降低 API 调用时的令牌消耗,从而节省成本。 |
| 提高模型专注度 | 让模型只关注最相关的工具,避免信息过载。 |
| 提升准确性 | 减少因工具列表过长、选择过多而导致的错误决策。 |
| 结构化输出 | 使用结构化的输出格式来确定工具的相关性,结果更可靠。 |
| 灵活配置 | 支持自定义选择模型和相关参数,以适应不同的业务需求。 |
代码示例
1 | # 基础LLM工具选择中间件配置 |
成本优化工具选择
1 | # 成本优化的工具选择 |
智能工具选择
1 | # 智能工具选择 |
多工具场景优化
1 | # 多工具场景优化 |
工具过滤和排除
1 | # 工具过滤和排除 |
选择流程
查询接收
接收用户的查询请求
同时获取当前可用的全部工具列表
这是整个流程的起点,为后续选择提供基础信息
选择模型调用
使用专门配置的轻量级 LLM(如
gpt-4o-mini)来执行工具选择任务这个模型的作用是分析用户查询,判断哪些工具最相关,而不是直接回答用户问题
这样可以避免主模型被大量不相关工具干扰,同时降低成本
结构化输出
工具选择模型会生成一个结构化的输出(如 JSON 格式)
输出内容明确列出与当前查询最相关的工具
结构化输出确保了结果的清晰和可靠,便于后续步骤自动处理
工具过滤
根据上一步的结构化输出,从原始工具列表中过滤掉不相关的工具
只保留被选择模型判定为相关的工具
这一步可以显著减少传递给主模型的工具数量,从而降低令牌消耗和 API 成本
主模型调用
将过滤后的精简工具列表和用户查询一起传递给主模型(如
gpt-4o)主模型现在只需要在少量相关工具中进行选择和调用,专注度和准确性都得到提升
结果返回
主模型完成工具调用和任务处理后,返回最终结果
这个结果是基于优化后的工具选择流程生成的,效率和准确性都更高
这个流程的核心价值在于:通过一个轻量级的专用模型先做 “智能过滤”,再让主模型在小范围的相关工具中高效工作,从而实现成本控制和性能提升的双重目标。
参数说明
| 参数名 | 类型 | 默认值 | 示例 | 说明 |
|---|---|---|---|---|
| model | string/BaseModel | 主模型 | model=”gpt-4o-mini” | 用于工具选择的模型,可以是字符串或 BaseChatModel 实例,一般使用成本较低的轻量模型 |
| system_prompt | string | 内置 | system_prompt=”选择最相关的工具…” | 给工具选择模型的系统提示(可选),可自定义选择策略、排除规则等 |
| max_tools | number | 无限 | max_tools=3(最多选择 3 个工具) |
限制工具选择的最大数量,用于控制成本和提升效率 |
| always_include | list[str] | None | always_include=["search"](始终包含搜索工具) |
始终包含在工具列表中的工具名称列表,确保基础能力不丢失 |
最佳实践
✅ 推荐做法
- 轻量模型选择:为工具选择使用轻量级模型(如
gpt-4o-mini),在保证选择准确性的同时控制成本。 - 控制工具数量:合理设置
max_tools参数,减少令牌消耗和 API 成本。 - 自定义选择逻辑:通过
system_prompt明确指导选择策略,如排除特定工具、优先选择成本效益高的工具。 - 确保关键工具可用:配置
always_include,保证核心工具(如搜索)始终在候选列表中。 - 适用场景匹配:在工具数量较多(10+)的场景下使用选择器,避免在工具很少时造成不必要开销。
- 持续评估优化:定期评估工具选择的结果质量,根据实际效果调整配置。
⚠️ 注意事项
- 避免滥用:在工具数量很少时使用选择器会增加不必要的开销,反而降低效率。
- 模型兼容性:注意选择模型和主模型的兼容性,确保结构化输出格式一致。
- 监控提示影响:监控
system_prompt对选择结果的影响,避免提示词偏差导致选择错误。 - 平衡准确性与延迟:在选择准确性和额外延迟之间找到平衡点,避免因选择过程过长影响用户体验。
- 回退机制:处理选择失败时的回退机制,例如在选择器失效时自动使用全部工具。
- 清晰的工具描述:保持工具描述的清晰和准确,这是选择器做出正确判断的基础。
🎯 适用场景
| 场景 | 说明 |
|---|---|
| 多工具系统 | 拥有大量工具(10+)的智能体系统,需要过滤不相关工具以提升效率。 |
| 成本敏感 | 需要严格控制 API 调用成本的应用,通过减少工具数量降低令牌消耗。 |
| 性能优化 | 追求最佳响应时间和准确性的应用,通过过滤无关信息提升模型专注度。 |
常见问题
| 问题 | 解答 |
|---|---|
| 如何选择合适的工具选择模型? | 推荐使用轻量级模型(如 gpt-4o-mini),平衡速度和成本;对于复杂场景,可选择更强大的模型。 |
max_tools 参数如何设置? |
根据主模型处理能力和工具复杂度调整,建议从 3-5 开始测试,观察准确性和 token 使用情况。 |
system_prompt 有什么作用? |
指导选择模型如何评估和选择工具,可包含成本考虑、优先级规则等,提高选择质量。 |
always_include 工具会影响 max_tools限制吗? |
不会,always_include 工具不计入 max_tools 限制,确保关键工具始终可用。 |
LLM tool emulator(LLM工具模拟器)
LLMToolEmulator 是 LangChain 1.0 中的一个工具模拟中间件。它的核心作用是:允许使用语言模型来模拟指定工具的行为,而不是真正去执行这些工具。
它的典型应用场景包括:
- 真实工具不可用
- 需要进行安全测试
- 需要控制 API 调用成本
同时,它支持选择性模拟特定工具,可以通过工具名称或工具实例来精确指定需要模拟的对象。
核心价值
| 核心价值 | 具体说明 |
|---|---|
| 安全测试 | 在沙箱环境中安全地测试工具调用,避免真实环境中的风险。 |
| 开发调试 | 无需真实工具即可进行开发和调试,提升开发效率。 |
| 成本控制 | 避免测试过程中产生的 API 调用费用,降低开发成本。 |
| 快速原型 | 快速验证工具集成方案,加速产品迭代。 |
| 行为仿真 | 可以模拟各种工具行为和边界情况,让测试更全面。 |
| 离线开发 | 支持在没有网络的离线环境下进行开发工作。 |
工作原理
- LLM 驱动的工具模拟原理
LLMToolEmulator 的核心是用语言模型(默认使用 Claude Sonnet)来 “扮演” 工具,而不是真的去调用它。其核心原理包括:
- 选择性模拟:可以精确控制只模拟特定的工具,通过工具名称或实例来指定,避免不必要的模拟。
- LLM 驱动生成:利用先进的语言模型深度理解工具的功能和预期行为,生成与真实工具响应格式完全一致的高质量模拟输出。
- 参数感知:分析工具调用的参数,确保模拟的响应与输入参数相关且合理,让模拟结果更可信。
- 灵活配置:支持高度自定义,包括选择要模拟的工具集,以及更换或自定义用于生成模拟的语言模型。
- 工作流程
当代理决定调用工具时,LLMToolEmulator 会拦截请求并按以下 6 个步骤执行:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 工具匹配 | 检查当前请求的工具是否在指定的模拟工具列表中(如果 tools 参数不是 None)。 |
| 2 | 模拟触发 | 如果工具需要被模拟,LLMToolEmulator 会阻止实际工具的执行,转而进行模拟。 |
| 3 | 上下文准备 | 收集工具信息、调用参数和请求上下文,构建一个详细的提示词,供 LLM 理解。 |
| 4 | LLM 调用 | 使用配置的语言模型(默认或自定义),根据构建好的提示生成模拟响应。 |
| 5 | 响应格式化 | 将 LLM 的原始输出转换为与原工具响应格式完全一致的结构,确保代理能无缝处理。 |
| 6 | 结果返回 | 将格式化后的模拟响应返回给代理,使其能够继续后续的工作流程。 |
代码示例
1 | # 模拟所有工具(默认行为) |
通过名称模拟特定工具
1 | # 只模拟特定的工具(通过名称) |
使用自定义模型进行模拟
1 | # 使用自定义模型进行工具模拟 |
通过工具实例模拟特定工具
1 | # 通过工具实例指定要模拟的工具 |
参数说明
tools参数用于指定需要模拟的工具集合。
| 配置方式 | 说明 | 示例 |
| :——————- | :———————————- | :—————————————————————- |
| 默认值 |None,表示模拟所有工具 |tools=None|
| 不模拟任何工具 | 传入空列表[]|tools=[]|
| 通过名称模拟 | 传入工具名称字符串列表 |tools=["get_weather", "get_user_location"]|
| 通过实例模拟 | 传入BaseTool实例列表 |tools=[get_weather_tool, calculator_tool]|model参数用于指定生成模拟响应的语言模型。
| 配置方式 | 说明 | 示例 |
| :————- | :————————————————————— | :—————————————————————— |
| 默认值 | 使用anthropic:claude-sonnet-4-5-20250929|model=None|
| 通过标识符 | 传入模型标识符字符串 |model="openai:gpt-4o-mini"|
| 通过实例 | 传入BaseChatModel实例 |ChatOpenAI(model="gpt-4o", temperature=0.3)|
最佳实践
✅ 推荐做法
- 按需模拟:根据测试需要选择性地模拟工具,避免过度模拟影响系统性能。
- 实例优先:对于复杂工具,使用工具实例而非名称来指定模拟,以提高准确性。
- 开发加速:在开发环境中默认模拟所有工具,以加快迭代和调试速度。
- 混合测试:在测试环境中模拟特定工具,同时保留部分真实工具用于集成测试,确保可靠性。
- 模型适配:为关键测试场景选择合适的模型进行模拟,以保证模拟质量。
- 结果对比:记录和比较模拟响应与真实工具的差异,用于验证和改进。
⚠️ 注意事项
- 结果差异:模拟结果与真实工具行为可能存在差异,不能完全替代真实测试。
- 生产禁用:生产环境中不建议使用工具模拟,可能导致不可预测的行为。
- 模型质量:模拟时使用的模型质量会直接影响模拟效果,需谨慎选择。
- 名称准确:工具名称拼写错误会导致模拟失败,需确保名称准确无误。
- 复杂工具:复杂的工具参数可能导致模拟响应不够准确,需重点关注。
- 成本控制:大量工具同时模拟可能增加 API 调用成本,需合理规划。
🎯 适用场景
| 场景 | 核心价值 |
|---|---|
| 开发测试 | 在工具开发阶段进行单元测试和集成测试,加速开发周期。 |
| 成本控制 | 避免频繁调用付费 API,有效降低开发和测试成本。 |
| 环境隔离 | 在受限环境或离线条件下进行开发和测试,不受外部限制。 |
| 错误模拟 | 测试代理处理各种工具响应场景的能力,提升系统鲁棒性。 |
| 快速原型 | 在工具尚未实现时,即可构建和测试代理系统,快速验证方案。 |
| 负载测试 | 在不增加外部 API 负载的情况下,对系统进行压力测试,评估性能。 |
系统与文件操作
File search(文件搜索)
FileSystemFileSearchMiddleware 是 LangChain 框架中,专门用于在本地文件系统进行搜索的中间件。它提供了两个核心工具:
- Glob:用于按文件名模式(如
*.py、src/**/*.md)快速查找文件。 - Grep:用于在文件内容中,通过正则表达式进行文本搜索。
这个中间件非常适合以下场景:
- 代码探索与分析,快速定位项目中的文件和代码片段。
- 按名称模式批量查找文件。
- 使用正则表达式在大型代码库中搜索特定内容。
- 需要高效文件发现的开发工作流。
核心价值
| 特性 | 说明 |
|---|---|
| 文件模式匹配 | 借助 Glob 模式(如 **/*.js),快速递归查找符合条件的文件,无需手动遍历目录。 |
| 内容搜索 | 利用正则表达式,在文件内部搜索关键词、代码片段或特定模式,精准定位内容。 |
| 高效搜索 | 支持 ripgrep 等高性能工具,比传统的 grep 更快,尤其适合大型代码库。 |
| 灵活配置 | 可以自定义搜索的根目录、排除文件、最大搜索深度等参数,适配不同项目结构。 |
| 代码探索 | 帮助开发者快速理解代码库结构,快速定位依赖、配置文件或特定功能实现。 |
简单来说,这个中间件让你在 LangChain 应用中,像使用命令行工具一样高效地操作本地文件系统,为代码理解、文档检索等任务提供了强大的本地数据支持
工作原理
该中间件提供了两个核心工具,分别处理不同的搜索需求:
| 工具 | 核心能力 | 特点与适用场景 |
|---|---|---|
| Glob 工具 | 快速文件模式匹配 | - 支持 **/*.py、src/**/*.ts 等模式,可递归查找文件- 按修改时间排序返回匹配的文件路径 - 适用于按名称查找特定类型的文件,如 “找出所有 Python 文件” |
| Grep 工具 | 文件内容搜索 | - 支持完整正则表达式语法,可精准定位代码片段或文本 - 通过 include 参数按文件模式过滤,缩小搜索范围- 提供三种输出模式: 1. files_with_matches:列出包含匹配项的文件2. content:返回具体匹配的内容片段3. count:返回匹配次数统计- 适用于在文件内容中搜索特定代码或文本,如 “查找所有包含 API_KEY 的配置文件” |
⚙️ 搜索流程
整个中间件的工作流程分为四个清晰的步骤:
初始化
设置搜索的根目录(如
./project)和其他配置参数,例如排除特定文件夹、设置最大搜索深度等,为后续搜索划定范围。工具注册
向 LangChain 的智能体(Agent)注册
glob_search和grep_search两个工具,让智能体知道可以调用这些能力来解决问题。搜索执行
智能体根据用户的查询意图,自动选择最合适的工具。例如,当用户问 “项目里有多少 Markdown 文件?” 时,会调用 Glob 工具;当问 “哪里定义了用户认证逻辑?” 时,则会调用 Grep 工具。
结果处理
对工具返回的原始结果进行格式化处理,如整理成结构化的列表或提取关键信息,然后返回给智能体或用户,方便后续使用。
简单来说,FileSystemFileSearchMiddleware 就像一个高效的本地文件搜索引擎,通过 Glob 和 Grep 这两把 “钥匙”,让 AI 应用可以轻松地在你的代码库和文件系统中 “寻宝”。
代码示例
1 | # 完整的FilesystemFileSearchMiddleware使用示例 |
配置选项
| 参数名 | 类型 | 默认值 | 作用与说明 | 示例 |
|---|---|---|---|---|
| root_path | str | 必填 | 定义搜索的根目录,所有文件操作都相对此路径,是最基础的安全与范围控制。 | root_path=”/workspace” |
| use_ripgrep | bool | True | 控制是否使用高性能的 ripgrep 工具进行内容搜索;若不可用则自动回退到 Python 正则。 |
use_ripgrep=True |
| max_file_size_mb | int | 10 | 设置要搜索的最大文件大小(MB),超过此值的文件会被跳过,避免浪费资源在大文件上。 | max_file_size_mb=10 |
工具功能说明
| 工具 | 核心能力 | 关键特性 | 示例代码 |
|---|---|---|---|
| Glob 工具 | 文件模式匹配 | - 快速按文件名模式查找文件 - 支持 ** 通配符,匹配任意层级目录- 支持 * 通配符,匹配文件名中任意字符- 返回按修改时间排序的文件路径列表 |
glob_search(pattern="**/*.py") |
| Grep 工具 | 文件内容搜索 | - 支持完整正则表达式语法 - include 参数:按文件模式过滤搜索范围- output_mode 控制结果显示方式:1. files_with_matches:仅返回匹配文件路径2. content:返回匹配内容和行号3. count:仅返回匹配计数 |
grep_search(pattern="async def", include="*.py") |
💡 补充说明
- Glob 工具:适合 “找文件” 的场景,比如 “找出项目中所有的 Python 文件” 或 “找出所有以
.md结尾的文档”。 - Grep 工具:适合 “找内容” 的场景,比如 “在所有 Python 文件中查找异步函数定义” 或 “在配置文件中查找特定的 API 密钥”。
最佳实践
✅ 推荐做法
| 做法 | 说明 |
|---|---|
启用 ripgrep |
开启 use_ripgrep=True,利用高性能工具大幅提升内容搜索速度,尤其在大型代码库中效果显著。 |
合理设置 max_file_size_mb |
为大型代码库设置文件大小限制(如默认 10MB),避免在日志、二进制文件等大文件上浪费资源。 |
| 先定位再搜索 | 先用 glob_search 精准定位文件范围,再用 grep_search 在小范围内搜索内容,减少不必要的开销。 |
| 使用精确文件模式 | 避免使用过于宽泛的模式(如 *.*),使用更精确的模式(如 src/**/*.ts)来缩小搜索范围。 |
细化 root_path |
对频繁搜索的目录,使用更具体的根目录(如 /workspace/src 而非 /workspace),提升效率和安全性。 |
⚠️ 注意事项
| 注意点 | 说明 |
|---|---|
| 避免宽泛的 glob 模式 | 在大目录中使用 **/* 这类宽泛模式会导致遍历大量文件,严重影响性能。 |
| 关注正则复杂度 | 过于复杂的正则表达式会显著拖慢搜索速度,应尽量使用简洁、高效的模式。 |
Windows 环境需单独安装 ripgrep |
在 Windows 上,ripgrep 通常需要手动安装,否则中间件会回退到 Python 正则。 |
| 确保目录访问权限 | 智能体必须拥有对 root_path 的读取权限,否则会出现权限错误。 |
| 大量文件需耐心等待 | 对于包含数万文件的项目,首次搜索可能需要较长时间,后续可通过缓存优化。 |
🎯 适用场景
| 场景 | 说明 |
|---|---|
| 代码探索 | 帮助开发者快速了解大型代码库的结构和内容,例如 “项目中有多少个微服务模块?” |
| 模式查找 | 按文件扩展名或命名模式批量查找文件,例如 “找出所有测试用例文件(*.test.ts)”。 |
| 代码搜索 | 使用正则表达式查找特定代码片段,例如 “定位所有包含数据库连接字符串的配置文件”。 |