From 62cf0ed5484f07e79c2c6d91d156a1ec11010360 Mon Sep 17 00:00:00 2001 From: hanserwei Date: Tue, 21 Oct 2025 14:04:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(ai):=20=E5=88=87=E6=8D=A2=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=A8=A1=E5=9E=8B=E5=B9=B6=E6=96=B0=E5=A2=9E=E6=B5=81?= =?UTF-8?q?=E5=BC=8F=E5=AF=B9=E8=AF=9D=E6=8E=A5=E5=8F=A3-=20=E5=B0=86?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E6=A8=A1=E5=9E=8B=E4=BB=8E=20deepseek-chat?= =?UTF-8?q?=20=E5=88=87=E6=8D=A2=E4=B8=BA=20deepseek-reasoner=20-=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20/ai/generateStream=20=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B5=81=E5=BC=8F=E5=AF=B9=E8=AF=9D=E8=BE=93?= =?UTF-8?q?=E5=87=BA=20-=20=E6=96=B0=E5=A2=9E=20/v1/ai/generateStream=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81=20reasoning=20=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E6=B5=81=E5=BC=8F=E8=BE=93=E5=87=BA=20-=20=E5=BC=95?= =?UTF-8?q?=E5=85=A5=20commons-lang3=20=E4=BE=9D=E8=B5=96=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=A4=84=E7=90=86-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Flux=20=E6=94=AF=E6=8C=81=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=BC=82=E6=AD=A5=E6=B5=81=E5=BC=8F=E5=93=8D=E5=BA=94?= =?UTF-8?q?=20-=20=E5=AE=8C=E5=96=84=20DeepSeekAssistantMessage=20?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E5=8C=BA=E5=88=86?= =?UTF-8?q?=E6=8E=A8=E7=90=86=E5=86=85=E5=AE=B9=E4=B8=8E=E6=9C=80=E7=BB=88?= =?UTF-8?q?=E5=9B=9E=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 +++ .../controller/DeepSeekChatController.java | 18 +++++++ .../controller/DeepSeekR1ChatController.java | 49 +++++++++++++++++++ src/main/resources/application.yml | 2 +- 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/hanserwei/airobot/controller/DeepSeekR1ChatController.java diff --git a/pom.xml b/pom.xml index 462eee0..d93520b 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ 21 1.0.3 + 3.19.0 @@ -39,6 +40,12 @@ spring-boot-starter-test test + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + diff --git a/src/main/java/com/hanserwei/airobot/controller/DeepSeekChatController.java b/src/main/java/com/hanserwei/airobot/controller/DeepSeekChatController.java index 12b66fb..5e1ab0e 100644 --- a/src/main/java/com/hanserwei/airobot/controller/DeepSeekChatController.java +++ b/src/main/java/com/hanserwei/airobot/controller/DeepSeekChatController.java @@ -1,11 +1,14 @@ 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.deepseek.DeepSeekChatModel; 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("/ai") @@ -25,4 +28,19 @@ public class DeepSeekChatController { 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/controller/DeepSeekR1ChatController.java b/src/main/java/com/hanserwei/airobot/controller/DeepSeekR1ChatController.java new file mode 100644 index 0000000..ff4ced5 --- /dev/null +++ b/src/main/java/com/hanserwei/airobot/controller/DeepSeekR1ChatController.java @@ -0,0 +1,49 @@ +package com.hanserwei.airobot.controller; + +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.deepseek.DeepSeekAssistantMessage; +import org.springframework.ai.deepseek.DeepSeekChatModel; +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("/v1/ai") +public class DeepSeekR1ChatController { + + @Resource + private DeepSeekChatModel chatModel; + + /** + * 流式对话 + * @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 -> { + // 获取响应内容 + DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) chatResponse.getResult().getOutput(); + // 推理内容 + String reasoningContent = deepSeekAssistantMessage.getReasoningContent(); + // 推理结束后的正式回答 + String text = deepSeekAssistantMessage.getText(); + + // 若推理内容有值,则响应推理内容,否则,说明推理结束了,响应正式回答 + return StringUtils.isNotBlank(reasoningContent) ? reasoningContent : text; + }); + + + + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 04a8fe6..3be31b2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,7 +8,7 @@ spring: base-url: https://api.deepseek.com # DeepSeek 的请求 URL, 可不填,默认值为 api.deepseek.com chat: options: - model: deepseek-chat # 使用哪个模型 + model: deepseek-reasoner # 使用哪个模型 temperature: 0.8 # 温度值 jasypt: encryptor: