Commit 96a743157d481ef742f7237b9e30a8f453bb0fb5

Authored by YunaiV
1 parent 2fbb9f88

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

yudao-module-ai/pom.xml
... ... @@ -86,6 +86,11 @@
86 86 </dependency>
87 87 <dependency>
88 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 94 <artifactId>spring-ai-starter-model-deepseek</artifactId>
90 95 <version>${spring-ai.version}</version>
91 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 33  
34 34 OPENAI("OpenAI", "OpenAI"), // OpenAI 官方
35 35 AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软
  36 + ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude
36 37 OLLAMA("Ollama", "Ollama"),
37 38  
38 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 67 import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
68 68 import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
69 69 import org.springframework.ai.minimax.api.MiniMaxApi;
  70 +import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
70 71 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
71 72 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
72 73 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
... ... @@ -93,6 +94,8 @@ import org.springframework.ai.openai.OpenAiImageModel;
93 94 import org.springframework.ai.openai.api.OpenAiApi;
94 95 import org.springframework.ai.openai.api.OpenAiImageApi;
95 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 99 import org.springframework.ai.stabilityai.StabilityAiImageModel;
97 100 import org.springframework.ai.stabilityai.api.StabilityAiApi;
98 101 import org.springframework.ai.vectorstore.SimpleVectorStore;
... ... @@ -168,6 +171,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
168 171 return buildOpenAiChatModel(apiKey, url);
169 172 case AZURE_OPENAI:
170 173 return buildAzureOpenAiChatModel(apiKey, url);
  174 + case ANTHROPIC:
  175 + return buildAnthropicChatModel(apiKey, url);
171 176 case OLLAMA:
172 177 return buildOllamaChatModel(url);
173 178 default:
... ... @@ -206,6 +211,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
206 211 return SpringUtil.getBean(OpenAiChatModel.class);
207 212 case AZURE_OPENAI:
208 213 return SpringUtil.getBean(AzureOpenAiChatModel.class);
  214 + case ANTHROPIC:
  215 + return SpringUtil.getBean(AnthropicChatModel.class);
209 216 case OLLAMA:
210 217 return SpringUtil.getBean(OllamaChatModel.class);
211 218 default:
... ... @@ -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 538 * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法
517 539 */
518 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 8 import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
9 9 import org.springaicommunity.moonshot.MoonshotChatOptions;
10 10 import org.springaicommunity.qianfan.QianFanChatOptions;
  11 +import org.springframework.ai.anthropic.AnthropicChatOptions;
11 12 import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
12 13 import org.springframework.ai.chat.messages.*;
13 14 import org.springframework.ai.chat.prompt.ChatOptions;
... ... @@ -67,6 +68,9 @@ public class AiUtils {
67 68 case AZURE_OPENAI:
68 69 return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
69 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 74 case OLLAMA:
71 75 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
72 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 16 */
17 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 25 @Test
23 26 @Disabled
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -175,7 +175,8 @@ spring:
175 175 azure: # OpenAI 微软
176 176 openai:
177 177 endpoint: https://eastusprejade.openai.azure.com
178   - api-key: xxx
  178 + anthropic: # Anthropic Claude
  179 + api-key: sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942
179 180 ollama:
180 181 base-url: http://127.0.0.1:11434
181 182 chat:
... ...