feat(ai): 集成多种大模型并支持会话记忆功能
- 新增 Ollama、智谱 AI 和 OpenAI 大模型接入配置- 实现基于 ChatMemory 的会话上下文管理 - 添加流式输出接口以提升响应体验 - 更新加密工具类密钥及测试数据 - 引入多个 AI 控制器用于不同模型的服务调用 - 在 pom.xml 中添加相关依赖项以支持多模型集成
This commit is contained in:
17
pom.xml
17
pom.xml
@@ -35,6 +35,23 @@
|
|||||||
<groupId>org.springframework.ai</groupId>
|
<groupId>org.springframework.ai</groupId>
|
||||||
<artifactId>spring-ai-starter-model-deepseek</artifactId>
|
<artifactId>spring-ai-starter-model-deepseek</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Ollama -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-starter-model-ollama</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- 智谱AI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- OpenAI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-starter-model-openai</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
package com.hanserwei.airobot.config;
|
package com.hanserwei.airobot.config;
|
||||||
|
|
||||||
import com.hanserwei.airobot.advisor.MyLoggerAdvisor;
|
import com.hanserwei.airobot.advisor.MyLoggerAdvisor;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.ai.chat.client.ChatClient;
|
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.client.advisor.SimpleLoggerAdvisor;
|
||||||
|
import org.springframework.ai.chat.memory.ChatMemory;
|
||||||
import org.springframework.ai.deepseek.DeepSeekChatModel;
|
import org.springframework.ai.deepseek.DeepSeekChatModel;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ChatClientConfig {
|
public class ChatClientConfig {
|
||||||
|
@Resource
|
||||||
|
private ChatMemory chatMemory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化 ChatClient 客户端
|
* 初始化 ChatClient 客户端
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.hanserwei.airobot.config;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.ai.chat.memory.ChatMemory;
|
||||||
|
import org.springframework.ai.chat.memory.ChatMemoryRepository;
|
||||||
|
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ChatMemoryConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记忆存储
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ChatMemoryRepository chatMemoryRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化一个 ChatMemory 实例,并注入到 Spring 容器中
|
||||||
|
* @return ChatMemory
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public ChatMemory chatMemory() {
|
||||||
|
return MessageWindowChatMemory.builder()
|
||||||
|
.maxMessages(50) // 最大消息窗口为 50,默认值为 20
|
||||||
|
.chatMemoryRepository(chatMemoryRepository) // 记忆存储
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.hanserwei.airobot.controller;
|
|||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.ai.chat.client.ChatClient;
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
|
import org.springframework.ai.chat.memory.ChatMemory;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@@ -36,9 +37,11 @@ public class ChatClientController {
|
|||||||
* @return 对话结果
|
* @return 对话结果
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
|
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
|
||||||
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
|
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message,
|
||||||
|
@RequestParam(value = "chatId") String chatId) {
|
||||||
return chatClient.prompt()
|
return chatClient.prompt()
|
||||||
.user(message) // 提示词
|
.user(message) // 提示词
|
||||||
|
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
|
||||||
.stream() // 流式输出
|
.stream() // 流式输出
|
||||||
.content();
|
.content();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.hanserwei.airobot.controller;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.ai.chat.model.ChatResponse;
|
||||||
|
import org.springframework.ai.chat.prompt.Prompt;
|
||||||
|
import org.springframework.ai.ollama.OllamaChatModel;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v3/ai")
|
||||||
|
public class OllamaController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OllamaChatModel chatModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通对话
|
||||||
|
* @param message 对话输入内容
|
||||||
|
* @return 对话结果
|
||||||
|
*/
|
||||||
|
@GetMapping("/generate")
|
||||||
|
public String generate(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
|
||||||
|
// 构建提示词,调用大模型
|
||||||
|
ChatResponse chatResponse = chatModel.call(new Prompt(message));
|
||||||
|
|
||||||
|
// 响应回答内容
|
||||||
|
return chatResponse.getResult().getOutput().getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.hanserwei.airobot.controller;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.ai.chat.messages.UserMessage;
|
||||||
|
import org.springframework.ai.chat.model.Generation;
|
||||||
|
import org.springframework.ai.chat.prompt.Prompt;
|
||||||
|
import org.springframework.ai.openai.OpenAiChatModel;
|
||||||
|
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 reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v5/ai")
|
||||||
|
public class OpenAIController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OpenAiChatModel chatModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通对话
|
||||||
|
* @param message 对话输入内容
|
||||||
|
* @return 对话结果
|
||||||
|
*/
|
||||||
|
@GetMapping("/generate")
|
||||||
|
public String generate(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
|
||||||
|
// 一次性返回结果
|
||||||
|
return chatModel.call(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流式对话
|
||||||
|
* @param message 对话输入内容
|
||||||
|
* @return 对话结果
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
|
||||||
|
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
|
||||||
|
// 构建提示词
|
||||||
|
Prompt prompt = new Prompt(new UserMessage(message));
|
||||||
|
|
||||||
|
// 流式输出
|
||||||
|
return chatModel.stream(prompt)
|
||||||
|
.mapNotNull(chatResponse -> {
|
||||||
|
Generation generation = chatResponse.getResult();
|
||||||
|
return generation.getOutput().getText();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.hanserwei.airobot.controller;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.ai.chat.messages.UserMessage;
|
||||||
|
import org.springframework.ai.chat.prompt.Prompt;
|
||||||
|
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
|
||||||
|
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 reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v4/ai")
|
||||||
|
public class ZhiPuController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ZhiPuAiChatModel chatModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通对话
|
||||||
|
* @param message 对话输入内容
|
||||||
|
* @return 对话结果
|
||||||
|
*/
|
||||||
|
@GetMapping("/generate")
|
||||||
|
public String generate(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
|
||||||
|
// 一次性返回结果
|
||||||
|
return chatModel.call(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流式对话
|
||||||
|
* @param message 对话输入内容
|
||||||
|
* @return 对话结果
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
|
||||||
|
public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
|
||||||
|
// 构建提示词
|
||||||
|
Prompt prompt = new Prompt(new UserMessage(message));
|
||||||
|
|
||||||
|
// 流式输出
|
||||||
|
return chatModel.stream(prompt)
|
||||||
|
.mapNotNull(chatResponse -> chatResponse.getResult().getOutput().getText());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import org.jasypt.util.text.AES256TextEncryptor;
|
|||||||
public class EncryptorUtil {
|
public class EncryptorUtil {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
AES256TextEncryptor textEncryptor = new AES256TextEncryptor();
|
AES256TextEncryptor textEncryptor = new AES256TextEncryptor();
|
||||||
textEncryptor.setPassword("password");
|
textEncryptor.setPassword("hanserwei");
|
||||||
System.out.println(textEncryptor.encrypt("sk-xxxxxxxxxxxxxx"));
|
System.out.println(textEncryptor.encrypt("sk-QXBlsyIonybNTcG5tt5GvmMpg2WpdMLPTvU55TXrt9urWpL8"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,27 @@ spring:
|
|||||||
options:
|
options:
|
||||||
model: deepseek-chat # 使用哪个模型
|
model: deepseek-chat # 使用哪个模型
|
||||||
temperature: 0.8 # 温度值
|
temperature: 0.8 # 温度值
|
||||||
|
ollama:
|
||||||
|
base-url: http://localhost:11434 # Ollama 服务的访问地址, 11434 端口是 Ollama 默认的启动端口
|
||||||
|
chat:
|
||||||
|
options: # 模型参数
|
||||||
|
model: qwen3:14b # 指定 Ollama 使用的大模型名称,根据你实际安装的来,我运行的是 14b
|
||||||
|
temperature: 0.7 # 温度值
|
||||||
|
zhipuai:
|
||||||
|
base-url: https://open.bigmodel.cn/api/paas # 智谱 AI 的请求 URL, 可不填,默认值为 open.bigmodel.cn/api/paas
|
||||||
|
api-key: ENC(Rz1O0AygSzG3q4UrIpIPHRwFoTQXCUZkWZ54vNzl1kgdBkQECzCYa3LoOADM9NlGLlAwCKTMtkj0nd6cP98T59DohcKtzc3iYyiAoNRfH0rsiu483CpaCciyMwxCUi5O) # 填写智谱 AI 的 API Key, 该成你自己的
|
||||||
|
chat:
|
||||||
|
options: # 模型参数
|
||||||
|
model: GLM-4.6 # 模型名称,使用智谱 AI 哪个模型
|
||||||
|
temperature: 0.7 # 温度值
|
||||||
|
openai:
|
||||||
|
base-url: https://api.master-jsx.top # OpenAI 服务的访问地址,这里使用的第三方代理商:智增增
|
||||||
|
api-key: ENC(D6ETp0VBeDYXvM612dcoGkyHaGUcPuwOVuSLtL92TOCxydyMKXL7/VBndWjFkxAQP/AS7TeQeegla+Ny6TrLStwdJtd28mVhoyf2YsKuXIdRnKF/mv8/uZ0MpzMdv9YR) # 填写智增增的 API Key, 该成你自己的
|
||||||
|
chat:
|
||||||
|
options:
|
||||||
|
model: gpt-4o # 模型名称
|
||||||
|
temperature: 0.7 # 温度值
|
||||||
|
|
||||||
jasypt:
|
jasypt:
|
||||||
encryptor:
|
encryptor:
|
||||||
password: ${jasypt.encryptor.password}
|
password: ${jasypt.encryptor.password}
|
||||||
|
|||||||
Reference in New Issue
Block a user