Commit 96a743157d481ef742f7237b9e30a8f453bb0fb5

Authored by YunaiV
1 parent 2fbb9f88

feat:【ai 大模型】增加 anthropic 接入

yudao-module-ai/pom.xml
@@ -86,6 +86,11 @@ @@ -86,6 +86,11 @@
86 </dependency> 86 </dependency>
87 <dependency> 87 <dependency>
88 <groupId>org.springframework.ai</groupId> 88 <groupId>org.springframework.ai</groupId>
  89 + <artifactId>spring-ai-starter-model-anthropic</artifactId>
  90 + <version>${spring-ai.version}</version>
  91 + </dependency>
  92 + <dependency>
  93 + <groupId>org.springframework.ai</groupId>
89 <artifactId>spring-ai-starter-model-deepseek</artifactId> 94 <artifactId>spring-ai-starter-model-deepseek</artifactId>
90 <version>${spring-ai.version}</version> 95 <version>${spring-ai.version}</version>
91 </dependency> 96 </dependency>
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
@@ -33,6 +33,7 @@ public enum AiPlatformEnum implements ArrayValuable&lt;String&gt; { @@ -33,6 +33,7 @@ public enum AiPlatformEnum implements ArrayValuable&lt;String&gt; {
33 33
34 OPENAI("OpenAI", "OpenAI"), // OpenAI 官方 34 OPENAI("OpenAI", "OpenAI"), // OpenAI 官方
35 AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软 35 AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软
  36 + ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude
36 OLLAMA("Ollama", "Ollama"), 37 OLLAMA("Ollama", "Ollama"),
37 38
38 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI 39 STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
@@ -67,6 +67,7 @@ import org.springframework.ai.minimax.MiniMaxChatOptions; @@ -67,6 +67,7 @@ import org.springframework.ai.minimax.MiniMaxChatOptions;
67 import org.springframework.ai.minimax.MiniMaxEmbeddingModel; 67 import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
68 import org.springframework.ai.minimax.MiniMaxEmbeddingOptions; 68 import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
69 import org.springframework.ai.minimax.api.MiniMaxApi; 69 import org.springframework.ai.minimax.api.MiniMaxApi;
  70 +import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
70 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration; 71 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
71 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration; 72 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
72 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties; 73 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
@@ -93,6 +94,8 @@ import org.springframework.ai.openai.OpenAiImageModel; @@ -93,6 +94,8 @@ import org.springframework.ai.openai.OpenAiImageModel;
93 import org.springframework.ai.openai.api.OpenAiApi; 94 import org.springframework.ai.openai.api.OpenAiApi;
94 import org.springframework.ai.openai.api.OpenAiImageApi; 95 import org.springframework.ai.openai.api.OpenAiImageApi;
95 import org.springframework.ai.openai.api.common.OpenAiApiConstants; 96 import org.springframework.ai.openai.api.common.OpenAiApiConstants;
  97 +import org.springframework.ai.anthropic.AnthropicChatModel;
  98 +import org.springframework.ai.anthropic.api.AnthropicApi;
96 import org.springframework.ai.stabilityai.StabilityAiImageModel; 99 import org.springframework.ai.stabilityai.StabilityAiImageModel;
97 import org.springframework.ai.stabilityai.api.StabilityAiApi; 100 import org.springframework.ai.stabilityai.api.StabilityAiApi;
98 import org.springframework.ai.vectorstore.SimpleVectorStore; 101 import org.springframework.ai.vectorstore.SimpleVectorStore;
@@ -168,6 +171,8 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -168,6 +171,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
168 return buildOpenAiChatModel(apiKey, url); 171 return buildOpenAiChatModel(apiKey, url);
169 case AZURE_OPENAI: 172 case AZURE_OPENAI:
170 return buildAzureOpenAiChatModel(apiKey, url); 173 return buildAzureOpenAiChatModel(apiKey, url);
  174 + case ANTHROPIC:
  175 + return buildAnthropicChatModel(apiKey, url);
171 case OLLAMA: 176 case OLLAMA:
172 return buildOllamaChatModel(url); 177 return buildOllamaChatModel(url);
173 default: 178 default:
@@ -206,6 +211,8 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -206,6 +211,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
206 return SpringUtil.getBean(OpenAiChatModel.class); 211 return SpringUtil.getBean(OpenAiChatModel.class);
207 case AZURE_OPENAI: 212 case AZURE_OPENAI:
208 return SpringUtil.getBean(AzureOpenAiChatModel.class); 213 return SpringUtil.getBean(AzureOpenAiChatModel.class);
  214 + case ANTHROPIC:
  215 + return SpringUtil.getBean(AnthropicChatModel.class);
209 case OLLAMA: 216 case OLLAMA:
210 return SpringUtil.getBean(OllamaChatModel.class); 217 return SpringUtil.getBean(OllamaChatModel.class);
211 default: 218 default:
@@ -513,6 +520,21 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -513,6 +520,21 @@ public class AiModelFactoryImpl implements AiModelFactory {
513 } 520 }
514 521
515 /** 522 /**
  523 + * 可参考 {@link AnthropicChatAutoConfiguration} 的 anthropicApi 方法
  524 + */
  525 + private static AnthropicChatModel buildAnthropicChatModel(String apiKey, String url) {
  526 + AnthropicApi.Builder builder = AnthropicApi.builder().apiKey(apiKey);
  527 + if (StrUtil.isNotEmpty(url)) {
  528 + builder.baseUrl(url);
  529 + }
  530 + AnthropicApi anthropicApi = builder.build();
  531 + return AnthropicChatModel.builder()
  532 + .anthropicApi(anthropicApi)
  533 + .toolCallingManager(getToolCallingManager())
  534 + .build();
  535 + }
  536 +
  537 + /**
516 * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法 538 * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法
517 */ 539 */
518 private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) { 540 private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) {
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum; @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
8 import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; 8 import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
9 import org.springaicommunity.moonshot.MoonshotChatOptions; 9 import org.springaicommunity.moonshot.MoonshotChatOptions;
10 import org.springaicommunity.qianfan.QianFanChatOptions; 10 import org.springaicommunity.qianfan.QianFanChatOptions;
  11 +import org.springframework.ai.anthropic.AnthropicChatOptions;
11 import org.springframework.ai.azure.openai.AzureOpenAiChatOptions; 12 import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
12 import org.springframework.ai.chat.messages.*; 13 import org.springframework.ai.chat.messages.*;
13 import org.springframework.ai.chat.prompt.ChatOptions; 14 import org.springframework.ai.chat.prompt.ChatOptions;
@@ -67,6 +68,9 @@ public class AiUtils { @@ -67,6 +68,9 @@ public class AiUtils {
67 case AZURE_OPENAI: 68 case AZURE_OPENAI:
68 return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens) 69 return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
69 .toolNames(toolNames).toolContext(toolContext).build(); 70 .toolNames(toolNames).toolContext(toolContext).build();
  71 + case ANTHROPIC:
  72 + return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
  73 + .toolNames(toolNames).toolContext(toolContext).build();
70 case OLLAMA: 74 case OLLAMA:
71 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens) 75 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
72 .toolNames(toolNames).toolContext(toolContext).build(); 76 .toolNames(toolNames).toolContext(toolContext).build();
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.ai.anthropic.AnthropicChatModel;
  6 +import org.springframework.ai.anthropic.api.AnthropicApi;
  7 +import org.springframework.ai.chat.messages.Message;
  8 +import org.springframework.ai.chat.messages.SystemMessage;
  9 +import org.springframework.ai.chat.messages.UserMessage;
  10 +import org.springframework.ai.chat.model.ChatResponse;
  11 +import org.springframework.ai.chat.prompt.Prompt;
  12 +import reactor.core.publisher.Flux;
  13 +
  14 +import java.util.ArrayList;
  15 +import java.util.List;
  16 +
  17 +/**
  18 + * {@link AnthropicChatModel} 集成测试类
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +public class AnthropicChatModelTest {
  23 +
  24 + private final AnthropicChatModel chatModel = AnthropicChatModel.builder()
  25 + .anthropicApi(AnthropicApi.builder()
  26 + .apiKey("sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942")
  27 + .baseUrl("https://aihubmix.com")
  28 + .build())
  29 + .build();
  30 +
  31 + @Test
  32 + @Disabled
  33 + public void testCall() {
  34 + // 准备参数
  35 + List<Message> messages = new ArrayList<>();
  36 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  37 + messages.add(new UserMessage("1 + 1 = ?"));
  38 +
  39 + // 调用
  40 + ChatResponse response = chatModel.call(new Prompt(messages));
  41 + // 打印结果
  42 + System.out.println(response);
  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(System.out::println).then().block();
  57 + }
  58 +
  59 +}
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
@@ -16,8 +16,11 @@ import org.springframework.ai.image.ImageResponse; @@ -16,8 +16,11 @@ import org.springframework.ai.image.ImageResponse;
16 */ 16 */
17 public class TongYiImagesModelTest { 17 public class TongYiImagesModelTest {
18 18
19 - private final DashScopeImageModel imageModel = new DashScopeImageModel(  
20 - new DashScopeImageApi("sk-7d903764249848cfa912733146da12d1")); 19 + private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
  20 + .dashScopeApi(DashScopeImageApi.builder()
  21 + .apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
  22 + .build())
  23 + .build();
21 24
22 @Test 25 @Test
23 @Disabled 26 @Disabled
yudao-server/src/main/resources/application.yaml
@@ -175,7 +175,8 @@ spring: @@ -175,7 +175,8 @@ spring:
175 azure: # OpenAI 微软 175 azure: # OpenAI 微软
176 openai: 176 openai:
177 endpoint: https://eastusprejade.openai.azure.com 177 endpoint: https://eastusprejade.openai.azure.com
178 - api-key: xxx 178 + anthropic: # Anthropic Claude
  179 + api-key: sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942
179 ollama: 180 ollama:
180 base-url: http://127.0.0.1:11434 181 base-url: http://127.0.0.1:11434
181 chat: 182 chat: