Spring AI 会话记忆多存储与提示词工程
一、基于 Ollama 本地部署的调用
首先下载 Ollama 到本地运行。
1. 引入依赖
推荐使用 Spring AI 1.x 系列(稳定正式版):
- 适配 Spring Boot:核心适配 3.2.x 系列
- 底层 Spring Framework:6.1.x/6.0.x
- JDK 版本要求:最低 JDK 17
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.10</version>
</parent>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
2. 配置模型
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
model: deepseek-r1:1.5b
3. 配置客户端
package com.ax.ai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CommonConfiguration {
@Bean
public ChatClient chatClient(OllamaChatModel model) {
return ChatClient.builder(model)
.defaultSystem("你是一个网安程序员,你的名字叫超哥,请你以超哥的身份和语气回答我的问题")
.build();
}
}
二、使用官方 API 进行调用
修改配置连接阿里云百炼或 OpenAI 兼容接口。
spring:
ai:
openai:
api-key: YOUR_API_KEY
base-url: https://dashscope.aliyuncs.com/compatible-mode
chat:
options:
model: qwen3-max
temperature: 0.7
配置类需注入 ChatModel 接口而非具体实现。
三、拓展功能
1. Spring AI 会话记忆
大模型本身不具备记忆功能,需将历史对话内容作为上下文发送。支持以下存储方式:
(1) JVM 内存存储
默认实现,适合本地开发调试。
@Bean
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
(2) 关系型数据库存储
通过自定义实现持久化到 MySQL/PostgreSQL。
@Bean
public ChatMemory chatMemory(JdbcTemplate jdbcTemplate) {
return new CustomJdbcChatMemory(jdbcTemplate);
}
(3) Redis 存储
- 低版本 Redis:普通聊天记忆存储(文本)。
- Redis 7.0+(带向量检索):可存储高维向量,用于 RAG/长会话。
2. 数据库表结构
CREATE TABLE IF NOT EXISTS ai_chat_memory (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
conversation_id VARCHAR(100) NOT NULL,
role VARCHAR(20) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
type VARCHAR(50) NOT NULL DEFAULT 'default'
);
3. 自定义 JDBC 记忆存储
实现 ChatMemory 接口,利用 ThreadLocal 隔离不同业务场景的数据。
package com.ax.ai.memory;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.*;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class CustomJdbcChatMemory implements ChatMemory {
private final JdbcTemplate jdbcTemplate;
private static final ThreadLocal<String> CURRENT_TYPE = ThreadLocal.withInitial(() -> "default");
public void setConversationType(String type) { CURRENT_TYPE.set(type); }
public void clearConversationType() { CURRENT_TYPE.remove(); }
@Override
public void add(String conversationId, List<Message> messages) {
String type = CURRENT_TYPE.get();
String sql = "INSERT INTO ai_chat_memory (conversation_id, type, role, content) VALUES (?, ?, ?, ?)";
for (Message message : messages) {
jdbcTemplate.update(sql, conversationId, type,
message.getMessageType().getValue(), message.getText());
}
}
@Override
public List<Message> get(String conversationId) {
String type = CURRENT_TYPE.get();
;
}
}
4. 提示词工程
定义系统常量控制角色行为。
public final class SystemConstants {
public static final String GAME_SYSTEM_PROMPT = "你需要根据以下任务中的描述进行角色扮演...";
}
在配置类中绑定专用 ChatClient。
@Bean
public ChatClient gameChatClient(ChatClient.Builder builder, ChatMemory chatMemory) {
MessageChatMemoryAdvisor advisor = MessageChatMemoryAdvisor.builder(chatMemory).build();
return builder
.defaultSystem(SystemConstants.GAME_SYSTEM_PROMPT)
.defaultAdvisors(advisor)
.build();
}
四、项目结构与代码
1. pom.xml 依赖配置
核心依赖包括 spring-boot-starter-web, spring-boot-starter-jdbc, spring-ai-starter-model-openai。
2. application.yaml 参数信息
配置数据源及 AI 模型参数。
3. Controller 层请求处理
通用对话接口与游戏接口分离,确保线程安全。
@RestController
@RequestMapping("/ai")
public class GameController {
private final ChatClient gameChatClient;
private final CustomJdbcChatMemory customChatMemory;
@RequestMapping(value = "/game", produces = "text/html;charset=utf-8")
public String chat(@RequestParam String prompt, @RequestParam String chatId) {
try {
customChatMemory.setConversationType("game");
return gameChatClient.prompt()
.user(prompt)
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
.call().content();
} finally {
customChatMemory.clearConversationType();
}
}
}
4. 全局日志切面
记录 AI 交互耗时与输入输出摘要。
@Aspect
@Component
@Slf4j
public class AiLogAspect {
@Around("execution(* com.ax.ai.controller..*.*(..))")
public Object logAiInteraction(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
log.info("AI_REQ [{}ms] | {}", duration, result);
return result;
}
}
5. 跨域配置
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS");
}
}


