2.1 定义和区别
Interceptor (拦截器 - 如 ModelInterceptor, ToolInterceptor):
- 图示表现: 你可以看到
ModelInterceptor是一个大框,直接包裹 了Model;同样ToolInterceptor也直接包裹了Tool。 - 含义: 拦截器是核心执行单元的代理/包装器 。它拥有对目标组件(大模型或工具)调用的绝对控制权 。请求必须先进入拦截器,由拦截器决定是否调用实际的
Model或Tool,以及如何处理调用前后的输入输出。它甚至可以直接阻断调用(例如:命中缓存时直接返回结果,不再请求大模型)。
Hook (钩子 - 如 AgentHook, ModelHook):
- 图示表现: 钩子是以独立节点的形式,按照顺序串联在执行流水线(Pipeline)上的。它们分为前置和后置节点。
- 含义: 钩子更像是生命周期中的观测点或切入点。当流程走到特定的阶段(例如:准备调用模型前、模型返回结果后),会触发相应的 Hook。它们通常用于执行一些旁路逻辑,比如:日志记录、埋点监控、状态更新、请求组装或结果过滤等。
| 特性 | Hook (钩子) | Interceptor (拦截器) |
|---|---|---|
| 图示形态 | 流水线上的独立、顺序节点 | 包裹核心组件的容器 |
| 核心职责 | 生命周期观测、状态介入、上下文处理 | 控制核心调用的执行、阻断、替换 |
| 层级区分 | 有宏观(Agent)与微观(Model)之分 |
通常与被代理的实体(Model/Tool)一一对应 |
| 执行位置 | Agent 级别(before/after agent, before/after model) | 模型或工具调用级别 |
| 中断能力 | 支持中断和恢复(如 HumanInTheLoopHook) | 不支持中断,仅拦截和修改 |
| 使用场景 | 人工审批、Agent 间协调 | 日志记录、重试、降级 |
| 配置方式 | .hooks(List.of(...)) |
.interceptors(List.of(...)) |

