From bfbfdbc90dbc5ba744d21d20847862ace130e6c8 Mon Sep 17 00:00:00 2001
From: Hanserwei <2628273921@qq.com>
Date: Tue, 21 Oct 2025 22:33:19 +0800
Subject: [PATCH] =?UTF-8?q?feat(ai):=20=E9=9B=86=E6=88=90=E5=A4=9A?=
=?UTF-8?q?=E7=A7=8D=E5=A4=A7=E6=A8=A1=E5=9E=8B=E5=B9=B6=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E4=BC=9A=E8=AF=9D=E8=AE=B0=E5=BF=86=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 Ollama、智谱 AI 和 OpenAI 大模型接入配置- 实现基于 ChatMemory 的会话上下文管理
- 添加流式输出接口以提升响应体验
- 更新加密工具类密钥及测试数据
- 引入多个 AI 控制器用于不同模型的服务调用
- 在 pom.xml 中添加相关依赖项以支持多模型集成
---
pom.xml | 17 ++++++
.../airobot/config/ChatClientConfig.java | 5 ++
.../airobot/config/ChatMemoryConfig.java | 30 +++++++++++
.../controller/ChatClientController.java | 5 +-
.../airobot/controller/OllamaController.java | 33 ++++++++++++
.../airobot/controller/OpenAIController.java | 53 +++++++++++++++++++
.../airobot/controller/ZhiPuController.java | 47 ++++++++++++++++
.../airobot/utils/EncryptorUtil.java | 4 +-
src/main/resources/application.yml | 21 ++++++++
9 files changed, 212 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java
create mode 100644 src/main/java/com/hanserwei/airobot/controller/OllamaController.java
create mode 100644 src/main/java/com/hanserwei/airobot/controller/OpenAIController.java
create mode 100644 src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java
diff --git a/pom.xml b/pom.xml
index ca6086c..1d22c4c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,6 +35,23 @@
org.springframework.ai
spring-ai-starter-model-deepseek
+
+
+ org.springframework.ai
+ spring-ai-starter-model-ollama
+
+
+
+ org.springframework.ai
+ spring-ai-starter-model-zhipuai
+
+
+
+ org.springframework.ai
+ spring-ai-starter-model-openai
+
+
+
org.springframework.boot
diff --git a/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java b/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java
index 5c10c5c..b72373b 100644
--- a/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java
+++ b/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java
@@ -1,14 +1,19 @@
package com.hanserwei.airobot.config;
import com.hanserwei.airobot.advisor.MyLoggerAdvisor;
+import jakarta.annotation.Resource;
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.deepseek.DeepSeekChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
+ @Resource
+ private ChatMemory chatMemory;
/**
* 初始化 ChatClient 客户端
diff --git a/src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java b/src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java
new file mode 100644
index 0000000..d4f00a5
--- /dev/null
+++ b/src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java
@@ -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();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java b/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java
index 602d7b7..f240484 100644
--- a/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java
+++ b/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java
@@ -2,6 +2,7 @@ package com.hanserwei.airobot.controller;
import jakarta.annotation.Resource;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@@ -36,9 +37,11 @@ public class ChatClientController {
* @return 对话结果
*/
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
- public Flux generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
+ public Flux generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message,
+ @RequestParam(value = "chatId") String chatId) {
return chatClient.prompt()
.user(message) // 提示词
+ .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
.stream() // 流式输出
.content();
diff --git a/src/main/java/com/hanserwei/airobot/controller/OllamaController.java b/src/main/java/com/hanserwei/airobot/controller/OllamaController.java
new file mode 100644
index 0000000..0334e66
--- /dev/null
+++ b/src/main/java/com/hanserwei/airobot/controller/OllamaController.java
@@ -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();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/hanserwei/airobot/controller/OpenAIController.java b/src/main/java/com/hanserwei/airobot/controller/OpenAIController.java
new file mode 100644
index 0000000..19157ff
--- /dev/null
+++ b/src/main/java/com/hanserwei/airobot/controller/OpenAIController.java
@@ -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 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();
+ });
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java b/src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java
new file mode 100644
index 0000000..3a420f2
--- /dev/null
+++ b/src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java
@@ -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 generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) {
+ // 构建提示词
+ Prompt prompt = new Prompt(new UserMessage(message));
+
+ // 流式输出
+ return chatModel.stream(prompt)
+ .mapNotNull(chatResponse -> chatResponse.getResult().getOutput().getText());
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java b/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java
index 7bf6b8d..e3909c3 100644
--- a/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java
+++ b/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java
@@ -5,7 +5,7 @@ import org.jasypt.util.text.AES256TextEncryptor;
public class EncryptorUtil {
public static void main(String[] args) {
AES256TextEncryptor textEncryptor = new AES256TextEncryptor();
- textEncryptor.setPassword("password");
- System.out.println(textEncryptor.encrypt("sk-xxxxxxxxxxxxxx"));
+ textEncryptor.setPassword("hanserwei");
+ System.out.println(textEncryptor.encrypt("sk-QXBlsyIonybNTcG5tt5GvmMpg2WpdMLPTvU55TXrt9urWpL8"));
}
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index c3f06da..235ec2e 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -10,6 +10,27 @@ spring:
options:
model: deepseek-chat # 使用哪个模型
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:
encryptor:
password: ${jasypt.encryptor.password}