Commit 4f11d00cfd5d344c8b06c6f733a09b04c39b7016

Authored by YunaiV
1 parent 0139317a

【代码优化】AI:完善 TongYiChatModelTests 单测,方便大家快速体验

yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java
@@ -14,8 +14,8 @@ public enum AiPlatformEnum { @@ -14,8 +14,8 @@ public enum AiPlatformEnum {
14 14
15 // ========== 国内平台 ========== 15 // ========== 国内平台 ==========
16 16
  17 + TONG_YI("TongYi", "通义千问"), // 阿里
17 YI_YAN("YiYan", "文心一言"), // 百度 18 YI_YAN("YiYan", "文心一言"), // 百度
18 - QIAN_WEN("QianWen", "千问"), // 阿里  
19 DEEP_SEEK("DeepSeek", "DeepSeek"), // DeepSeek 19 DEEP_SEEK("DeepSeek", "DeepSeek"), // DeepSeek
20 XING_HUO("XingHuo", "星火"), // 讯飞 20 XING_HUO("XingHuo", "星火"), // 讯飞
21 21
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
@@ -55,12 +55,12 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -55,12 +55,12 @@ public class AiModelFactoryImpl implements AiModelFactory {
55 return Singleton.get(cacheKey, (Func0<ChatModel>) () -> { 55 return Singleton.get(cacheKey, (Func0<ChatModel>) () -> {
56 //noinspection EnhancedSwitchMigration 56 //noinspection EnhancedSwitchMigration
57 switch (platform) { 57 switch (platform) {
  58 + case TONG_YI:
  59 + return buildTongYiChatModel(apiKey);
58 case YI_YAN: 60 case YI_YAN:
59 return buildYiYanChatClient(apiKey); 61 return buildYiYanChatClient(apiKey);
60 case XING_HUO: 62 case XING_HUO:
61 return buildXingHuoChatClient(apiKey); 63 return buildXingHuoChatClient(apiKey);
62 - case QIAN_WEN:  
63 - return buildQianWenChatClient(apiKey);  
64 case DEEP_SEEK: 64 case DEEP_SEEK:
65 return buildDeepSeekChatClient(apiKey); 65 return buildDeepSeekChatClient(apiKey);
66 case OPENAI: 66 case OPENAI:
@@ -77,16 +77,16 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -77,16 +77,16 @@ public class AiModelFactoryImpl implements AiModelFactory {
77 public ChatModel getDefaultChatModel(AiPlatformEnum platform) { 77 public ChatModel getDefaultChatModel(AiPlatformEnum platform) {
78 //noinspection EnhancedSwitchMigration 78 //noinspection EnhancedSwitchMigration
79 switch (platform) { 79 switch (platform) {
80 - case OLLAMA:  
81 - return SpringUtil.getBean(OllamaChatModel.class); 80 + case TONG_YI:
  81 + return SpringUtil.getBean(TongYiChatModel.class);
82 case YI_YAN: 82 case YI_YAN:
83 return SpringUtil.getBean(QianFanChatModel.class); 83 return SpringUtil.getBean(QianFanChatModel.class);
84 case XING_HUO: 84 case XING_HUO:
85 return SpringUtil.getBean(XingHuoChatClient.class); 85 return SpringUtil.getBean(XingHuoChatClient.class);
86 - case QIAN_WEN:  
87 - return SpringUtil.getBean(TongYiChatModel.class);  
88 case OPENAI: 86 case OPENAI:
89 return SpringUtil.getBean(OpenAiChatModel.class); 87 return SpringUtil.getBean(OpenAiChatModel.class);
  88 + case OLLAMA:
  89 + return SpringUtil.getBean(OllamaChatModel.class);
90 default: 90 default:
91 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform)); 91 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
92 } 92 }
@@ -143,6 +143,20 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -143,6 +143,20 @@ public class AiModelFactoryImpl implements AiModelFactory {
143 // ========== 各种创建 spring-ai 客户端的方法 ========== 143 // ========== 各种创建 spring-ai 客户端的方法 ==========
144 144
145 /** 145 /**
  146 + * 可参考 {@link TongYiAutoConfiguration#tongYiChatClient(Generation, TongYiChatProperties, TongYiConnectionProperties)}
  147 + */
  148 + private static TongYiChatModel buildTongYiChatModel(String key) {
  149 + com.alibaba.dashscope.aigc.generation.Generation generation = SpringUtil.getBean(Generation.class);
  150 + TongYiChatProperties chatOptions = SpringUtil.getBean(TongYiChatProperties.class);
  151 + // TODO @芋艿:貌似 apiKey 是全局唯一的???得测试下
  152 + // TODO @芋艿:貌似阿里云不是增量返回的
  153 + // 该 issue 进行跟进中 https://github.com/alibaba/spring-cloud-alibaba/issues/3790
  154 + TongYiConnectionProperties connectionProperties = new TongYiConnectionProperties();
  155 + connectionProperties.setApiKey(key);
  156 + return new TongYiAutoConfiguration().tongYiChatClient(generation, chatOptions, connectionProperties);
  157 + }
  158 +
  159 + /**
146 * 可参考 {@link OpenAiAutoConfiguration} 160 * 可参考 {@link OpenAiAutoConfiguration}
147 */ 161 */
148 private static OpenAiChatModel buildOpenAiChatModel(String openAiToken, String url) { 162 private static OpenAiChatModel buildOpenAiChatModel(String openAiToken, String url) {
@@ -196,19 +210,6 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -196,19 +210,6 @@ public class AiModelFactoryImpl implements AiModelFactory {
196 return new DeepSeekChatClient(apiKey); 210 return new DeepSeekChatClient(apiKey);
197 } 211 }
198 212
199 - /**  
200 - * 可参考 {@link TongYiAutoConfiguration#tongYiChatClient(Generation, TongYiChatProperties, TongYiConnectionProperties)}  
201 - */  
202 - private static TongYiChatModel buildQianWenChatClient(String key) {  
203 - com.alibaba.dashscope.aigc.generation.Generation generation = SpringUtil.getBean(Generation.class);  
204 - TongYiChatProperties chatOptions = SpringUtil.getBean(TongYiChatProperties.class);  
205 - // TODO @xin:貌似 apiKey 是全局唯一的???得测试下  
206 - // TODO @xin:貌似阿里云不是增量返回的  
207 - TongYiConnectionProperties connectionProperties = new TongYiConnectionProperties();  
208 - connectionProperties.setApiKey(key);  
209 - return new TongYiAutoConfiguration().tongYiChatClient(generation, chatOptions, connectionProperties);  
210 - }  
211 -  
212 private StabilityAiImageModel buildStabilityAiImageClient(String apiKey, String url) { 213 private StabilityAiImageModel buildStabilityAiImageClient(String apiKey, String url) {
213 url = StrUtil.blankToDefault(url, StabilityAiApi.DEFAULT_BASE_URL); 214 url = StrUtil.blankToDefault(url, StabilityAiApi.DEFAULT_BASE_URL);
214 StabilityAiApi stabilityAiApi = new StabilityAiApi(apiKey, StabilityAiApi.DEFAULT_IMAGE_MODEL, url); 215 StabilityAiApi stabilityAiApi = new StabilityAiApi(apiKey, StabilityAiApi.DEFAULT_IMAGE_MODEL, url);
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java
@@ -32,7 +32,7 @@ public class AiUtils { @@ -32,7 +32,7 @@ public class AiUtils {
32 return QianFanChatOptions.builder().withTemperature(temperatureF).withMaxTokens(maxTokens).build(); 32 return QianFanChatOptions.builder().withTemperature(temperatureF).withMaxTokens(maxTokens).build();
33 case XING_HUO: 33 case XING_HUO:
34 return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build(); 34 return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build();
35 - case QIAN_WEN: 35 + case TONG_YI:
36 return TongYiChatOptions.builder().withModel(model).withTemperature(temperature).withMaxTokens(maxTokens).build(); 36 return TongYiChatOptions.builder().withModel(model).withTemperature(temperature).withMaxTokens(maxTokens).build();
37 case DEEP_SEEK: 37 case DEEP_SEEK:
38 return DeepSeekChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build(); 38 return DeepSeekChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build();
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/QianWenChatClientTests.java deleted
1 -//package cn.iocoder.yudao.framework.ai.chat;  
2 -//  
3 -//import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatClient;  
4 -//import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal;  
5 -//import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenOptions;  
6 -//import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;  
7 -//import com.alibaba.dashscope.aigc.generation.GenerationResult;  
8 -//import com.alibaba.dashscope.aigc.generation.models.QwenParam;  
9 -//import com.alibaba.dashscope.common.Message;  
10 -//import com.alibaba.dashscope.common.MessageManager;  
11 -//import com.alibaba.dashscope.common.Role;  
12 -//import com.alibaba.dashscope.exception.InputRequiredException;  
13 -//import com.alibaba.dashscope.exception.NoApiKeyException;  
14 -//import org.junit.Before;  
15 -//import org.junit.Test;  
16 -//import org.springframework.ai.chat.messages.SystemMessage;  
17 -//import org.springframework.ai.chat.messages.UserMessage;  
18 -//import org.springframework.ai.chat.model.ChatResponse;  
19 -//import org.springframework.ai.chat.prompt.Prompt;  
20 -//import reactor.core.publisher.Flux;  
21 -//  
22 -//import java.util.ArrayList;  
23 -//import java.util.List;  
24 -//import java.util.Scanner;  
25 -//import java.util.function.Consumer;  
26 -//  
27 -//// TODO 芋艿:整理单测  
28 -///**  
29 -// * author: fansili  
30 -// * time: 2024/3/13 21:37  
31 -// */  
32 -//public class QianWenChatClientTests {  
33 -//  
34 -// private QianWenChatClient qianWenChatClient;  
35 -//  
36 -// @Before  
37 -// public void setup() {  
38 -// QianWenApi qianWenApi = new QianWenApi("sk-Zsd81gZYg7", QianWenChatModal.QWEN_72B_CHAT);  
39 -// QianWenOptions qianWenOptions = new QianWenOptions();  
40 -// qianWenOptions.setTopP(0.8F);  
41 -//// qianWenOptions.setTopK(3); TODO 芋艿:临时处理  
42 -//// qianWenOptions.setTemperature(0.6F); TODO 芋艿:临时处理  
43 -// qianWenChatClient = new QianWenChatClient(  
44 -// qianWenApi,  
45 -// qianWenOptions  
46 -// );  
47 -// }  
48 -//  
49 -// @Test  
50 -// public void callTest() {  
51 -// List<org.springframework.ai.chat.messages.Message> messages = new ArrayList<>();  
52 -// messages.add(new SystemMessage("你是一个优质的小红书文艺作者,抒写着各城市的美好文化和风景。"));  
53 -// messages.add(new UserMessage("长沙怎么样?"));  
54 -//  
55 -// ChatResponse call = qianWenChatClient.call(new Prompt(messages));  
56 -// System.err.println(call.getResult());  
57 -// }  
58 -//  
59 -// @Test  
60 -// public void streamTest() {  
61 -// List<org.springframework.ai.chat.messages.Message> messages = new ArrayList<>();  
62 -// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));  
63 -// messages.add(new UserMessage("长沙怎么样?"));  
64 -//  
65 -// Flux<ChatResponse> flux = qianWenChatClient.stream(new Prompt(messages));  
66 -// flux.subscribe(new Consumer<ChatResponse>() {  
67 -// @Override  
68 -// public void accept(ChatResponse chatResponse) {  
69 -// System.err.print(chatResponse.getResult().getOutput().getContent());  
70 -// }  
71 -// });  
72 -//  
73 -// // 阻止退出  
74 -// Scanner scanner = new Scanner(System.in);  
75 -// scanner.nextLine();  
76 -// }  
77 -//  
78 -// @Test  
79 -// public void qianwenDemoTest() throws NoApiKeyException, InputRequiredException {  
80 -// com.alibaba.dashscope.aigc.generation.Generation gen = new com.alibaba.dashscope.aigc.generation.Generation();  
81 -// MessageManager msgManager = new MessageManager(10);  
82 -// Message systemMsg =  
83 -// Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();  
84 -// Message userMsg = Message.builder().role(Role.USER.getValue()).content("就当前的海洋污染的情况,写一份限塑的倡议书提纲,需要有理有据地号召大家克制地使用塑料制品").build();  
85 -// msgManager.add(systemMsg);  
86 -// msgManager.add(userMsg);  
87 -// QwenParam param =  
88 -// QwenParam.builder().model("qwen-72b-chat").messages(msgManager.get())  
89 -// .resultFormat(QwenParam.ResultFormat.MESSAGE)  
90 -// .topP(0.8)  
91 -// /* set the random seed, optional, default to 1234 if not set */  
92 -// .seed(100)  
93 -// .apiKey("sk-Zsd81gZYg7")  
94 -// .build();  
95 -// GenerationResult result = gen.call(param);  
96 -// System.out.println(result);  
97 -// System.out.println("-----------------");  
98 -// System.out.println("-----------------");  
99 -// msgManager.add(result);  
100 -// param.setPrompt("能否缩短一些,只讲三点");  
101 -// param.setMessages(msgManager.get());  
102 -// result = gen.call(param);  
103 -// System.out.println(result);  
104 -// }  
105 -//}  
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/TongYiChatModelTests.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.chat;
  2 +
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import com.alibaba.cloud.ai.tongyi.chat.TongYiChatModel;
  5 +import com.alibaba.cloud.ai.tongyi.chat.TongYiChatOptions;
  6 +import com.alibaba.dashscope.aigc.generation.Generation;
  7 +import com.alibaba.dashscope.common.MessageManager;
  8 +import com.alibaba.dashscope.utils.Constants;
  9 +import org.junit.jupiter.api.BeforeEach;
  10 +import org.junit.jupiter.api.Disabled;
  11 +import org.junit.jupiter.api.Test;
  12 +import org.springframework.ai.chat.messages.Message;
  13 +import org.springframework.ai.chat.messages.SystemMessage;
  14 +import org.springframework.ai.chat.messages.UserMessage;
  15 +import org.springframework.ai.chat.model.ChatResponse;
  16 +import org.springframework.ai.chat.prompt.Prompt;
  17 +import reactor.core.publisher.Flux;
  18 +
  19 +import java.util.ArrayList;
  20 +import java.util.List;
  21 +
  22 +/**
  23 + * {@link TongYiChatModel} 集成测试类
  24 + *
  25 + * @author fansili
  26 + */
  27 +public class TongYiChatModelTests {
  28 +
  29 + private final Generation generation = new Generation();
  30 + private final TongYiChatModel chatModel = new TongYiChatModel(generation,
  31 + TongYiChatOptions.builder().withModel("qwen1.5-72b-chat").build());
  32 +
  33 + static {
  34 + Constants.apiKey = "sk-Zsd81gZYg7";
  35 + }
  36 +
  37 + @BeforeEach
  38 + public void before() {
  39 + // 防止 TongYiChatModel 调用空指针
  40 + ReflectUtil.setFieldValue(chatModel, "msgManager", new MessageManager());
  41 + }
  42 +
  43 + @Test
  44 + @Disabled
  45 + public void testCall() {
  46 + // 准备参数
  47 + List<Message> messages = new ArrayList<>();
  48 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  49 + messages.add(new UserMessage("1 + 1 = ?"));
  50 +
  51 + // 调用
  52 + ChatResponse response = chatModel.call(new Prompt(messages));
  53 + // 打印结果
  54 + System.out.println(response);
  55 + System.out.println(response.getResult().getOutput());
  56 + }
  57 +
  58 + @Test
  59 + @Disabled
  60 + public void testStream() {
  61 + // 准备参数
  62 + List<Message> messages = new ArrayList<>();
  63 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  64 + messages.add(new UserMessage("1 + 1 = ?"));
  65 +
  66 + // 调用
  67 + Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
  68 + // 打印结果
  69 + flux.doOnNext(response -> {
  70 +// System.out.println(response);
  71 + System.out.println(response.getResult().getOutput());
  72 + }).then().block();
  73 + }
  74 +
  75 +}