2.2 作用
2.2.1 消息压缩
java
import com.alibaba.cloud.ai.graph.agent.hook.summarization.SummarizationHook;
// 创建消息压缩 Hook
SummarizationHook summarizationHook = SummarizationHook.builder()
.model(chatModel)
.maxTokensBeforeSummary(4000)
.messagesToKeep(20)
.build();
// 使用
ReactAgent agent = ReactAgent.builder()
.name("my_agent")
.model(chatModel)
.hooks(summarizationHook)
.build();
2.2.2 人机协同(需要人工批准的操作)
java
import com.alibaba.cloud.ai.graph.agent.hook.hip.HumanInTheLoopHook;
import com.alibaba.cloud.ai.graph.agent.hook.hip.ToolConfig;
// 创建 Human-in-the-Loop Hook
HumanInTheLoopHook humanReviewHook = HumanInTheLoopHook.builder()
.approvalOn("sendEmailTool", ToolConfig.builder().description("Please confirm sending the email.").build())
.approvalOn("deleteDataTool")
.build();
ReactAgent agent = ReactAgent.builder()
.name("supervised_agent")
.model(chatModel)
.tools(sendEmailTool, deleteDataTool)
.hooks(humanReviewHook)
.saver(new RedisSaver())
.build();
还可以使用interceptToolCall进行拦截确认
java
public class ConsoleApprovalInterceptor extends ToolInterceptor {
private final Set<String> toolsRequiringApproval;
private final Scanner scanner;
public ConsoleApprovalInterceptor(Set<String> toolsRequiringApproval, Scanner scanner) {
this.toolsRequiringApproval = toolsRequiringApproval;
this.scanner = scanner;
}
@Override
public ToolCallResponse interceptToolCall(ToolCallRequest request, ToolCallHandler handler) {
String toolName = request.getToolName();
if (toolsRequiringApproval.contains(toolName)) {
System.out.println("\n[Approval Required]");
System.out.println("Tool: " + toolName);
System.out.println("Arguments: " + request.getArguments());
System.out.print("Approve? (y/n): ");
String approval = scanner.nextLine();
if (!"y".equalsIgnoreCase(approval)) {
return ToolCallResponse.of(
request.getToolCallId(),
toolName,
"Tool call rejected by user"
);
}
}
return handler.call(request);
}
@Override
public String getName() {
return "console-approval";
}
}
2.2.3 模型调用限制
java
ReactAgent agent = ReactAgent.builder()
.name("my_agent")
.model(chatModel)
.hooks(ModelCallLimitHook.builder().runLimit(5).build()) // 限制模型调用次数为5次
.saver(new MemorySaver())
.build();
注意:这里是限制用户发起一次对话,agent在底层调用大模型的次数,不是用户调用大模型的次数
2.2.4 PII检测
java
import com.alibaba.cloud.ai.graph.agent.hook.pii.PIIDetectionHook;
import com.alibaba.cloud.ai.graph.agent.hook.pii.PIIType;
import com.alibaba.cloud.ai.graph.agent.hook.pii.RedactionStrategy;
PIIDetectionHook pii = PIIDetectionHook.builder()
.piiType(PIIType.EMAIL)
.strategy(RedactionStrategy.REDACT)
.applyToInput(true)
.build();
// 使用
ReactAgent agent = ReactAgent.builder()
.name("secure_agent")
.model(chatModel)
.hooks(pii)
.build();
简单来说就是对敏感信息进行脱敏:
例如:请你帮我给 123@gmail.com 发送一个邮件,祝他生日快乐。
PII脱敏之后,大模型收到的消息为:请你帮我给[脱敏邮箱]发送一个邮件,祝他生日快乐。
缺点就是:如果你需要大模型帮你调用工具发送邮箱,由于被脱敏保护,大模型会丢失关键邮箱参数,导致不能发送邮箱
2.2.5 工具重试
java
import com.alibaba.cloud.ai.graph.agent.interceptor.toolretry.ToolRetryInterceptor;
// 使用
ReactAgent agent = ReactAgent.builder()
.name("resilient_agent")
.model(chatModel)
.tools(searchTool, databaseTool)
.interceptors(ToolRetryInterceptor.builder()
.maxRetries(2)
.onFailure(ToolRetryInterceptor.OnFailureBehavior.RETURN_MESSAGE)
.build())
.build();
2.2.6 LLM 工具选择器、LLM 工具模拟器、上下文编辑
java
ReactAgent agent = ReactAgent.builder()
.name("smart_selector_agent")
.model(chatModel)
.tools(tool1, tool2)
.interceptors(ToolSelectionInterceptor.builder().build(),
ToolEmulatorInterceptor.builder().model(chatModel).build(),
ContextEditingInterceptor.builder().trigger(120000).clearAtLeast(60000).build()
)
.build();
2.3 自定义Hooks和Interceptors
-
自定义Hooks:
-
标记Hooks的所在位置(模型调用前后 / agent调用前后)
-
继承AgentHook / MessagesModelHook / ModelHook 并重写方法
javapackage com.dyl.springaialibabastudy.hooks; import com.alibaba.cloud.ai.graph.OverAllState; import com.alibaba.cloud.ai.graph.RunnableConfig; import com.alibaba.cloud.ai.graph.agent.hook.AgentHook; import com.alibaba.cloud.ai.graph.agent.hook.HookPosition; import com.alibaba.cloud.ai.graph.agent.hook.HookPositions; import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.CompletableFuture; // 1. AgentHook - 在 Agent 开始/结束时执行,每次Agent调用只会运行一次 @HookPositions({HookPosition.BEFORE_AGENT, HookPosition.AFTER_AGENT}) @Component public class LoggingHook extends AgentHook { @Override public String getName() { return "logging"; } @Override public CompletableFuture<Map<String, Object>> beforeAgent(OverAllState state, RunnableConfig config) { System.out.println("Agent 开始执行"); return CompletableFuture.completedFuture(Map.of()); } @Override public CompletableFuture<Map<String, Object>> afterAgent(OverAllState state, RunnableConfig config) { System.out.println("Agent 执行完成"); return CompletableFuture.completedFuture(Map.of()); } } // 模型前后:@HookPositions({HookPosition.BEFORE_MODEL, HookPosition.AFTER_MODEL}) // extends MessagesModelHook 或 ModelHook
MessagesModelHook 和 ModelHook 区别:
特性 MessagesModelHook (推荐) ModelHook 关注核心 专注于 消息列表 (Messages) 的操作 关注 Agent 的 完整状态 (OverAllState) 数据访问范围 只能接收和返回模型的对话消息(如 SystemMessage, UserMessage, AssistantMessage 等) 可以访问并修改 Agent 运行时的全部上下文状态,包括消息列表、业务变量、中间状态等 使用复杂度 极简。不需要了解底层的复杂状态机,只需处理 List 即可 较高 。需要处理复杂的 OverAllState对象官方态度 ⭐️ 更推荐(针对大多数常规需求) 基础/底层 Hook(针对复杂需求) MessagesModelHook(消息钩子): 它是ModelHook的一种更聚焦、更高层的抽象。在实际开发中,我们在大模型调用前后,90% 的工作都是在处理"说的话"(消息)。这个 Hook 把你从复杂的 Agent 状态引擎中解放出来,只塞给你一堆 Message,你处理完再把 Message 还给它就行了。ModelHook(模型状态钩子): 它是更底层的机制。当 Agent 运行到一个节点准备调用模型时,ModelHook能够拿到这个 Agent 当前脑子里的所有东西(OverAllState) 。如果你不仅想改消息,还想根据消息偷偷修改 Agent 的某些业务标记(比如:识别到用户生气了,在全局状态里打个is_angry=true的 Tag,供后面的其他节点使用),你就必须用它。 -
-
自定义Interceptor
- ModelInterceptor
- ToolInterceptor
2.4 执行顺序
java
ReactAgent agent = ReactAgent.builder()
.name("my_agent")
.model(chatModel)
.hooks(hook1, hook2, hook3)
.interceptors(interceptor1, interceptor2)
.interceptors(toolInterceptor1, toolInterceptor2)
.build();
执行流程:
- Before Agent Hooks (按顺序):
hook1.beforeAgent()hook2.beforeAgent()hook3.beforeAgent()
- Agent 循环开始
- Before Model Hooks (按顺序):
hook1.beforeModel()hook2.beforeModel()hook3.beforeModel()
- Model Interceptors (嵌套调用):
interceptor1→interceptor2→ 模型调用
- After Model Hooks (逆序):
hook3.afterModel()hook2.afterModel()hook1.afterModel()
- Tool Interceptors (如果有工具调用,嵌套调用): (先调用模型,然后模型请求调用tool,所以ToolInterceptor一定会在ModelHooks 和 ModelInterceptor后面)
toolInterceptor1→toolInterceptor2→ 工具执行
- Agent 循环结束
- After Agent Hooks (逆序):
hook3.afterAgent()hook2.afterAgent()hook1.afterAgent()
关键规则:
before_*hooks: 从第一个到最后一个after_*hooks: 从最后一个到第一个(逆序)- Interceptors: 嵌套调用(第一个拦截器包装所有其他的)