项目环境:JDK17,springboot 版本:3.4.5,springai版本:1.0.0-RC1,mysql版本:8.0
##问题描述:在使用基于mysql 的JdbcChatMemoryRepository作为持久化存储库的时候,与大模型对话会触发下面的异常:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BYtimestamp` DESC LIMIT ?]
.....
Caused by: java.sql.SQLException: No value specified for parameter 2
###ChatClient配置:
@Configuration
public class AIClientConfig {
/**
* 配置并创建一个ChatMemoryRepository bean实例
*
* @param jdbcTemplate JDBC模板对象,用于与数据库进行交互
* @return ChatMemoryRepository实例,用于存储聊天记录
*/
@Bean
public ChatMemoryRepository getChatMemoryRepository(JdbcTemplate jdbcTemplate) {
return JdbcChatMemoryRepository.builder()
.jdbcTemplate(jdbcTemplate)
//这里添加的是MySQL实现的聊天记忆仓库
.dialect(new MysqlChatMemoryRepositoryDialect())
.build();
}
/**
* 配置并创建一个ChatMemory bean实例
* 该实例用于管理聊天消息的记忆,确保对话的连贯性
*
* @return ChatMemory实例,用于消息记忆管理
*/
@Bean
public ChatMemory getChatMemory(ChatMemoryRepository jdbcChatMemoryRepository) {
// 创建一个MessageWindowChatMemory实例,最多保存100条消息
return MessageWindowChatMemory.builder()
.chatMemoryRepository(jdbcChatMemoryRepository)
.maxMessages(100).build();
}
/**
* 配置并创建一个ChatClient实例
*
* @param model 用于聊天客户端的模型,决定了客户端的响应行为和风格
* @param chatMemory 聊天记忆对象,使得客户端能够根据之前的对话内容进行有上下文的响应
* @return ChatClient实例,用于与用户进行个性化和有记忆的对话
*/
@Bean
public ChatClient gptChatClient(OpenAiChatModel model, ChatMemory chatMemory) {
// 创建ChatClient实例,使用指定的模型和系统默认设置
return ChatClient
.builder(model)
.defaultSystem("你的名字叫小周,用可爱的语句回答问题")
.defaultAdvisors(new SimpleLoggerAdvisor(), MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
}
}
`
###问题产生的原因:
springai官方提供的MySQL聊天消息仓库实现的getSelectMessagesSql()方法返回的SQL语句需要的参数有2个,一个是conversation_id,一个是获取消息的条数,即limit关键字后面的部分。
但在JdbcChatMemoryRepository 、JdbcTemplate里面调用的时候只给了一个参数
JdbcChatMemoryRepository:
JdbcTemplate:

由于参数不匹配,就会抛出 BadSqlGrammarException 异常:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT content, type FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ? ORDER BY timestamp` DESC LIMIT ?]
。。。。
Caused by: java.sql.SQLException: No value specified for parameter 2
`
###官方回应:目前springai官方仓库已经发现该问题,可能在后续的版本中修复:

补充,如果自定义 ChatMemoryRepositoryDialect,然后在ChatClient指定数据库的方言,还是会抛出同样的异常,原因在于通过配置文件使用 JDBC URL 时,springai会从JDBC URL 中自动选择对应的数据库,然后选择对应的 ChatMemoryRepository,官方文档描述如下:
使用 JdbcChatMemoryRepositoryDialect.from(DataSource) 时,可以从 JDBC URL 自动检测正确的方言。您可以通过实现 JdbcChatMemoryRepositoryDialect 接口来扩展对其他数据库的支持。
###自定义ChatMemoryRepository过程:
` public class CustomChatMemoryRepositoryDialect implements JdbcChatMemoryRepositoryDialect { private static final int DEFAULT_MAX_MESSAGES = 50;
@Override
public String getSelectMessagesSql() {
return "SELECT message_text, message_type FROM chat_memory WHERE conversation_id = ? ORDER BY timestamp DESC LIMIT " + DEFAULT_MAX_MESSAGES;
}
@Override
public String getInsertMessageSql() {
return "INSERT INTO chat_memory (id, conversation_id, message_text, message_type, timestamp) VALUES (?, ?, ?, ?, ?)";
}
@Override
public String getDeleteMessagesSql() {
return "DELETE FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ?";
}
@Override
public String getSelectConversationIdsSql() {
return "SELECT DISTINCT conversation_id FROM SPRING_AI_CHAT_MEMORY";
}
}
/**
* 配置并创建一个ChatMemoryRepository bean实例
*
* @param jdbcTemplate JDBC模板对象,用于与数据库进行交互
* @return ChatMemoryRepository实例,用于存储聊天记录
*/
@Bean
public ChatMemoryRepository getChatMemoryRepository(JdbcTemplate jdbcTemplate) {
return JdbcChatMemoryRepository.builder()
.jdbcTemplate(jdbcTemplate)
//此处使用自定义数据库
.dialect(new CustomChatMemoryRepositoryDialect())
.build();
}
`
结语:以上就是使用springai中MySQL作为消息持久化仓库有可能产生的问题,如果大家在使用springai的过程中遇到了其他问题,欢迎在评论区补充!
本文由博客一文多发平台 OpenWrite 发布!