在某些情况下,你可能希望 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

AI项目博客






