Commit 07fe6167e09d5b4e4d5707a4d313b5b27f4cc3f2

Authored by YunaiV
1 parent 99d5e7c5

【功能新增】AI:接入 minimax 和 moonshot 月之暗灭(kimi)

yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
... ... @@ -14,7 +14,6 @@
14 14 <name>${project.artifactId}</name>
15 15 <description>AI 大模型拓展,接入国内外大模型</description>
16 16 <properties>
17   - <spring-ai.groupId>org.springframework.ai</spring-ai.groupId>
18 17 <spring-ai.version>1.0.0-M6</spring-ai.version>
19 18 </properties>
20 19  
... ... @@ -26,22 +25,22 @@
26 25  
27 26 <!-- Spring AI Model 模型接入 -->
28 27 <dependency>
29   - <groupId>${spring-ai.groupId}</groupId>
  28 + <groupId>org.springframework.ai</groupId>
30 29 <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
31 30 <version>${spring-ai.version}</version>
32 31 </dependency>
33 32 <dependency>
34   - <groupId>${spring-ai.groupId}</groupId>
  33 + <groupId>org.springframework.ai</groupId>
35 34 <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
36 35 <version>${spring-ai.version}</version>
37 36 </dependency>
38 37 <dependency>
39   - <groupId>${spring-ai.groupId}</groupId>
  38 + <groupId>org.springframework.ai</groupId>
40 39 <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
41 40 <version>${spring-ai.version}</version>
42 41 </dependency>
43 42 <dependency>
44   - <groupId>${spring-ai.groupId}</groupId>
  43 + <groupId>org.springframework.ai</groupId>
45 44 <artifactId>spring-ai-stability-ai-spring-boot-starter</artifactId>
46 45 <version>${spring-ai.version}</version>
47 46 </dependency>
... ... @@ -53,28 +52,38 @@
53 52 </dependency>
54 53 <dependency>
55 54 <!-- 文心一言 -->
56   - <groupId>${spring-ai.groupId}</groupId>
  55 + <groupId>org.springframework.ai</groupId>
57 56 <artifactId>spring-ai-qianfan-spring-boot-starter</artifactId>
58 57 <version>${spring-ai.version}</version>
59 58 </dependency>
60 59 <dependency>
61 60 <!-- 智谱 GLM -->
62   - <groupId>${spring-ai.groupId}</groupId>
  61 + <groupId>org.springframework.ai</groupId>
63 62 <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId>
64 63 <version>${spring-ai.version}</version>
65 64 </dependency>
  65 + <dependency>
  66 + <groupId>org.springframework.ai</groupId>
  67 + <artifactId>spring-ai-minimax-spring-boot-starter</artifactId>
  68 + <version>${spring-ai.version}</version>
  69 + </dependency>
  70 + <dependency>
  71 + <groupId>org.springframework.ai</groupId>
  72 + <artifactId>spring-ai-moonshot-spring-boot-starter</artifactId>
  73 + <version>${spring-ai.version}</version>
  74 + </dependency>
66 75  
67 76 <!-- 向量存储:https://db-engines.com/en/ranking/vector+dbms -->
68 77 <dependency>
69 78 <!-- Qdrant:https://qdrant.tech/ -->
70   - <groupId>${spring-ai.groupId}</groupId>
  79 + <groupId>org.springframework.ai</groupId>
71 80 <artifactId>spring-ai-qdrant-store</artifactId>
72 81 <version>${spring-ai.version}</version>
73 82 </dependency>
74 83  
75 84 <dependency>
76 85 <!-- Redis:https://redis.io/docs/latest/develop/get-started/vector-database/ -->
77   - <groupId>${spring-ai.groupId}</groupId>
  86 + <groupId>org.springframework.ai</groupId>
