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

Spring AI Alibaba 02|Agents 智能体 · 高级特性:结构化输出

在某些情况下,你可能希望 Agent 以特定格式返回输出。ReactAgent 提供了两种策略。

使用 outputType

通过 Java 类定义输出结构,Agent 会自动生成对应的 JSON Schema:

public class PoemOutput {
  private String title;
  private String content;
  private String style;

  // Getters and Setters
  public String getTitle() { return title; }
  public void setTitle(String title) { this.title = title; }

  public String getContent() { return content; }
  public void setContent(String content) { this.content = content; }

  public String getStyle() { return style; }
  public void setStyle(String style) { this.style = style; }
}

ReactAgent agent = ReactAgent.builder()
  .name("poem_agent")
  .model(chatModel)
  .outputType(PoemOutput.class)
  .saver(new MemorySaver())
  .build();

AssistantMessage response = agent.call("写一首关于春天的诗");
// 输出会遵循 PoemOutput 的结构
System.out.println(response.getText());

使用 outputSchema

使用 BeanOutputConverter 生成输出 Schema,提供类型安全和自动 schema 生成:

import org.springframework.ai.converter.BeanOutputConverter;

// 定义输出类型
public static class TextAnalysisResult {
  private String summary;
  private List<String> keywords;
  private String sentiment;
  private Double confidence;

  // Getters and Setters
  public String getSummary() { return summary; }
  public void setSummary(String summary) { this.summary = summary; }
  public List<String> getKeywords() { return keywords; }
  public void setKeywords(List<String> keywords) { this.keywords = keywords; }
  public String getSentiment() { return sentiment; }
  public void setSentiment(String sentiment) { this.sentiment = sentiment; }
  public Double getConfidence() { return confidence; }
  public void setConfidence(Double confidence) { this.confidence = confidence; }
}

// 使用 BeanOutputConverter 生成 outputSchema
BeanOutputConverter<TextAnalysisResult> outputConverter = new BeanOutputConverter<>(TextAnalysisResult.class);
String format = outputConverter.getFormat();

ReactAgent agent = ReactAgent.builder()
  .name("analysis_agent")
  .model(chatModel)
  .outputSchema(format)
  .saver(new MemorySaver())
  .build();

AssistantMessage response = agent.call("分析这段文本:春天来了,万物复苏。");

选择建议:

  • outputType:类型安全,适合结构固定的场景(推荐)
  • outputSchema:使用 BeanOutputConverter 生成时提供类型安全,手动提供字符串时灵活性高,适合动态或复杂的输出格式

Agent 通过状态自动维护对话历史。使用 MemorySaver 配置持久化存储。

import com.alibaba.cloud.ai.graph.checkpoint.config.SaverConfig;
import com.alibaba.cloud.ai.graph.checkpoint.constant.SaverEnum;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;

// 配置内存存储
ReactAgent agent = ReactAgent.builder()
  .name("chat_agent")
  .model(chatModel)
  .saver(new MemorySaver())
  .build();

// 使用 thread_id 维护对话上下文
RunnableConfig config = RunnableConfig.builder()
  .threadId("user_123")
  .build();

agent.call("我叫张三", config);
agent.call("我叫什么名字?", config);  // 输出: "你叫张三"

生产环境:使用 RedisSaver、MongoSaver 等持久化存储替代 MemorySaver。

Hooks 允许在 Agent 执行的关键点插入自定义逻辑。

Hook 类型与使用

import com.alibaba.cloud.ai.graph.agent.hook.*;
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;

// 1. AgentHook - 在 Agent 开始/结束时执行,每次Agent调用只会运行一次
@HookPositions({HookPosition.BEFORE_AGENT, HookPosition.AFTER_AGENT})
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());
  }
}

// 2. MessagesModelHook - 在模型调用前后执行(例如:消息修剪),专门用于操作消息列表,使用更简单,更推荐。区别于AgentHook,MessagesModelHook在一次agent调用中可能会调用多次,也就是每次 reasoning-acting 迭代都会执行
@HookPositions({HookPosition.BEFORE_MODEL})
public class MessageTrimmingHook extends MessagesModelHook {
  private static final int MAX_MESSAGES = 10;

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

  @Override
  public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {
      if (previousMessages.size() > MAX_MESSAGES) {
          // 只保留最后 MAX_MESSAGES 条消息
          List<Message> trimmedMessages = previousMessages.subList(
              previousMessages.size() - MAX_MESSAGES, 
              previousMessages.size()
          );
          return new AgentCommand(trimmedMessages, UpdatePolicy.REPLACE);
      }
      // 消息数量未超过限制,直接返回原消息列表
      return new AgentCommand(previousMessages);
  }
}

Hook 执行位置:

  • BEFORE_AGENT / AFTER_AGENT:Agent 整体执行前后
  • BEFORE_MODEL / AFTER_MODEL:Agent Loop 循环过程中,每次模型调用前后

Interceptors 提供更细粒度的控制,可以拦截和修改模型调用和工具执行。

使用示例

import com.alibaba.cloud.ai.graph.agent.interceptor.*;

// ModelInterceptor - 内容安全检查
public class GuardrailInterceptor extends ModelInterceptor {
  @Override
  public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
      // 前置:检查输入
      if (containsSensitiveContent(request.getMessages())) {
      	return ModelResponse.of(AssistantMessage.builder().content("检测到不适当的内容").build());
      }

      // 执行调用
      ModelResponse response = handler.call(request);

      // 后置:检查输出
      return sanitizeIfNeeded(response);
  }
}

// ToolInterceptor - 监控和错误处理
public class ToolMonitoringInterceptor extends ToolInterceptor {
  @Override
  public ToolCallResponse interceptToolCall(ToolCallRequest request, ToolCallHandler handler) {
      long startTime = System.currentTimeMillis();
      try {
          ToolCallResponse response = handler.call(request);
          logSuccess(request, System.currentTimeMillis() - startTime);
          return response;
      } catch (Exception e) {
          logError(request, e, System.currentTimeMillis() - startTime);
          return ToolCallResponse.error(request.getToolCall(),
              "工具执行遇到问题,请稍后重试");
      }
  }
}

// 组合使用
ReactAgent agent = ReactAgent.builder()
  .name("my_agent")
  .model(chatModel)
  .interceptors(new GuardrailInterceptor(), new LoggingInterceptor(), new ToolMonitoringInterceptor())
  .saver(new MemorySaver())
  .build();

常见用途:

  • ModelInterceptor:内容安全、动态提示、日志记录、性能监控
  • ToolInterceptor:错误重试、权限检查、结果缓存、审计日志

本文整理自 Spring AI Alibaba 官方文档《Agents 智能体》:https://java2ai.com/docs/frameworks/agent-framework/tutorials/agents

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 02|Agents 智能体 · 高级特性:结构化输出

评论 抢沙发

AI项目博客

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

关于本站文章归档

登录

找回密码

注册