AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 25|Hooks 与 Interceptors · 自定义 Hooks 和 Interceptors:MessagesModelHook vs ModelHook:如何选择?

MessagesModelHook 和 ModelHook 都可以在模型调用前后执行自定义逻辑,但它们有不同的设计目标和适用场景。

核心区别

特性 MessagesModelHook ModelHook
易用性 ⭐⭐⭐⭐⭐ 更简单,直接操作消息列表 ⭐⭐⭐ 需要理解 OverAllState
灵活性 ⭐⭐⭐ 专注于消息操作 ⭐⭐⭐⭐⭐ 可访问和修改完整状态
推荐场景 消息修剪、过滤、添加系统提示 需要访问全局状态、自定义状态管理
API 复杂度 简单:AgentCommand 返回消息列表 复杂:返回 Map<String, Object> 更新状态

使用建议

选择 MessagesModelHook,如果你需要:

  • ✅ 简单的消息操作(修剪、过滤、转换);
  • ✅ 添加或修改系统提示;
  • ✅ 消息压缩和摘要;
  • ✅ 快速实现消息相关的 Hook。

选择 ModelHook,如果你需要:

  • ✅ 访问和修改 OverAllState 中的其他数据;
  • ✅ 在状态中存储自定义信息(如计数器、缓存等);
  • ✅ 基于全局状态做复杂决策;
  • ✅ 需要查看 Agent 执行过程中的完整上下文。

对比示例

场景:消息修剪

使用 MessagesModelHook(推荐):

import com.alibaba.cloud.ai.graph.agent.hook.messages.MessagesModelHook;
import com.alibaba.cloud.ai.graph.agent.hook.messages.AgentCommand;
import com.alibaba.cloud.ai.graph.agent.hook.messages.UpdatePolicy;
import com.alibaba.cloud.ai.graph.agent.hook.HookPosition;
import com.alibaba.cloud.ai.graph.agent.hook.HookPositions;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import org.springframework.ai.chat.messages.Message;
import java.util.List;

@HookPositions({HookPosition.BEFORE_MODEL})
public class SimpleMessageTrimmingHook extends MessagesModelHook {
  private static final int MAX_MESSAGES = 10;

  @Override
  public String getName() {
      return "simple_message_trimming";
  }

  @Override
  public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {
      if (previousMessages.size() > MAX_MESSAGES) {
          List<Message> trimmed = previousMessages.subList(
              previousMessages.size() - MAX_MESSAGES,
              previousMessages.size()
          );
          return new AgentCommand(trimmed, UpdatePolicy.REPLACE);
      }
      return new AgentCommand(previousMessages);
  }
}

使用 ModelHook(更复杂但更灵活):

import com.alibaba.cloud.ai.graph.agent.hook.ModelHook;
import com.alibaba.cloud.ai.graph.agent.hook.HookPosition;
import com.alibaba.cloud.ai.graph.agent.hook.HookPositions;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.state.ReplaceAllWith;
import org.springframework.ai.chat.messages.Message;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@HookPositions({HookPosition.BEFORE_MODEL})
public class AdvancedMessageTrimmingHook extends ModelHook {
  private static final int MAX_MESSAGES = 10;
  private static final String TRIM_COUNT_KEY = "trim_count";

  @Override
  public String getName() {
      return "advanced_message_trimming";
  }

  @Override
  public CompletableFuture<Map<String, Object>> beforeModel(OverAllState state, RunnableConfig config) {
      // 可以访问完整状态
      Optional<Object> messagesOpt = state.value("messages");
      if (messagesOpt.isEmpty()) {
          return CompletableFuture.completedFuture(Map.of());
      }

      List<Message> messages = (List<Message>) messagesOpt.get();

      // 可以访问和更新自定义状态
      int trimCount = (Integer) state.value(TRIM_COUNT_KEY).orElse(0);

      if (messages.size() > MAX_MESSAGES) {
          List<Message> trimmed = messages.subList(
              messages.size() - MAX_MESSAGES,
              messages.size()
          );

          // 可以同时更新消息和自定义状态
          return CompletableFuture.completedFuture(Map.of(
              "messages", ReplaceAllWith.of(trimmed),
              TRIM_COUNT_KEY, trimCount + 1  // 记录修剪次数
          ));
      }

      return CompletableFuture.completedFuture(Map.of());
  }
}

总结:

  • 优先使用 MessagesModelHook:对于大多数消息操作场景,它提供了更简洁的 API,代码更易读易维护。
  • 使用 ModelHook:当你需要访问全局状态、存储自定义数据或进行复杂的状态管理时。

在 Agent 整体执行的开始和结束时执行:

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 java.util.concurrent.CompletableFuture;

@HookPositions({HookPosition.BEFORE_AGENT, HookPosition.AFTER_AGENT})
public class CustomAgentHook extends AgentHook {

  @Override
  public String getName() {
      return "custom_agent_hook";
  }

  @Override
  public CompletableFuture<Map<String, Object>> beforeAgent(OverAllState state, RunnableConfig config) {
      System.out.println("Agent 开始执行");
      // 可以初始化资源、记录开始时间等
      return CompletableFuture.completedFuture(Map.of("start_time", System.currentTimeMillis()));
  }

  @Override
  public CompletableFuture<Map<String, Object>> afterAgent(OverAllState state, RunnableConfig config) {
      System.out.println("Agent 执行完成");
      // 可以清理资源、计算执行时间等
      Optional<Object> startTime = state.value("start_time");
      if (startTime.isPresent()) {
          long duration = System.currentTimeMillis() - (Long) startTime.get();
          System.out.println("执行耗时: " + duration + "ms");
      }
      return CompletableFuture.completedFuture(Map.of());
  }
}

本文整理自 Spring AI Alibaba 官方文档《Hooks 与 Interceptors》:https://java2ai.com/docs/frameworks/agent-framework/tutorials/hooks

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 25|Hooks 与 Interceptors · 自定义 Hooks 和 Interceptors:MessagesModelHook vs ModelHook:如何选择?

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册