SpringAI是一个AI工程领域的应用程序框架,对OpenAI、DeepSeek等主流 AI 大模型提供了支持。
x1<!-- 继承SpringBoot父工程:spring-boot-starter-parent -->
2<parent>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-parent</artifactId>
5 <version>3.4.3</version>
6</parent>
7
8<!-- 使用JDK17+版本编译 -->
9<properties>
10 <maven.compiler.source>17</maven.compiler.source>
11 <maven.compiler.target>17</maven.compiler.target>
12 <spring-ai.version>1.0.0-M5</spring-ai.version>
13 <spring-ai-alibaba.version>1.0.0-M6.1</spring-ai-alibaba.version>
14</properties>
15
16<!-- 依赖 -->
17<dependencies>
18 <!-- SpringBoot Web模块 -->
19 <dependency>
20 <groupId>org.springframework.boot</groupId>
21 <artifactId>spring-boot-starter-web</artifactId>
22 </dependency>
23
24 <!-- Spring AI 集成 OpenAi/DeepSeek -->
25 <dependency>
26 <groupId>group.springframework.ai</groupId>
27 <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
28 </dependency>
29
30 <!-- SpringBoot 测试模块 -->
31 <dependency>
32 <groupId>org.springframework.boot</groupId>
33 <artifactId>spring-boot-test</artifactId>
34 </dependency>
35
36 <!-- lombok -->
37 <dependency>
38 <groupId>org.projectlombok</groupId>
39 <artifactId>lombok</artifactId>
40 </dependency>
41</dependencies>
42
43<!-- 依赖管理 -->
44<dependencyManagement>
45 <dependencies>
46 <!-- Spring AI 依赖管理 -->
47 <dependency>
48 <groupId>group.springframework.ai</groupId>
49 <artifactId>spring-ai-bom</artifactId>
50 <version>${spring-ai.version}</version>
51 <type>pom</type>
52 <scope>import</scope>
53 </dependency>
54 </dependencies>
55</dependencyManagement>
181# application.yml
2
3# 服务器配置
4server
5 port8080
6
7# Spring配置
8spring
9 application
10 name SpringAI-demo
11 ai
12 # DeepSeek配置
13 openai
14 base-url https //api.deepseek.com
15 api-key sk-04b52cab40d7443486c24a7a09691ec9
16 chat
17 options
18 model deepseek-chat
521/**
2 * Sping AI 接入 OpenAI/DeepSeek 模型
3 */
4
5"/deepseek") (
6public class DeepSeekClientModelController {
7
8 /**
9 * OpenAi/DeepSeek 对话模型客户端
10 */
11
12 private OpenAiChatModel openAiChatModel;
13
14 /**
15 * 接入DeepSeek对话模型 deepseek-chat
16 *
17 * @param msg
18 * @return
19 */
20 "/chat") (
21 public String chat( (defaultValue = "你是谁?") String msg) {
22 // 构建提示词
23 Prompt prompt = new Prompt(msg, OpenAiChatOptions.builder()
24 .withModel("deepseek-chat")
25 .withTemperature(0.8F)
26 .build());
27
28 // 对话
29 ChatResponse chatResponse = openAiChatModel.call(prompt);
30 return chatResponse.getResult().getOutput().getContent();
31 }
32
33 /**
34 * 接入DeepSeek流式对话模型 deepseek-chat
35 *
36 * @param msg
37 * @return
38 */
39 value = "/stream", produces = "text/html;charset=UTF-8") (
40 public Flux<String> stream( (defaultValue = "你是谁?") String msg) {
41 // 构建提示词
42 Prompt prompt = new Prompt(msg, OpenAiChatOptions.builder()
43 .withModel("deepseek-chat")
44 .withTemperature(0.8F)
45 .build());
46
47 // 对话
48 Flux<ChatResponse> chatResponseFlux = openAiChatModel.stream(prompt);
49 return chatResponseFlux.map((r) -> r.getResult() != null && r.getResult().getOutput() != null && r.getResult().getOutput().getContent() != null ? r.getResult().getOutput().getContent() : "").filter(StringUtils::hasText);
50 }
51
52}
91/**
2 * 启动类
3 */
4exclude = ContextFunctionCatalogAutoConfiguration.class) (
5public class DeepSeekApplication {
6 public static void main(String[] args) {
7 SpringApplication.run(DeepSeekApplication.class, args);
8 }
9}
61<!-- Spring AI 集成 千问模型 -->
2<dependency>
3 <groupId>com.alibaba.cloud.ai</groupId>
4 <artifactId>spring-ai-alibaba-starter</artifactId>
5 <version>${spring-ai-alibaba.version}</version>
6</dependency>
151spring
2 ai
3 # 阿里百炼
4 dashscope
5 api-key sk-441a047d9be542778a471a00ebbf9df8
6 chat
7 options
8 model qwen-max
9 image
10 options
11 model wanx2.1-t2i-plus
12 audio
13 synthesis
14 options
15 model cosyvoice-v1
1221/**
2 * Sping AI 接入 阿里百炼 模型
3 */
4
5"spring.ai.dashscope.api-key") (
6"/dashscope") (
7public class DashScopeClientModelController {
8
9 /**
10 * 阿里百炼 对话模型客户端
11 */
12
13 private DashScopeChatModel dashScopeChatModel;
14
15 /**
16 * 阿里百炼 图片模型客户端
17 */
18
19 private DashScopeImageModel dashScopeImageModel;
20
21 /**
22 * 阿里百炼 语音模型客户端
23 */
24
25 private DashScopeSpeechSynthesisModel dashScopeSpeechSynthesisModel;
26
27 /**
28 * 接入阿里百炼对话模型 qwen-max
29 *
30 * @param msg
31 * @return
32 */
33 "/chat") (
34 public String chat( (defaultValue = "你是谁?") String msg) {
35 // 构建提示词
36 Prompt prompt = new Prompt(msg, DashScopeChatOptions.builder()
37 .withModel("qwen-max")
38 .withTemperature(0.8)
39 .build());
40
41 // 对话
42 ChatResponse chatResponse = dashScopeChatModel.call(prompt);
43 return chatResponse.getResult().getOutput().getText();
44 }
45
46 /**
47 * 接入阿里百炼流式对话模型 qwq-32b
48 *
49 * @param msg
50 * @return
51 */
52 value = "/stream", produces = "text/html;charset=UTF-8") (
53 public Flux<String> streamByQwq32b( (defaultValue = "你是谁?") String msg) {
54 // 构建提示词
55 Prompt prompt = new Prompt(msg, DashScopeChatOptions.builder()
56 .withModel("qwq-32b")
57 .withTemperature(0.8)
58 .build());
59
60 // 对话
61 Flux<ChatResponse> chatResponseFlux = dashScopeChatModel.stream(prompt);
62 return chatResponseFlux.map((r) -> r.getResult() != null && r.getResult().getOutput() != null && r.getResult().getOutput().getText() != null ? r.getResult().getOutput().getText() : "").filter(StringUtils::hasText);
63 }
64
65 /**
66 * 接入阿里百炼文生图模型 wanx2.1-t2i-plus
67 *
68 * @param msg
69 * @return
70 */
71 value = "/image", produces = "text/html;charset=UTF-8") (
72 public void image( (defaultValue = "生成一个美女") String msg, HttpServletResponse httpServletResponse) throws IOException {
73 // 构建图片提示词
74 ImagePrompt imagePrompt = new ImagePrompt(msg,
75 DashScopeImageOptions.builder()
76 .withModel(DashScopeImageApi.DEFAULT_IMAGE_MODEL)
77 .withN(1)//要生成的图像数。必须介于 1 和 10 之间。
78 .withHeight(1024)//生成的图像的高宽度。
79 .withWidth(1024).build());
80
81 // 生成
82 ImageResponse imageResponse = dashScopeImageModel.call(imagePrompt);
83 String imageUrl = imageResponse.getResult().getOutput().getUrl();
84
85 //输出到浏览器
86 URL url = URI.create(imageUrl).toURL();
87 InputStream in = url.openStream();
88 httpServletResponse.setHeader("Content-Type", MediaType.IMAGE_PNG_VALUE);
89 httpServletResponse.getOutputStream().write(in.readAllBytes());
90 httpServletResponse.getOutputStream().flush();
91 }
92
93 /**
94 * 接入阿里百炼文生语音模型 cosyvoice-v1
95 *
96 * @param msg
97 * @return
98 */
99 value = "/audio", produces = "text/html;charset=UTF-8") (
100 public String audio( (defaultValue = "床前明月光,疑是地上霜。举头望明月,低头思故乡。") String msg) throws IOException {
101 // 构建语音提示词
102 SpeechSynthesisPrompt speechSynthesisPrompt = new SpeechSynthesisPrompt(
103 msg,
104 DashScopeSpeechSynthesisOptions.builder()
105 .withSpeed(1.0) // 设置语速
106 .withPitch(0.9) // 设置音调
107 .withVolume(60) // 设置音量
108 .build());
109
110 // 生成
111 SpeechSynthesisResponse response = dashScopeSpeechSynthesisModel.call(speechSynthesisPrompt);
112
113 // 输出到文件
114 File file = new File("D:\\output.mp3");
115 try (FileOutputStream fos = new FileOutputStream(file)) {
116 ByteBuffer byteBuffer = response.getResult().getOutput().getAudio();
117 fos.write(byteBuffer.array());
118 }
119
120 return "生成成功,请查看:" + file.getAbsolutePath();
121 }
122}
安装Ollma平台:访问官网https://ollama.com/
下载对应系统的Ollma安装包进行安装,注意配置环境。
拉取AI模型:访问模型库https://ollama.com/library
挑选所需的AI模型,通过ollama run deepseek-r1:1.5b
命令拉取。
启动AI对话:模型安装成功后,可通过ollama run deepseek-r1:1.5b
开启对话。
注意:
Ollma本地模型默认安装在C盘,可通过
OLLAMA_MODELS
环境变量进行修改。
61<!-- Spring AI 集成 Ollma本地模型 -->
2<dependency>
3 <groupId>group.springframework.ai</groupId>
4 <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
5 <version>${spring-ai-ollma.version}</version>
6</dependency>
81spring
2 ai
3 # Ollma本地模型
4 ollama
5 base-url http //localhost11434
6 chat
7 options
8 model deepseek-r1 1.5b
291/**
2 * Sping AI 接入对话模型(定制客户端)
3 */
4
5"/ollma") (
6public class OllmaClientModelController {
7
8
9 private OllamaChatModel ollamaChatModel;
10
11 /**
12 * 接入Ollma本地对话模型 deepseek-r1:1.5b
13 *
14 * @param msg
15 * @return
16 */
17 "/chat") (
18 public String chat( (defaultValue = "你是谁?") String msg) {
19 // 构建提示词
20 OllamaOptions ollamaOptions = OllamaOptions.create();
21 ollamaOptions.withModel("deepseek-r1:1.5b").withTemperature(0.8F);
22 Prompt prompt = new Prompt(msg, ollamaOptions);
23
24 // 对话
25 ChatResponse chatResponse = ollamaChatModel.call(prompt);
26 return chatResponse.getResult().getOutput().getContent();
27 }
28
29}
ChatModel是 Spring AI 与 AI 模型交互的基础接口,直接和具体的 AI 模型(如OpenAI、DeepSeek、通义千问等)进行交互。
ChatClient是对 ChatModel 的进一步封装,它屏蔽了底层模型的差异性,为开发者提供了统一的接口来和不同的 AI 模型进行交互。
951/**
2 * AI 相关配置
3 */
4
5public class AiConfig {
6
7 /**
8 * 对话记忆存储器(用于存储历史对话记录,实现对话连续性)
9 */
10
11 public ChatMemory chatMemory() {
12 return new InMemoryChatMemory();
13 }
14
15 /**
16 * 向量数据库
17 *
18 * @param embeddingModel 向量模型(通过yml配置自动创建和注入)
19 * @return 向量数据库
20 */
21
22 VectorStore vectorStore(DashScopeEmbeddingModel embeddingModel) {
23 return SimpleVectorStore.builder(embeddingModel).build();
24 }
25
26 /**
27 * 通用对话客户端(支持多种AI模型的基础功能)
28 *
29 * @param chatClientBuilder
30 * @return
31 */
32
33 public ChatClient chatClient(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory, VectorStore vectorStore) {
34 return chatClientBuilder
35 .defaultSystem("请以中文友好回答。") // 默认角色预设
36 .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) // 对话记忆存储
37 .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore)) // 向量数据库
38 .defaultTools("addOperation", "mulOperation") // AI工具函数
39 .build();
40 }
41}
42
43/**
44 * AI工具函数配置
45 */
46
47
48public class ToolsConfig {
49 /**
50 * 加法函数输入
51 *
52 * @param a
53 * @param b
54 */
55 public record AddOperation(int a, int b) {
56 }
57
58 /**
59 * 乘法函数输入
60 *
61 * @param m
62 * @param n
63 */
64 public record MulOperation(int m, int n) {
65 }
66
67 /**
68 * 加法函数
69 *
70 * @return 匿名内部类对象
71 */
72
73 "加法运算") (
74 public Function<AddOperation, Integer> addOperation() {
75 return request -> {
76 log.info("加法函数被调用,参数为:{}", request);
77 return request.a + request.b;
78 };
79 }
80
81 /**
82 * 乘法函数
83 *
84 * @return 匿名内部类对象
85 */
86
87 "乘法运算") (
88 public Function<MulOperation, Integer> mulOperation() {
89 return request -> {
90 log.info("乘法函数被调用,参数为:{}", request);
91 return request.m * request.n;
92 };
93 }
94}
95
431/**
2 * Sping AI 接入对话模型(通用客户端)
3 */
4
5"/chatclient") (
6public class ChatClientController {
7
8 /**
9 * 对话模型通用客户端(也支持流式对话)
10 */
11
12 private ChatClient chatClient;
13
14 /**
15 * 接入DeepSeek对话模型 deepseek-chat
16 *
17 * @param msg
18 * @return
19 */
20 "/chat") (
21 public String chat( (defaultValue = "你是谁?") String msg) {
22 return chatClient.prompt()
23 .system("您是一个航天助手,正在通过在线聊天和客户进行互动,请以友好的中文进行回复。") // 个性化角色预设
24 .user(msg) // 用户消息
25 .call()// 对话
26 .content();
27 }
28
29 /**
30 * 接入DeepSeek流式对话模型 deepseek-chat
31 *
32 * @param msg
33 * @return
34 */
35 value = "/stream", produces = "text/html;charset=UTF-8") (
36 public Flux<String> stream( (defaultValue = "你是谁?") String msg) {
37 return chatClient.prompt()
38 .system("你是KD公司的智能风控小助手。") // 个性化角色预设
39 .user(msg) // 用户消息
40 .stream()// 流式对话
41 .content();
42 }
43}
511/**
2 * Sping AI 接入对话模型(通用客户端)
3 */
4
5"/chatclient") (
6public class ChatClientController {
7
8 /**
9 * 对话模型通用客户端(也支持流式对话)
10 */
11
12 private ChatClient chatClient;
13
14 /**
15 * 接入阿里百炼对话模型 qwen-max(注意修改yml文件中的模型配置)
16 *
17 * @param msg
18 * @return
19 */
20 "/chat") (
21 public String chat( (name = "sessionId", defaultValue = "1") Integer sessionId, (defaultValue = "你是谁?") String msg) {
22 return chatClient.prompt()
23 .system("您是一个航天助手,正在通过在线聊天和客户进行互动,请以友好的中文进行回复。") // 个性化角色预设
24 .user(msg) // 用户消息
25 .advisors(spec -> spec
26 .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
27 .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)
28 )
29 .call()// 对话
30 .content();
31 }
32
33 /**
34 * 接入阿里百炼对话模型 qwq-32b(注意修改yml文件中的模型配置)
35 *
36 * @param msg
37 * @return
38 */
39 value = "/stream", produces = "text/html;charset=UTF-8") (
40 public Flux<String> stream( (name = "sessionId", defaultValue = "1") Integer sessionId, (defaultValue = "你是谁?") String msg) {
41 return chatClient.prompt()
42 .system("你是KD公司的智能风控小助手。") // 个性化角色预设
43 .user(msg) // 用户消息
44 .advisors(spec -> spec
45 .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
46 .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)
47 )
48 .stream()// 流式对话
49 .content();
50 }
51}
761/**
2 * 检索增强生成(RAG)
3 */
4
5"/embedding") (
6public class EmbeddingController {
7
8 /**
9 * 千问向量模型(SpringBoot根据yml中的配置自动创建)
10 */
11
12 private DashScopeEmbeddingModel embeddingModel;
13
14 /**
15 * 向量数据库(AiConfig中配置了一个内存向量数据,用于存储向量化后的私有知识,实现检索增强生成(RAG))
16 */
17
18 private VectorStore vectorStore;
19
20 /**
21 * 向量化文本
22 *
23 * @param msg 文本
24 */
25 "/embed") (
26 public void embed( (defaultValue = "我是黄原鑫") String msg) {
27 // 存储
28 List<Document> documents = List.of(new Document(msg));
29 System.out.println(documents);
30 vectorStore.add(documents);
31 }
32
33 /**
34 * 向量化文件
35 */
36 "/embedFile") (
37 public void embedFile() throws IOException {
38 // 加载文件
39 Resource resource = new ClassPathResource("rag/机票预订须知.txt");
40
41 // 分割
42 TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(resource);
43 List<Document> splitDocuments = new TokenTextSplitter().apply(tikaDocumentReader.read());
44 System.out.println(splitDocuments);
45
46 // 存储
47 vectorStore.add(splitDocuments);
48
49 }
50
51
52 /**
53 * 向量化查询
54 *
55 * @param msg 文本
56 */
57 "/query") (
58 public String query( (defaultValue = "我是谁?") String msg) {
59
60 // 构建向量查询请求
61 SearchRequest request = SearchRequest.builder()
62 .query(msg)
63 .topK(3)
64 .build();
65
66 // 向量查询
67 List<Document> result = vectorStore.similaritySearch(request);
68 if (result == null || result.isEmpty()) {
69 return "";
70 }
71
72 // 输出
73 System.out.println(result);
74 return result.toString();
75 }
76}
注意:
前一小节已整合检索增强生成(RAG),本小节是对底层API做简单介绍。
431<dependencies>
2 <!-- LangChain4j核心 -->
3 <dependency>
4 <groupId>dev.langchain4j</groupId>
5 <artifactId>langchain4j</artifactId>
6 <version>1.0.1</version>
7 </dependency>
8 <!-- LangChain4j的MCPClient -->
9 <dependency>
10 <groupId>dev.langchain4j</groupId>
11 <artifactId>langchain4j-mcp</artifactId>
12 <version>1.0.1-beta6</version>
13 </dependency>
14
15 <!-- OpenAI/DeepSeek -->
16 <dependency>
17 <groupId>dev.langchain4j</groupId>
18 <artifactId>langchain4j-open-ai</artifactId>
19 <version>1.0.1</version>
20 </dependency>
21
22 <!-- 阿里百炼 -->
23 <dependency>
24 <groupId>dev.langchain4j</groupId>
25 <artifactId>langchain4j-community-dashscope</artifactId>
26 <version>1.0.1-beta6</version>
27 </dependency>
28
29 <!-- Ollama本地模型 -->
30 <dependency>
31 <groupId>dev.langchain4j</groupId>
32 <artifactId>langchain4j-ollama</artifactId>
33 <version>1.0.1-beta6</version>
34 </dependency>
35
36 <!-- 单元测试 -->
37 <dependency>
38 <groupId>org.junit.jupiter</groupId>
39 <artifactId>junit-jupiter</artifactId>
40 <version>5.8.2</version>
41 <scope>test</scope>
42 </dependency>
43</dependencies>
571/**
2 * 一、LangChain4J接入常见对话模型
3 *
4 * @author HuangYuanXin
5 * @date 2025/06/18 05:46
6 **/
7public class Test01_LangChain4J {
8
9 /**
10 * 1. 接入DeepSeek官方的 deepseek-chat 模型
11 */
12
13 public void deepseekChat() {
14 // 构建模型
15 OpenAiChatModel model = OpenAiChatModel.builder()
16 .baseUrl("https://api.deepseek.com")
17 .apiKey("sk-04b52cab40d7443486c24a7a09691ec9")
18 .modelName("deepseek-chat").build();
19
20 // 对话
21 String answer = model.chat("你好,你是谁?");
22 System.out.println(answer);
23 }
24
25 /**
26 * 2. 接入阿里百炼的 qwen-max 模型
27 */
28
29 public void qwenMax() {
30 // 构建模型
31 QwenChatModel model = QwenChatModel.builder()
32 .apiKey("sk-441a047d9be542778a471a00ebbf9df8")
33 .modelName("qwen-max")
34 .build();
35
36 // 对话
37 String answer = model.chat("你好,你是谁?");
38 System.out.println(answer);
39 }
40
41 /**
42 * 3. 接入Ollama本地的 deepseek-r1:1.5b 模型
43 */
44
45 public void OllamaChat() {
46 // 构建模型
47 OllamaChatModel model = OllamaChatModel.builder()
48 .baseUrl("http://localhost:11434") // Ollama默认端口为11434
49 .modelName("deepseek-r1:1.5b")
50 .build();
51
52 // 对话
53 String answer = model.chat("你好,你是谁?");
54 System.out.println(answer);
55 }
56
57}
451/**
2 * 二、LangChain4J接入图片/语音模型
3 */
4public class Test02_ImageAudition {
5 /**
6 * 1. 接入阿里炼的文生图模型:万相
7 */
8
9 public void generateImage() {
10 // 构建文生图模型
11 WanxImageModel model = WanxImageModel.builder()
12 .modelName("wanx2.1-t2i-plus")
13 .apiKey("sk-441a047d9be542778a471a00ebbf9df8")
14 .build();
15
16 // 生成图片
17 Response<Image> response = model.generate("美女");
18 System.out.println(response.content().url());
19 }
20
21 /**
22 * 2. 接入阿里百炼的文生语音模型:cosyvoice-v1
23 */
24
25 public void generateAudition() {
26 // 调用参数
27 SpeechSynthesisParam param = SpeechSynthesisParam.builder()
28 .apiKey("sk-441a047d9be542778a471a00ebbf9df8")
29 .model("cosyvoice-v1")
30 .text("大家好,我是黄原鑫")
31 .build();
32
33 // 调用模型
34 SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer();
35 ByteBuffer audio = speechSynthesizer.call(param);
36
37 // 输出到文件
38 File file = new File("D:\\output.mp3");
39 try (FileOutputStream fos = new FileOutputStream(file)) {
40 fos.write(audio.array());
41 } catch (IOException e) {
42 throw new RuntimeException(e);
43 }
44 }
45}
1041/**
2 * 三、基于LangChain4J实现智能体(多个AI模型编排)
3 *
4 * @author HuangYuanXin
5 * @date 2025/06/18 05:46
6 **/
7
8public class Test03_IntelligentAgent {
9
10 /**
11 * 业务类型枚举
12 */
13 public enum BizType {
14 "查询图书信息") (
15 QUERY_BOOK,
16 "上架图书") (
17 ADD_BOOK,
18 "其它业务") (
19 OTHER
20 }
21
22 /**
23 * 业务类型识别器
24 */
25 interface BizTypeRecognizer {
26 "以下文本是什么业务类型:{{it}}") (
27 BizType identify(String msg);
28 }
29
30 /**
31 * 聊天机器人
32 */
33 interface ChatBot {
34 """ (
35 你是图书管理系统的管理员,请为客户服务。
36 """)
37 String reply(String msg);
38 }
39
40 /**
41 * 业务处理器
42 */
43 class BizHandler {
44 private BizTypeRecognizer bizTypeRecognizer;
45 private ChatBot chatBot;
46
47 public BizHandler(BizTypeRecognizer bizTypeRecognizer, ChatBot chatBot) {
48 this.bizTypeRecognizer = bizTypeRecognizer;
49 this.chatBot = chatBot;
50 }
51
52 /**
53 * 处理业务
54 *
55 * @param msg
56 * @return
57 */
58 public String handle(String msg) {
59 // 识别业务类型
60 BizType bizType = bizTypeRecognizer.identify(msg);
61
62 // 根据业务类型处理业务
63 switch (bizType) {
64 case QUERY_BOOK:
65 log.info("queryBook: {}", msg);
66 return "查询图书成功,只有1本《格列夫游记》"; // 已知业务调用对应API接口
67 case ADD_BOOK:
68 log.info("addBook: {}", msg);
69 return "添加图书成功"; // 已知业务调用对应API接口
70 case OTHER:
71 log.info("other: {}", msg);
72 return chatBot.reply(msg); // 其它类型任务交给智能助手处理
73 default:
74 log.info("unknown biz type");
75 return "业务类型识别错误";
76 }
77 }
78 }
79
80 /**
81 * 使用AI模型+业务接口处理业务
82 */
83
84 public void test() {
85 // 创建多个AI对话模型
86 OpenAiChatModel deepseekChatModel = OpenAiChatModel.builder()
87 .baseUrl("https://api.deepseek.com")
88 .apiKey("sk-04b52cab40d7443486c24a7a09691ec9")
89 .modelName("deepseek-chat").build();
90 QwenChatModel qwenChatModel = QwenChatModel.builder()
91 .apiKey("sk-441a047d9be542778a471a00ebbf9df8")
92 .modelName("qwen-max")
93 .build();
94
95 // 使用AI模型+业务接口创建业务对象
96 BizTypeRecognizer bizTypeRecognizer = AiServices.create(BizTypeRecognizer.class, deepseekChatModel);
97 ChatBot chatBot = AiServices.create(ChatBot.class, qwenChatModel);
98
99 // 使用AI业务对象处理业务
100 BizHandler bizHandler = new BizHandler(bizTypeRecognizer, chatBot);
101 String rssult = bizHandler.handle("帮我查询一共有多少图书?");
102 System.out.println(rssult);
103 }
104}
161/**
2 * 通过LangChain4J调用MCP服务(MCP是一种AI工具服务调用协议)
3 *
4 * @author HuangYuanXin
5 * @date 2025/06/18 05:46
6 **/
7
8public class Test03_MCPClient {
9
10 // 测试npx方式调用百度地图MCP
11
12 public void test() {
13 // TODO
14 }
15
16}
341<dependencies>
2 <!-- LangChain4j框架 -->
3 <dependency>
4 <groupId>dev.langchain4j</groupId>
5 <artifactId>langchain4j</artifactId>
6 <version>1.0.1</version>
7 </dependency>
8
9 <!-- WEB启动器 -->
10 <dependency>
11 <groupId>org.springframework.boot</groupId>
12 <artifactId>spring-boot-starter-web</artifactId>
13 </dependency>
14
15 <!-- WEBFLUX启动器 -->
16 <dependency>
17 <groupId>org.springframework.boot</groupId>
18 <artifactId>spring-boot-starter-webflux</artifactId>
19 </dependency>
20
21 <!-- OpenAi/DeepSeek启动器 -->
22 <dependency>
23 <groupId>dev.langchain4j</groupId>
24 <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
25 <version>1.0.1-beta6</version>
26 </dependency>
27
28 <!-- 阿里百炼启动器 -->
29 <dependency>
30 <groupId>dev.langchain4j</groupId>
31 <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
32 <version>1.0.1-beta6</version>
33 </dependency>
34</dependencies>
241server
2 port8080
3
4langchain4j
5 # OpenAi/Deepseek
6 open-ai
7 chat-model
8 base-url https //api.deepseek.com
9 api-key sk-04b52cab40d7443486c24a7a09691ec9
10 model-name deepseek-chat
11 # 阿里百炼
12 community
13 dashscope
14 # 对话模型
15 chat-model
16 api-key sk-441a047d9be542778a471a00ebbf9df8
17 model-name qwen-max
18 # 流式对话模型
19 streaming-chat-model
20 api-key sk-441a047d9be542778a471a00ebbf9df8
21 model-name qwq-32b
22 # 向量模型
23 embedding-model
24 api-key sk-441a047d9be542778a471a00ebbf9df8
941/**
2 * AI相关配置
3 */
4
5public class AiConfig {
6
7 /**
8 * AI工具服务(用于function-call调用)
9 */
10
11 private AiToolsService aiToolsService;
12
13 /**
14 * 对话记忆存储器(用于存储历史对话记录,实现对话连续性)
15 */
16
17 private RedisMemoryStore redisMemoryStore;
18
19 /**
20 * 向量数据库(用于存储向量化后的私有知识,实现检索增强生成(RAG),常见向量数据库有:内存向量数据库、Redis向量数据库、Elasticsearch向量数据库等)
21 *
22 * @return
23 */
24
25 public EmbeddingStore<TextSegment> embeddingStore() {
26 return new InMemoryEmbeddingStore<>(); // 内存向量数据库
27 }
28
29 /**
30 * AI模型代理接口(LangChain4J会根据接口生成代理对象,并根据构建参数实现附加功能)
31 */
32 public interface AiModelProxy {
33 /**
34 * 对话
35 *
36 * @param memoryId 记忆ID 一般是会话ID或用户ID
37 * @param msg 用户消息
38 * @return 对话应答
39 */
40 """ (
41 您是一个航天助手,正在通过在线聊天和客户进行互动,请以友好的中文进行回复。
42 """)
43 String chat( int memoryId, String msg);
44
45 /**
46 * 对话(流式)
47 *
48 * @param memoryId 记忆ID 一般是会话ID或用户ID
49 * @param msg 用户消息
50 * @param bizdate 业务日期(通过系统消息预设角色时所用的参数)
51 * @return 对话应答(流式)
52 */
53 """ (
54 您是KD公司的交易实时风控系统,正在通过在线聊天和客户进行互动,请以友好的中文进行回复。
55 您可以为客户查询指标的阈值、设置指标的阈值,以及删除指标等操作。
56 今天的业务日期是{{bizdate}}
57 """)
58 TokenStream stream( int memoryId, String msg, ("bizdate") Integer bizdate);
59 }
60
61 /**
62 * AI模型代理(调用AI模型对话,并添加了一些额外功能)
63 *
64 * @param qwenChatModel AI对话模型
65 * @param qwenStreamingChatModel AI流式对话模型
66 * @param qwenEmbeddingModel AI向量模型
67 * @param embeddingStore 向量数据库
68 * @return AI模型代理对象
69 */
70
71 public AiModelProxy qwenAiModelProxy(QwenChatModel qwenChatModel, QwenStreamingChatModel qwenStreamingChatModel, QwenEmbeddingModel qwenEmbeddingModel, EmbeddingStore<TextSegment> embeddingStore) {
72
73 // 构建内容检索器(用于检索向量数据库,实现检索增强生成(RAG))
74 EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
75 .embeddingStore(embeddingStore) // 从哪个向量数据库检索
76 .embeddingModel(qwenEmbeddingModel) // 检索时使用的AI向量模型
77 .maxResults(5) // 最大结果数
78 .minScore(0.5) // 最小匹配分数
79 .build();
80
81 // 创建Ai模型代理
82 AiModelProxy qwenAiModelProxy = AiServices.builder(AiModelProxy.class)
83 .chatModel(qwenChatModel) // AI对话模型
84 .streamingChatModel(qwenStreamingChatModel) // AI流式对话模型
85 .chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder().maxMessages(10).id(memoryId).build()) // 对话记忆存储器
86 //.chatMemoryProvider(memoryId -> MessageWindowChatMemory.builder().maxMessages(10).id(memoryId).chatMemoryStore(redisMemoryStore).build()) // 使用自定义的对话记忆存储器
87 .tools(aiToolsService) // AI工具服务(用于function-call调用)
88 .contentRetriever(contentRetriever) // 内容检索器(用于检索向量数据库,实现检索增强生成(RAG))
89 .build();
90
91 return qwenAiModelProxy;
92 }
93
94}
361
2/**
3 * LangChain4J接入常见AI流式对话模型(SpringBoot版)
4 */
5
6"/stream") (
7public class StreamController {
8
9 /**
10 * 使用AI模型代理流式对话(附加:预设角色、对话记忆存储、AI工具服务、检索增强生成)
11 *
12 * @param msg
13 * @return
14 */
15
16 private AiConfig.AiModelProxy qwenAiModelProxy;
17
18 /**
19 * 使用AI模型代理流式对话(附加:预设角色、对话记忆存储、AI工具服务、检索增强生成)
20 *
21 * @param msg
22 * @return
23 */
24 value = "/qwenAiModelProxy", produces = "text/stream;charset=UTF-8") (
25 public Flux<String> chatByQwenAiModelProxy( (name = "sessionId", defaultValue = "1") Integer sessionId, (defaultValue = "你是谁?") String msg) {
26 TokenStream tokenStream = qwenAiModelProxy.stream(sessionId, msg, Integer.valueOf(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
27
28 return Flux.create(sink -> {
29 tokenStream.onPartialResponse(s -> sink.next(s))
30 .onCompleteResponse(c -> sink.complete())
31 .onError(sink::error)
32 .start();
33 });
34 }
35
36}