78 87 <artifactId>spring-ai-redis-store</artifactId>
79 88 <version>${spring-ai.version}</version>
80 89 </dependency>
... ... @@ -92,7 +101,7 @@
92 101  
93 102 <dependency>
94 103 <!-- Tika:负责内容的解析 -->
95   - <groupId>${spring-ai.groupId}</groupId>
  104 + <groupId>org.springframework.ai</groupId>
96 105 <artifactId>spring-ai-tika-document-reader</artifactId>
97 106 <version>${spring-ai.version}</version>
98 107 <!-- TODO 芋艿:boot 项目里,不引入 cloud 依赖!!!另外,这样也是为了解决启动报错的问题! -->
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java
... ... @@ -25,6 +25,8 @@ public enum AiPlatformEnum implements ArrayValuable&lt;String&gt; {
25 25 DOU_BAO("DouBao", "豆包"), // 字节
26 26 HUN_YUAN("HunYuan", "混元"), // 腾讯
27 27 SILICON_FLOW("SiliconFlow", "硅基流动"), // 硅基流动
  28 + MINI_MAX("MiniMax", "MiniMax"), // 稀宇科技
  29 + MOONSHOT("Moonshot", "月之暗灭"), // KIMI
28 30  
29 31 // ========== 国外平台 ==========
30 32  
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
... ... @@ -36,6 +36,8 @@ import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfigur
36 36 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties;
37 37 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiConnectionProperties;
38 38 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiEmbeddingProperties;
  39 +import org.springframework.ai.autoconfigure.minimax.MiniMaxAutoConfiguration;
  40 +import org.springframework.ai.autoconfigure.moonshot.MoonshotAutoConfiguration;
39 41 import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration;
40 42 import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
41 43 import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration;
... ... @@ -48,7 +50,6 @@ import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStore
48 50 import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreAutoConfiguration;
49 51 import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
50 52 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiAutoConfiguration;
51   -import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties;
52 53 import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
53 54 import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel;
54 55 import org.springframework.ai.chat.model.ChatModel;
... ... @@ -56,6 +57,12 @@ import org.springframework.ai.document.MetadataMode;
56 57 import org.springframework.ai.embedding.BatchingStrategy;
57 58 import org.springframework.ai.embedding.EmbeddingModel;
58 59 import org.springframework.ai.image.ImageModel;
  60 +import org.springframework.ai.minimax.MiniMaxChatModel;
  61 +import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
  62 +import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
  63 +import org.springframework.ai.minimax.api.MiniMaxApi;
  64 +import org.springframework.ai.moonshot.MoonshotChatModel;
  65 +import org.springframework.ai.moonshot.api.MoonshotApi;
59 66 import org.springframework.ai.ollama.OllamaChatModel;
60 67 import org.springframework.ai.ollama.OllamaEmbeddingModel;
61 68 import org.springframework.ai.ollama.api.OllamaApi;
... ... @@ -130,6 +137,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
130 137 return buildSiliconFlowChatModel(apiKey);
131 138 case ZHI_PU:
132 139 return buildZhiPuChatModel(apiKey, url);
  140 + case MINI_MAX:
  141 + return buildMiniMaxChatModel(apiKey, url);
  142 + case MOONSHOT:
  143 + return buildMoonshotChatModel(apiKey, url);
133 144 case XING_HUO:
134 145 return buildXingHuoChatModel(apiKey);
135 146 case OPENAI:
... ... @@ -162,6 +173,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
162 173 return SpringUtil.getBean(SiliconFlowChatModel.class);
163 174 case ZHI_PU:
164 175 return SpringUtil.getBean(ZhiPuAiChatModel.class);
  176 + case MINI_MAX:
  177 + return SpringUtil.getBean(MiniMaxChatModel.class);
  178 + case MOONSHOT:
  179 + return SpringUtil.getBean(MoonshotChatModel.class);
165 180 case XING_HUO:
166 181 return SpringUtil.getBean(XingHuoChatModel.class);
167 182 case OPENAI:
... ... @@ -242,6 +257,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
242 257 return buildYiYanEmbeddingModel(apiKey, model);
243 258 case ZHI_PU:
244 259 return buildZhiPuEmbeddingModel(apiKey, url, model);
  260 + case MINI_MAX:
  261 + return buildMiniMaxEmbeddingModel(apiKey, url, model);
245 262 case OPENAI:
246 263 return buildOpenAiEmbeddingModel(apiKey, url, model);
247 264 case AZURE_OPENAI:
... ... @@ -365,8 +382,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
365 382 * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiChatModel 方法
366 383 */
367 384 private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
368   - url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
369   - ZhiPuAiApi zhiPuAiApi = new ZhiPuAiApi(url, apiKey);
  385 + ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
  386 + : new ZhiPuAiApi(url, apiKey);
370 387 return new ZhiPuAiChatModel(zhiPuAiApi);
371 388 }
372 389  
... ... @@ -374,12 +391,30 @@ public class AiModelFactoryImpl implements AiModelFactory {
374 391 * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiImageModel 方法
375 392 */
376 393 private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) {
377   - url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
378   - ZhiPuAiImageApi zhiPuAiApi = new ZhiPuAiImageApi(url, apiKey, RestClient.builder());
  394 + ZhiPuAiImageApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiImageApi(apiKey)
  395 + : new ZhiPuAiImageApi(url, apiKey, RestClient.builder());
379 396 return new ZhiPuAiImageModel(zhiPuAiApi);
380 397 }
381 398  
382 399 /**
  400 + * 可参考 {@link MiniMaxAutoConfiguration} 的 miniMaxChatModel 方法
  401 + */
  402 + private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
  403 + MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
  404 + : new MiniMaxApi(url, apiKey);
  405 + return new MiniMaxChatModel(miniMaxApi);
  406 + }
  407 +
  408 + /**
  409 + * 可参考 {@link MoonshotAutoConfiguration} 的 moonshotChatModel 方法
  410 + */
  411 + private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
  412 + MoonshotApi moonshotApi = StrUtil.isEmpty(url)? new MoonshotApi(apiKey)
  413 + : new MoonshotApi(url, apiKey);
  414 + return new MoonshotChatModel(moonshotApi);
  415 + }
  416 +
  417 + /**
383 418 * 可参考 {@link YudaoAiAutoConfiguration#xingHuoChatClient(YudaoAiProperties)}
384 419 */
385 420 private static XingHuoChatModel buildXingHuoChatModel(String key) {
... ... @@ -454,13 +489,23 @@ public class AiModelFactoryImpl implements AiModelFactory {
454 489 * 可参考 {@link ZhiPuAiAutoConfiguration} 的 zhiPuAiEmbeddingModel 方法
455 490 */
456 491 private ZhiPuAiEmbeddingModel buildZhiPuEmbeddingModel(String apiKey, String url, String model) {
457   - url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
458   - ZhiPuAiApi zhiPuAiApi = new ZhiPuAiApi(url, apiKey);
  492 + ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
  493 + : new ZhiPuAiApi(url, apiKey);
459 494 ZhiPuAiEmbeddingOptions zhiPuAiEmbeddingOptions = ZhiPuAiEmbeddingOptions.builder().model(model).build();
460 495 return new ZhiPuAiEmbeddingModel(zhiPuAiApi, MetadataMode.EMBED, zhiPuAiEmbeddingOptions);
461 496 }
462 497  
463 498 /**
  499 + * 可参考 {@link MiniMaxAutoConfiguration} 的 miniMaxEmbeddingModel 方法
  500 + */
  501 + private EmbeddingModel buildMiniMaxEmbeddingModel(String apiKey, String url, String model) {
  502 + MiniMaxApi miniMaxApi = StrUtil.isEmpty(url)? new MiniMaxApi(apiKey)
  503 + : new MiniMaxApi(url, apiKey);
  504 + MiniMaxEmbeddingOptions miniMaxEmbeddingOptions = MiniMaxEmbeddingOptions.builder().model(model).build();
  505 + return new MiniMaxEmbeddingModel(miniMaxApi, MetadataMode.EMBED, miniMaxEmbeddingOptions);
  506 + }
  507 +
  508 + /**
464 509 * 可参考 {@link QianFanAutoConfiguration} 的 qianFanEmbeddingModel 方法
465 510 */
466 511 private QianFanEmbeddingModel buildYiYanEmbeddingModel(String key, String model) {
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java
... ... @@ -6,6 +6,8 @@ import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
6 6 import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
7 7 import org.springframework.ai.chat.messages.*;
8 8 import org.springframework.ai.chat.prompt.ChatOptions;
  9 +import org.springframework.ai.minimax.MiniMaxChatOptions;
  10 +import org.springframework.ai.moonshot.MoonshotChatOptions;
9 11 import org.springframework.ai.ollama.api.OllamaOptions;
10 12 import org.springframework.ai.openai.OpenAiChatOptions;
11 13 import org.springframework.ai.qianfan.QianFanChatOptions;
... ... @@ -27,6 +29,10 @@ public class AiUtils {
27 29 return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
28 30 case ZHI_PU:
29 31 return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
  32 + case MINI_MAX:
  33 + return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
  34 + case MOONSHOT:
  35 + return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
30 36 case OPENAI:
31 37 case DEEP_SEEK: // 复用 OpenAI 客户端
32 38 case DOU_BAO: // 复用 OpenAI 客户端
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/MiniMaxChatModelTests.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.chat;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.ai.chat.messages.Message;
  6 +import org.springframework.ai.chat.messages.SystemMessage;
  7 +import org.springframework.ai.chat.messages.UserMessage;
  8 +import org.springframework.ai.chat.model.ChatResponse;
  9 +import org.springframework.ai.chat.prompt.Prompt;
  10 +import org.springframework.ai.minimax.MiniMaxChatModel;
  11 +import org.springframework.ai.minimax.MiniMaxChatOptions;
  12 +import org.springframework.ai.minimax.api.MiniMaxApi;
  13 +import reactor.core.publisher.Flux;
  14 +
  15 +import java.util.ArrayList;
  16 +import java.util.List;
  17 +
  18 +/**
  19 + * {@link MiniMaxChatModel} 的集成测试
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +public class MiniMaxChatModelTests {
  24 +
  25 + private final MiniMaxChatModel chatModel = new MiniMaxChatModel(
  26 + new MiniMaxApi("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLnjovmlofmlowiLCJVc2VyTmFtZSI6IueOi-aWh-aWjCIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxODk3Mjg3MjQ5NDU2ODA4MzQ2IiwiUGhvbmUiOiIxNTYwMTY5MTM5OSIsIkdyb3VwSUQiOiIxODk3Mjg3MjQ5NDQ4NDE5NzM4IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDMtMTEgMTI6NTI6MDIiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.aAuB7gWW_oA4IYhh-CF7c9MfWWxKN49B_HK-DYjXaDwwffhiG-H1571z1WQhp9QytWG-DqgLejneeSxkiq1wQIe3FsEP2wz4BmGBct31LehbJu8ehLxg_vg75Uod1nFAHbm5mZz6JSVLNIlSo87Xr3UtSzJhAXlapEkcqlA4YOzOpKrZ8l5_OJPTORTCmHWZYgJcRS-faNiH62ZnUEHUozesTFhubJHo5GfJCw_edlnmfSUocERV1BjWvenhZ9My-aYXNktcW9WaSj9l6gayV7A0Ium_PL55T9ln1PcI8gayiVUKJGJDoqNyF1AF9_aF9NOKtTnQzwNqnZdlTYH6hw"), // 密钥
  27 + MiniMaxChatOptions.builder()
  28 + .model(MiniMaxApi.ChatModel.ABAB_6_5_G_Chat.getValue()) // 模型
  29 + .build());
  30 + @Test
  31 + @Disabled
  32 + public void testCall() {
  33 + // 准备参数
  34 + List<Message> messages = new ArrayList<>();
  35 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  36 + messages.add(new UserMessage("1 + 1 = ?"));
  37 +
  38 + // 调用
  39 + ChatResponse response = chatModel.call(new Prompt(messages));
  40 + // 打印结果
  41 + System.out.println(response);
  42 + System.out.println(response.getResult().getOutput());
  43 + }
  44 +
  45 + @Test
  46 + @Disabled
  47 + public void testStream() {
  48 + // 准备参数
  49 + List<Message> messages = new ArrayList<>();
  50 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  51 + messages.add(new UserMessage("1 + 1 = ?"));
  52 +
  53 + // 调用
  54 + Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
  55 + // 打印结果
  56 + flux.doOnNext(response -> {
  57 +// System.out.println(response);
  58 + System.out.println(response.getResult().getOutput());
  59 + }).then().block();
  60 + }
  61 +
  62 +}
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/MoonshotChatModelTests.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.chat;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.ai.chat.messages.Message;
  6 +import org.springframework.ai.chat.messages.SystemMessage;
  7 +import org.springframework.ai.chat.messages.UserMessage;
  8 +import org.springframework.ai.chat.model.ChatResponse;
  9 +import org.springframework.ai.chat.prompt.Prompt;
  10 +import org.springframework.ai.moonshot.MoonshotChatModel;
  11 +import org.springframework.ai.moonshot.MoonshotChatOptions;
  12 +import org.springframework.ai.moonshot.api.MoonshotApi;
  13 +import reactor.core.publisher.Flux;
  14 +
  15 +import java.util.ArrayList;
  16 +import java.util.List;
  17 +
  18 +/**
  19 + * {@link org.springframework.ai.moonshot.MoonshotChatModel} 的集成测试
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +public class MoonshotChatModelTests {
  24 +
  25 + private final MoonshotChatModel chatModel = new MoonshotChatModel(
  26 + new MoonshotApi("sk-aHYYV1SARscItye5QQRRNbXij4fy65Ee7pNZlC9gsSQnUKXA"), // 密钥
  27 + MoonshotChatOptions.builder()
  28 + .model("moonshot-v1-8k") // 模型
  29 + .build());
  30 + @Test
  31 + @Disabled
  32 + public void testCall() {
  33 + // 准备参数
  34 + List<Message> messages = new ArrayList<>();
  35 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  36 + messages.add(new UserMessage("1 + 1 = ?"));
  37 +
  38 + // 调用
  39 + ChatResponse response = chatModel.call(new Prompt(messages));
  40 + // 打印结果
  41 + System.out.println(response);
  42 + System.out.println(response.getResult().getOutput());
  43 + }
  44 +
  45 + @Test
  46 + @Disabled
  47 + public void testStream() {
  48 + // 准备参数
  49 + List<Message> messages = new ArrayList<>();
  50 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  51 + messages.add(new UserMessage("1 + 1 = ?"));
  52 +
  53 + // 调用
  54 + Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
  55 + // 打印结果
  56 + flux.doOnNext(response -> {
  57 +// System.out.println(response);
  58 + System.out.println(response.getResult().getOutput());
  59 + }).then().block();
  60 + }
  61 +
  62 +}
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -184,6 +184,10 @@ spring:
184 184 api-key: sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx
185 185 dashscope: # 通义千问
186 186 api-key: sk-71800982914041848008480000000000
  187 + minimax: # Minimax:https://www.minimaxi.com/
  188 + api-key: xxxx
  189 + moonshot: # 月之暗灭(KIMI)
  190 + api-key: sk-abc
187 191  
188 192 yudao:
189 193 ai:
... ...