如上所示,修剪或删除消息的问题在于你可能会丢失消息队列淘汰的信息。因此,一些应用程序受益于使用聊天模型总结消息历史的更复杂方法。
要在 Agent 中总结消息历史,可以使用自定义 Hook:
import com.alibaba.cloud.ai.graph.agent.hook.HookPosition;
import com.alibaba.cloud.ai.graph.agent.hook.HookPositions;
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.RunnableConfig;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import java.util.ArrayList;
import java.util.List;
@HookPositions({HookPosition.BEFORE_MODEL})
public class MessageSummarizationHook extends MessagesModelHook {
private final ChatModel summaryModel;
private final int maxTokensBeforeSummary;
private final int messagesToKeep;
public MessageSummarizationHook(
ChatModel summaryModel,
int maxTokensBeforeSummary,
int messagesToKeep
) {
this.summaryModel = summaryModel;
this.maxTokensBeforeSummary = maxTokensBeforeSummary;
this.messagesToKeep = messagesToKeep;
}
@Override
public String getName() {
return "message_summarization";
}
@Override
public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {
// 估算 token 数量(简化版)
int estimatedTokens = previousMessages.stream()
.mapToInt(m -> m.getText().length() / 4)
.sum();
if (estimatedTokens < maxTokensBeforeSummary) {
return new AgentCommand(previousMessages);
}
// 需要总结
int messagesToSummarize = previousMessages.size() - messagesToKeep;
if (messagesToSummarize <= 0) {
return new AgentCommand(previousMessages);
}
List<Message> oldMessages = previousMessages.subList(0, messagesToSummarize);
List<Message> recentMessages = previousMessages.subList(messagesToSummarize, previousMessages.size());
// 生成摘要
String summary = generateSummary(oldMessages);
// 创建摘要消息
SystemMessage summaryMessage = new SystemMessage(
"## 之前对话摘要:
" + summary
);
// 构建新的消息列表:摘要消息 + 保留的最近消息
List<Message> newMessages = new ArrayList<>();
newMessages.add(summaryMessage);
newMessages.addAll(recentMessages);
// 使用 REPLACE 策略替换消息列表
return new AgentCommand(newMessages, UpdatePolicy.REPLACE);
}
private String generateSummary(List<Message> messages) {
StringBuilder conversation = new StringBuilder();
for (Message msg : messages) {
conversation.append(msg.getMessageType())
.append(": ")
.append(msg.getText())
.append("
");
}
String summaryPrompt = "请简要总结以下对话:
" + conversation;
ChatResponse response = summaryModel.call(
new Prompt(new UserMessage(summaryPrompt))
);
return response.getResult().getOutput().getText();
}
}
// 使用
ChatModel summaryModel = // ... 用于总结的模型(可以是更便宜的模型)
MessageSummarizationHook summarizationHook = new MessageSummarizationHook(
summaryModel,
4000, // 在 4000 tokens 时触发总结
20 // 总结后保留最后 20 条消息
);
ReactAgent agent = ReactAgent.builder()
.name("my_agent")
.model(chatModel)
.hooks(summarizationHook)
.saver(new MemorySaver())
.build();
RunnableConfig config = RunnableConfig.builder()
.threadId("1")
.build();
agent.call("你好,我叫 bob", config);
agent.call("写一首关于猫的短诗", config);
agent.call("现在对狗做同样的事情", config);
AssistantMessage finalResponse = agent.call("我叫什么名字?", config);
System.out.println(finalResponse.getText());
// 输出:你的名字是 Bob!
本文整理自 Spring AI Alibaba 官方文档《Memory 短期记忆》:https://java2ai.com/docs/frameworks/agent-framework/tutorials/memory

AI项目博客






