model,让其选择要执行的 tools,然后在不再调用任何工具时结束。
Middleware.before_model:在模型执行前运行。可更新状态或跳转到不同节点(model,tools,__end__)Middleware.modify_model_request:在模型执行前运行,用于准备模型请求对象。只能修改当前模型请求对象(不能永久更新状态),且不能跳转到不同节点。Middleware.after_model:在模型执行后、工具执行前运行。可更新状态或跳转到不同节点(model,tools,END)
before_model、modify_model_request 或 after_model 中间件。无需实现全部三种。
在代理中使用
可以通过将中间件传递给create_agent 来在代理中使用:
model必须是字符串或BaseChatModel。若传入函数则会报错。如需动态控制模型,请使用AgentMiddleware.modify_model_requestprompt必须是字符串或 None。若传入函数则会报错。如需动态控制提示词,请使用AgentMiddleware.modify_model_request- 不得提供
pre_model_hook。请改用AgentMiddleware.before_model - 不得提供
post_model_hook。请改用AgentMiddleware.after_model
内置中间件
LangChain 提供了若干开箱即用的内置中间件:摘要
summarizationMiddleware 在接近令牌限制时自动通过摘要旧消息来管理对话历史。该中间件监控消息的总令牌数,并创建简洁摘要以在保持上下文的同时不超出模型限制。
主要特性:
- 自动令牌计数和阈值监控
- 智能消息分区,保留 AI/工具消息对
- 可自定义的摘要提示和令牌限制
- 超过令牌限制的长时对话
- 具有广泛上下文的多轮对话
model:用于生成摘要的语言模型(必需)maxTokensBeforeSummary:触发摘要的令牌阈值messagesToKeep:保留的最近消息数量(默认:20)tokenCounter:自定义令牌计数函数(默认为基于字符的近似值)summaryPrompt:摘要生成的自定义提示模板summaryPrefix:添加到包含摘要的系统消息前的前缀(默认:”## Previous conversation summary:”)
- 从不拆分 AI 消息与其对应的工具响应
- 保留最新消息以保持连续性
- 在新摘要周期中包含之前的摘要
人在回路
humanInTheLoopMiddleware 为 AI 代理执行的工具调用启用人工监督和干预。该中间件拦截工具执行,允许人工操作员在执行前批准、修改、拒绝或手动响应工具调用。
主要特性:
- 基于配置的工具选择性批准
- 多种响应类型(接受、编辑、忽略、响应)
- 使用 LangGraph 中断的异步审批工作流
- 带上下文信息的自定义审批消息
- 需要人工批准的高风险操作(数据库写入、文件系统更改)
- AI 行为的质量控制和安全检查
- 需要审计跟踪的合规场景
- 代理行为的开发和测试
accept:使用原始参数执行工具edit:修改参数后再执行 -{ type: "edit", args: { action: "tool_name", args: { modified: "args" } } }ignore:跳过工具执行并终止代理response:提供手动响应而非执行工具 -{ type: "response", args: "手动响应文本" }
toolConfigs:工具名称到其审批设置的映射requireApproval:该工具是否需要人工批准description:审批请求时显示的自定义消息
messagePrefix:审批消息的默认前缀
Anthropic 提示缓存
AnthropicPromptCachingMiddleware 是一个中间件,可启用 Anthropic 的原生提示缓存功能。
提示缓存通过允许从提示中的特定前缀恢复来优化 API 使用。这对于具有重复提示或冗余信息提示的任务特别有用。
了解更多关于 Anthropic 提示缓存(策略、限制等)请点击此处。
自定义中间件
代理的中间件是AgentMiddleware 的子类,实现其一个或多个钩子。
AgentMiddleware 目前提供三种修改核心代理循环的方式:
before_model:在模型运行前执行。可更新状态或通过跳转提前退出。modify_model_request:在模型运行前执行。不能更新状态或通过跳转提前退出。after_model:在模型运行后执行。可更新状态或通过跳转提前退出。
jump_to 键,其值为以下之一:
"model":跳转到模型节点"tools":跳转到工具节点"__end__":跳转到结束节点
before_model
在模型运行前执行。可通过返回新状态对象或状态更新来修改状态。
签名:
modify_model_request
在模型运行前执行,但在所有 before_model 调用之后。
这些函数不能修改永久状态或提前退出。
它们旨在以无状态*方式修改模型调用。
如果你想以有状态**方式修改模型调用,则需要使用 before_model
修改模型请求。模型请求有几个关键属性:
-
model(BaseChatModel):要使用的模型。注意:这需要是基础聊天模型,而不是字符串。 -
system_prompt(str):要使用的系统提示。将被前置到messages -
messages(消息列表):消息列表。不应包含系统提示。 -
tool_choice(任意):要使用的工具选择 -
tools(BaseTool列表):此模型调用要使用的工具 -
response_format(ResponseFormat):用于结构化输出的响应格式
after_model
在模型运行后执行。可通过返回新状态对象或状态更新来修改状态。
签名:
新状态键
中间件可以通过自定义属性扩展代理的状态,实现中间件组件之间的丰富数据流,并确保代理执行过程中的类型安全。状态扩展
中间件可以定义在代理执行过程中持续存在的额外状态属性。这些属性成为代理状态的一部分,并可供该中间件的所有钩子使用。上下文扩展
目前仅在 JavaScript 中可用。
组合多个中间件
使用多个中间件时,它们的状态和上下文模式会被合并。必须满足所有中间件的所有必需属性:代理级上下文模式
代理也可以定义自己的上下文要求,这些要求与中间件要求相结合:最佳实践
- 使用状态存储动态数据:执行过程中变化的属性(用户会话、累积数据)
- 使用上下文存储配置:静态配置值(API 密钥、功能标志、限制)
- 尽可能提供默认值:在 Zod 模式中使用
.default()使属性可选 - 记录要求:清晰记录中间件所需的状态和上下文属性
中间件执行顺序
你可以提供多个中间件。它们按以下逻辑执行:before_model:按传入顺序执行。如果较早的中间件提前退出,则后续中间件不会运行
modify_model_request:按传入顺序执行。
after_model:按传入顺序的反向执行。如果较早的中间件提前退出,则后续中间件不会运行
代理跳转
为了提前退出,你可以在状态更新中添加一个jump_to 键,其值为以下之一:
"model":跳转到模型节点"tools":跳转到工具节点"__end__":跳转到结束节点
model 节点,所有 before_model 中间件都会运行。禁止从现有的 before_model 中间件跳转到 model。
使用示例: