当前位置: 首页 > news >正文

Spring Ai 1.0.1中存在的问题:使用MessageChatMemoryAdvisor导致System未被正确的放在首位

使用MessageChatMemoryAdvisor导致System未被正确的放在首位

如下是使用Spring Ai实现多轮对话的官方例子(文档地址:https://docs.spring.io/spring-ai/reference/api/chat-memory.html):

 @AutowiredChatMemoryRepository chatMemoryRepository;  //注入对话记忆@GetMapping("/chatMemory")@Operation(summary = "带记忆的同步调用")String chatMemory(String userInput) {// 1. 构建对话记忆存储配置// 使用MessageWindowChatMemory实现窗口记忆策略ChatMemory chatMemory = MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository) // 底层记忆存储仓库(测试使用内存实现).maxMessages(20)    // 设置历史消息最大保留轮次(滑动窗口大小).build();// 2. 生成唯一会话ID(实际项目中由)String conversationId = "123456789"; // 示例固定值,生产环境需动态生成// 3. 构建对话请求并配置各组件return this.chatClient.prompt()// 3.1 设置对话角色.system(system)  // 系统角色设定(AI人设/指令)// 3.2 设置基础参数.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId) // 绑定当前对话ID到请求上下文)// 3.3 添加增强功能(Advisors).advisors(new SimpleLoggerAdvisor(),  // 启用请求日志记录(用于调试)MessageChatMemoryAdvisor.builder(chatMemory).build(),   // 启用记忆管理功能)// 3.4 设置当前用户输入.user(userInput)// 3.5 执行调用.call() // 发送同步请求到对话服务// 3.6 处理响应.content(); // 提取响应中的文本内容}

如上示例是根据官方文档写的,实际测下来是有问题的,例如:有的模型在二轮对话的时候返回顺序问题报错,有的模型在二轮对话的时候丢失人设。(这个和模型的兼容性有关系)

经过排查可以发现二轮对话的Message中内容顺序会有问题(System人设被放到了倒数第二句):

[{"role": "user","content": "您好"},{"role": "assistant","content": "\n\n您好!很高兴为您提供服务。请问有什么可以帮助您的吗?"},{"role": "system","content": "你是智能助理小明"},{"role": "user","content": "你叫什么名字啊"}
]

已上述的格式请求大模型会出现各种问题,因为正常规定的顺序就是S- U- A-U。
在GitHub中有大佬给出临时解决办法,创建一个SystemFirstSortingAdvisor来确保System人设始终保持第一位:(GitHub原问题地址:https://github.com/spring-projects/spring-ai/issues/4170)

/*** 保证SYSTEM在最前面的增强*/
public class SystemFirstSortingAdvisor implements BaseAdvisor {@Overridepublic ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {List<Message> processedMessages = chatClientRequest.prompt().getInstructions();processedMessages.sort(Comparator.comparing(m -> m.getMessageType() == MessageType.SYSTEM ? 0 : 1));return chatClientRequest.mutate().prompt(chatClientRequest.prompt().mutate().messages(processedMessages).build()).build();}@Overridepublic ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {return chatClientResponse; // no-op}@Overridepublic int getOrder() {return 0; // larger than MessageChatMemoryAdvisor so it runs afterwards}
}

最后正确调用(在advisors中加入SystemFirstSortingAdvisor):

 @AutowiredChatMemoryRepository chatMemoryRepository;  //注入对话记忆@GetMapping("/chatMemory")@Operation(summary = "带记忆的同步调用")String chatMemory(String userInput) {// 1. 构建对话记忆存储配置// 使用MessageWindowChatMemory实现窗口记忆策略ChatMemory chatMemory = MessageWindowChatMemory.builder().chatMemoryRepository(chatMemoryRepository) // 底层记忆存储仓库(测试使用内存实现).maxMessages(20)    // 设置历史消息最大保留轮次(滑动窗口大小).build();// 2. 生成唯一会话ID(实际项目中由)String conversationId = "123456789"; // 示例固定值,生产环境需动态生成// 3. 构建对话请求并配置各组件return this.chatClient.prompt()// 3.1 设置对话角色.system(system)  // 系统角色设定(AI人设/指令)// 3.2 设置基础参数.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId) // 绑定当前对话ID到请求上下文)// 3.3 添加增强功能(Advisors).advisors(new SimpleLoggerAdvisor(),  // 启用请求日志记录(用于调试)MessageChatMemoryAdvisor.builder(chatMemory).build(),   // 启用记忆管理功能new SystemFirstSortingAdvisor() // 确保系统消息优先排序)// 3.4 设置当前用户输入.user(userInput)// 3.5 执行调用.call() // 发送同步请求到对话服务// 3.6 处理响应.content(); // 提取响应中的文本内容}

综上所述,下个版本可能会优化掉这个BUG,目前就先使用SystemFirstSortingAdvisor来保证正常调用。

http://www.xdnf.cn/news/1349173.html

相关文章:

  • c++最新进展
  • fdisk工具源码编译生成
  • DAY14-新世纪DL(DeepLearning/深度学习)战士:破(优化算法)2
  • 多线程下为什么用ConcurrentHashMap而不是HashMap
  • 【Android】 连接wifi时,强制应用使用流量
  • 【从零开始java学习|第九篇】方法的相关知识与练习
  • 【微服务的数据一致性分发问题】究极解决方案
  • 日志的配置
  • 一键部署openGauss6.0.2轻量版单节点
  • Spring原理
  • 最近 | 黄淮教务 | 小工具合集
  • 世界模型一种能够对现实世界环境进行仿真,并基于文本、图像、视频和运动等输入数据来生成视频、预测未来状态的生成式 AI 模型
  • Maxscript如何清理3dMax场景?
  • 打工人日报20250822
  • More Effective C++ 条款01:仔细区别 pointers 和 references
  • Java设计模式-外观模式
  • 滑动窗口+子串+普通数组算法
  • Elasticsearch搜索原理
  • HEVC(H.265)与HVC1的关系及区别
  • Unreal Engine UProjectileMovementComponent
  • 异步开发的三种实现方式
  • Unreal Engine USceneComponent
  • Unreal Engine Simulate Physics
  • 线段树01
  • 20250822 组题总结
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘uvicorn’问题
  • 北京-测试-入职甲方金融-上班第三天
  • 嵌入式第三十五天(网络编程(UDP))
  • GPS欺骗式干扰的产生
  • DSPy框架:从提示工程到声明式编程的革命性转变