Spring-AI-Alibaba 学习笔记-记忆功能(2)
记忆可以让Agent更好的记住之前的会话内容。对于AI Agent,记忆至关重要,因为它们能够记住先前的交互、从反馈中学习并适应用户的偏好。短期记忆让你的应用程序能够在单个线程或会话中记住先前的交互。注意:会话可以隔离同一个 Agent 实例中的多个不同交互,类似于电子邮件在单个对话中分组消息的方式。
·
概述
记忆可以让Agent更好的记住之前的会话内容。对于AI Agent,记忆至关重要,因为它们能够记住先前的交互、从反馈中学习并适应用户的偏好。
短期记忆让你的应用程序能够在单个线程或会话中记住先前的交互。
注意:会话可以隔离同一个 Agent 实例中的多个不同交互,类似于电子邮件在单个对话中分组消息的方式。
目标
-
通过spring-ai-alibaba完成对会话的记忆功能
-
支持多种记忆(redis,MySQL)
工程
-
依赖
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-jdbc</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.49.1.0</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
<version>1.1.0</version>
</dependency>
-
application.yml
spring:
application:
name: spring-ai-alibaba-exmple
ai:
dashscope:
api-key: ${DASH_SCOPE_API_KEY}
memory:
redis:
host: localhost
port: 6379
password: root
timeout: 5000
chat:
memory:
repository:
jdbc:
mysql:
jdbc-url: jdbc:mysql://localhost:3306/saa_data_agent?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&tinyInt1isBit=false&allowLoadLocalInfile=true&allowLocalInfile=true&allowUrl
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
enabled: true
server:
port: 8080
-
代码和工程结构
1.MemoryConfig.java
package com.xzgzs.ai.memory.config;
import com.alibaba.cloud.ai.memory.jdbc.MysqlChatMemoryRepository;
import com.alibaba.cloud.ai.memory.redis.RedissonRedisChatMemoryRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
/**
* @author wangyf
* @date 2026/1/8
*/
@Configuration
public class MemoryConfig {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MemoryConfig.class);
@Value("${spring.ai.memory.redis.host}")
private String redisHost;
@Value("${spring.ai.memory.redis.port}")
private int redisPort;
@Value("${spring.ai.memory.redis.password}")
private String redisPassword;
@Value("${spring.ai.memory.redis.timeout}")
private int redisTimeout;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.jdbc-url}")
private String mysqlJdbcUrl;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.username}")
private String mysqlUsername;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.password}")
private String mysqlPassword;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.driver-class-name}")
private String mysqlDriverClassName;
@Bean
public MysqlChatMemoryRepository mysqlChatMemoryRepository() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(mysqlJdbcUrl);
dataSource.setUsername(mysqlUsername);
dataSource.setPassword(mysqlPassword);
dataSource.setDriverClassName(mysqlDriverClassName);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return MysqlChatMemoryRepository.mysqlBuilder()
.jdbcTemplate(jdbcTemplate).build();
}
@Bean
public RedissonRedisChatMemoryRepository redissonRedisChatMemoryRepository() {
log.info("redisHost:{},redisPort:{},redisPassword:{},redisTimeout:{}", redisHost, redisPort, redisPassword, redisTimeout);
return RedissonRedisChatMemoryRepository.builder()
.host(redisHost)
.port(redisPort)
.password(redisPassword)
.timeout(redisTimeout)
.build();
}
}
InMemoryController.java
package com.xzgzs.ai.memory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;
/**
* @author wangyf
* @date 2026/1/7
*/
@RestController
@RequestMapping("/memory/in")
public class InMemoryController {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(InMemoryController.class);
private final ChatClient chatClient;
private final InMemoryChatMemoryRepository chatMemoryRepository = new InMemoryChatMemoryRepository();
private final int MAX_MESSAGES = 100;
private final MessageWindowChatMemory messageWindowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();
public InMemoryController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
.build()
)
.build();
}
@GetMapping("/call")
public String call(@RequestParam(value = "query", defaultValue = "你好,我是北京市最帅的程序员 best_coder_cn") String query,
@RequestParam(value = "conversation_id", defaultValue = "handsome") String conversationId
) {
return chatClient.prompt(query)
.advisors(
a -> a.param(CONVERSATION_ID, conversationId)
)
.call().content();
}
@GetMapping("/messages")
public List<Message> messages(@RequestParam(value = "conversation_id", defaultValue = "best_coder_cn") String conversationId) {
return messageWindowChatMemory.get(conversationId);
}
}
MysqlMemoryController.java
@RestController
@RequestMapping("/memory/mysql")
public class MysqlMemoryController {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MysqlMemoryController.class);
private final ChatClient chatClient;
private final int MAX_MESSAGES = 100;
private final MessageWindowChatMemory messageWindowChatMemory;
public MysqlMemoryController(ChatClient.Builder builder, MysqlChatMemoryRepository chatMemoryRepository) {
this.messageWindowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();
this.chatClient = builder.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
.build()
)
.build();
}
@RequestMapping("/call")
public String call(@RequestParam(value = "query", defaultValue = "你好,我是北京市最帅的程序员 best_coder_cn") String query,
@RequestParam(value = "conversation_id", defaultValue = "best_coder_cn") String conversationId) {
return chatClient.prompt(query).advisors(
a -> a.param(CONVERSATION_ID, conversationId)
)
.call().content();
}
@RequestMapping("/messages")
public List<Message> messages(@RequestParam(value = "conversation_id", defaultValue = "best_coder_cn") String conversationId) {
return messageWindowChatMemory.get(conversationId);
}
}
RedisMemoryController.java
@RestController
@RequestMapping("/memory/redis")
public class RedisMemoryController {
private final ChatClient chatClient;
private final MessageWindowChatMemory messageWindowChatMemory;
private final int MAX_MESSAGES = 100;
public RedisMemoryController(ChatClient.Builder builder, RedissonRedisChatMemoryRepository redissonRedisChatMemoryRepository) {
this.messageWindowChatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(redissonRedisChatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();
this.chatClient = builder.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory).build()
)
.build();
}
@GetMapping("/call")
public String call(@RequestParam(value = "query", defaultValue = "你好,我是北京市最帅的程序员 best_coder_cn") String query,
@RequestParam(value = "conversation_id", defaultValue = "best_coder_cn") String conversationId) {
return chatClient.prompt(query)
.advisors(
a -> a.param(CONVERSATION_ID, conversationId)
)
.call()
.content();
}
@GetMapping("/messages")
public List<Message> messages(@RequestParam(value = "conversation_id", defaultValue = "best_coder_cn") String conversationId) {
return messageWindowChatMemory.get(conversationId);
}
更多推荐



所有评论(0)