springAI DeepSeek 对话机器人 会话记忆、会话历史 20250623
######前端代码
######后端代码 git
1、Ollama

参考https://www.cnblogs.com/smallfa/p/18906777
2、pom.xml

<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0-M7</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

3、Configuration
package com.dsai.dsai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Administrator
*/
@Configuration
public class CommonConfiguration {
@Bean //配置ChatMemory实例 会话记忆 放在内存中
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
@Bean
public ChatClient chatClient(OllamaChatModel model) {
//创建ChatClient工厂实例
return ChatClient.builder(model)
.defaultSystem("你是一个热心、可爱的智能助手、你的名字叫小团团,请以小团团的身份和语气回答问题")
.defaultAdvisors(
//配置日志Advisor
new SimpleLoggerAdvisor(),
//配置会话记忆Advisor
new MessageChatMemoryAdvisor(chatMemory)
)
//创建ChatClient实例
.build();
}
}
注:SimpleLoggerAdvisor

与前端交互跨域
package com.dsai.dsai.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").
allowedOrigins("*").
allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").
allowedHeaders("*");
}
}
4、application.yaml
spring:
application:
name: DS-AI
ai:
ollama:
base-url: http://192.168.177.128:11434
chat:
model: deepseek-r1:1.5b
#会话日志
logging:
level:
org.springframework.ai.chat.client.advisor: debug
com.dsai.dsai: debug


5、Controller
package com.dsai.dsai.controller;
import com.dsai.dsai.repository.ChatHistoryRespository;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
/**
* @author Administrator
*/
@RestController
@RequestMapping("/api/ai")
public class ChatController {
private final ChatClient chatClient;
private final ChatHistoryRespository chatHistoryRespository;
// 手动编写构造器
public ChatController(ChatClient chatClient, ChatHistoryRespository chatHistoryRespository) {
this.chatClient = chatClient;
this.chatHistoryRespository = chatHistoryRespository;
}
@RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
public Flux<String> chat(String prompt,String chatId) {
//1、保存会话ID
chatHistoryRespository.save("chat", chatId);
//2、请求模型
return chatClient.prompt()
.user(prompt)
//传递会话ID,不同的会话ID,会话记忆会不同
.advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY,chatId))
.stream()
.content();
}
}
package com.dsai.dsai.controller;
import com.dsai.dsai.entity.vo.MessageVO;
import com.dsai.dsai.repository.ChatHistoryRespository;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/ai")
public class ChatHistoryController {
private final ChatHistoryRespository chatHistoryRespository;
private final ChatMemory chatMemory;
public ChatHistoryController(ChatHistoryRespository chatHistoryRespository, ChatMemory chatMemory) {
this.chatHistoryRespository = chatHistoryRespository;
this.chatMemory = chatMemory;
}
@GetMapping("/history/{type}")
public List<String> getChatIds(@PathVariable("type") String type){
return chatHistoryRespository.getChatIds(type);
}
@GetMapping("/history/{type}/{chatId}")
public List<MessageVO> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId){
List<Message> messages = chatMemory.get(chatId,Integer.MAX_VALUE);
if(messages==null) {
return List.of();
}
return messages.stream().map(MessageVO::new).toList(); }
}



6、实体MessageVO package com.dsai.dsai.entity.vo;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.Message;
/**
* @author Administrator
*/
public class MessageVO {
private String role;
private String content;
MessageVO() {
}
public MessageVO(Message message) {
switch (message.getMessageType()) {
case USER:
this.role = "user";
break;
case ASSISTANT:
this.role = "assistant";
break;
default:
this.role = "";
break;
}
this.content = message.getText();
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
7、repository
package com.dsai.dsai.repository;
import java.util.List;
public interface ChatHistoryRespository {
/**
* 保存会话记录
* @param type 业务类型 如: chat, service,pdf
* @param chatId 会话id
*/
void save(String type, String chatId);
/**
* 获取会话id列表
* @param type 业务类型 如: chat, service,pdf
* @return 会话id列表
*/
List<String> getChatIds(String type);
}
package com.dsai.dsai.repository;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.resource.ResourceUrlProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class InMemoryChatHistoryRepository implements ChatHistoryRespository{
private final Map<String,List<String>> chatHistory= new HashMap<>();
private final ResourceUrlProvider mvcResourceUrlProvider;
public InMemoryChatHistoryRepository(ResourceUrlProvider mvcResourceUrlProvider) {
this.mvcResourceUrlProvider = mvcResourceUrlProvider;
}
@Override
public void save(String type, String chatId) {
/* if(!chatHistory.containsKey(type)){
chatHistory.put(type, new ArrayList<>());
}
List<String> chatIds = chatHistory.get(type);*/
List<String> chatIds=chatHistory.computeIfAbsent(type, k -> new ArrayList<>());
if(chatIds.contains(chatId)){
return;
}
chatIds.add(chatId);
}
@Override
public List<String> getChatIds(String type) {
/*List<String> chatIds=chatHistory.get(type);
return chatIds==null? new ArrayList<>():chatIds;*/
return chatHistory.getOrDefault(type, List.of());
}
}
8、控制台日志

9、前端


前端记忆 "messageType" : "ASSISTANT"



9.1 与模型交互

9.2 会话历史列表




浙公网安备 33010602011771号