基于SpringAI实现会话记忆和对话内容持久化的AI对话服务

如何为自己的JAVA项目集成AI对话服务(含prompt工程、对话持久化至MongoDB、会话上下文记忆)

1. 总体概览

项目地址

亮点:

  • 实现基于Spring AI的大模型对话服务
  • 构建面向医疗问诊场景的 Prompt 工程体系
  • 支持流式响应与多轮会话上下文记忆
  • 将完整对话内容持久化到 MongoDB 数据库

核心技术栈:

能力 技术
大模型调用 Spring AI / OpenAI 兼容模式
Prompt 工程 Spring AI Prompt API
流式输出 WebFlux + Flux
会话记忆 Spring AI ChatMemory
持久化 MongoDB(存储用户、AI、系统消息)
检索增强 Milvus VectorStore(已集成)

2. Spring AI 大模型对话服务实现

2.1 大模型配置

application.yml:

1
2
3
4
5
6
7
8
spring:
ai:
openai:
base-url: https://dashscope.aliyuncs.com/compatible-mode
api-key: xxx
chat:
options:
model: qwen-vl-max # 多模态模型

通过 OpenAI 兼容模式直接调用 Qwen 系列模型,Spring AI 会自动组合成 ChatModel Bean。

2.2 ChatClient 装配(对话客户端)

核心配置类:AiConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
@Bean
public ChatClient chatClient() {
MessageChatMemoryAdvisor messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory);

return ChatClient.builder(chatModel)
.defaultAdvisors(
messageChatMemoryAdvisor, // 会话记忆
new SimpleLoggerAdvisor(), // 日志
new QuestionAnswerAdvisor(vectorStore) // RAG,可选
)
.build();
}

它做了三件事:

  1. 绑定大模型 chatModel
  2. 给所有对话默认挂载对话记忆 MessageChatMemoryAdvisor
  3. 集成 RAG(Milvus)语义检索能力

因此,在任何 Controller 里调用 chatClient 时,都会自动带上记忆能力。

3. 构建医疗场景 Prompt 工程体系

在 Controller 层,为医疗场景定义了系统级 Prompt:

1
.system("你是一个医疗问诊助手,你会根据用户的问题,提供相关的医疗咨询。拒绝回答非医疗相关的问题。")

这相当于每个对话的「角色设定」:

  • 限制 AI 回答范围
  • 让 AI 遵循医疗问诊风格进行回复
  • 自动过滤不相关问题

4. Spring AI 流式输出(Flux 流式推送)

Controller:

1
2
3
4
5
6
7
8
9
10
@GetMapping("/chat")
public Flux<String> chat(@RequestParam("message") String message) {
return chatClient
.prompt()
.system("你是一个医疗问诊助手...")
.user(message)
.advisors(a -> a.param(ChatMemory.DEFAULT_CONVERSATION_ID, conversationId))
.stream()
.content();
}

A. .stream() 的作用

启动大模型的 Streaming 模式(Server-Sent Events),返回类型为 Flux<String>,可让前端实时显示 Token。

B. 使用advisors绑定会话ID,实现对话记忆功能

1
.advisors(a -> a.param(ChatMemory.DEFAULT_CONVERSATION_ID, conversationId))

它将当前对话请求绑定到指定的会话ID(conversationId),从而让你的多轮对话记忆生效

5. 多轮会话记忆实现 + 对话内容持久化到 MongoDB

Spring AI 会话记忆的机制:
ChatClient → MessageChatMemoryAdvisor → ChatMemory

5.1 定义存入MongoDB的Msg

1
2
3
4
5
6
7
@Document("msg")
public class Msg {
private String conversationId;
private String text;
private Date date;
private String type;
}

每一条对话都会自动生成:

字段 内容
conversationId 同一个会话的唯一 ID
text 聊天文本
type user / assistant / system
date 时间戳

5.2 新消息写入 MongoDB

1
2
3
4
5
6
7
@Override
public void add(String conversationId, List<Message> messages) {
for (Message message : messages) {
Msg msg = new Msg(conversationId, message);
msgRepository.save(msg);
}
}
  • Message(user/assistant/system)
  • 持久化为 Msg
  • 存入 MongoDB “msg” 集合
1
2
3
4
5
6
{
"conversationId": "sessionId-xxxx",
"text": "发烧怎么办?",
"type": "user",
"date": "2025-11-25"
}

5.3 ChatClient 查询历史记忆

当再次调用对话 API 时,Spring AI 会自动调用:

1
2
@Override
public List<Message> get(String conversationId, int lastN)

读取 MongoDB 中该会话 ID 的历史消息:

1
2
query.addCriteria(Criteria.where("conversationId").is(id)).limit(lastN);
return mongoTemplate.find(query, Msg.class);

并将其转换回 Spring AI 的 Message:

1
case "user" -> new UserMessage(msg.getText());

这意味着所有历史聊天都会再次被送入大模型,实现:

  • 上下文理解
  • 多轮连续对话