Parcourir la source

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

YunaiV il y a 9 mois
Parent
commit
96a743157d

+ 5 - 0
yudao-module-ai/pom.xml

@@ -84,6 +84,11 @@
             <artifactId>spring-ai-starter-model-azure-openai</artifactId>
             <version>${spring-ai.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.ai</groupId>
+            <artifactId>spring-ai-starter-model-anthropic</artifactId>
+            <version>${spring-ai.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springframework.ai</groupId>
             <artifactId>spring-ai-starter-model-deepseek</artifactId>

+ 1 - 0
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java

@@ -33,6 +33,7 @@ public enum AiPlatformEnum implements ArrayValuable<String> {
 
     OPENAI("OpenAI", "OpenAI"), // OpenAI 官方
     AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软
+    ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude
     OLLAMA("Ollama", "Ollama"),
 
     STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI

+ 22 - 0
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;
 import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
 import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
 import org.springframework.ai.minimax.api.MiniMaxApi;
+import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
 import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
@@ -93,6 +94,8 @@ import org.springframework.ai.openai.OpenAiImageModel;
 import org.springframework.ai.openai.api.OpenAiApi;
 import org.springframework.ai.openai.api.OpenAiImageApi;
 import org.springframework.ai.openai.api.common.OpenAiApiConstants;
+import org.springframework.ai.anthropic.AnthropicChatModel;
+import org.springframework.ai.anthropic.api.AnthropicApi;
 import org.springframework.ai.stabilityai.StabilityAiImageModel;
 import org.springframework.ai.stabilityai.api.StabilityAiApi;
 import org.springframework.ai.vectorstore.SimpleVectorStore;
@@ -168,6 +171,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
                     return buildOpenAiChatModel(apiKey, url);
                 case AZURE_OPENAI:
                     return buildAzureOpenAiChatModel(apiKey, url);
+                case ANTHROPIC:
+                    return buildAnthropicChatModel(apiKey, url);
                 case OLLAMA:
                     return buildOllamaChatModel(url);
                 default:
@@ -206,6 +211,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
                 return SpringUtil.getBean(OpenAiChatModel.class);
             case AZURE_OPENAI:
                 return SpringUtil.getBean(AzureOpenAiChatModel.class);
+            case ANTHROPIC:
+                return SpringUtil.getBean(AnthropicChatModel.class);
             case OLLAMA:
                 return SpringUtil.getBean(OllamaChatModel.class);
             default:
@@ -512,6 +519,21 @@ public class AiModelFactoryImpl implements AiModelFactory {
                 .build();
     }
 
+    /**
+     * 可参考 {@link AnthropicChatAutoConfiguration} 的 anthropicApi 方法
+     */
+    private static AnthropicChatModel buildAnthropicChatModel(String apiKey, String url) {
+        AnthropicApi.Builder builder = AnthropicApi.builder().apiKey(apiKey);
+        if (StrUtil.isNotEmpty(url)) {
+            builder.baseUrl(url);
+        }
+        AnthropicApi anthropicApi = builder.build();
+        return AnthropicChatModel.builder()
+                .anthropicApi(anthropicApi)
+                .toolCallingManager(getToolCallingManager())
+                .build();
+    }
+
     /**
      * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法
      */

+ 4 - 0
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;
 import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
 import org.springaicommunity.moonshot.MoonshotChatOptions;
 import org.springaicommunity.qianfan.QianFanChatOptions;
+import org.springframework.ai.anthropic.AnthropicChatOptions;
 import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
 import org.springframework.ai.chat.messages.*;
 import org.springframework.ai.chat.prompt.ChatOptions;
@@ -67,6 +68,9 @@ public class AiUtils {
             case AZURE_OPENAI:
                 return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
                         .toolNames(toolNames).toolContext(toolContext).build();
+            case ANTHROPIC:
+                return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
+                        .toolNames(toolNames).toolContext(toolContext).build();
             case OLLAMA:
                 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
                         .toolNames(toolNames).toolContext(toolContext).build();

+ 59 - 0
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java

@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.anthropic.AnthropicChatModel;
+import org.springframework.ai.anthropic.api.AnthropicApi;
+import org.springframework.ai.chat.messages.Message;
+import org.springframework.ai.chat.messages.SystemMessage;
+import org.springframework.ai.chat.messages.UserMessage;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.Prompt;
+import reactor.core.publisher.Flux;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link AnthropicChatModel} 集成测试类
+ *
+ * @author 芋道源码
+ */
+public class AnthropicChatModelTest {
+
+    private final AnthropicChatModel chatModel = AnthropicChatModel.builder()
+            .anthropicApi(AnthropicApi.builder()
+                    .apiKey("sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942")
+                    .baseUrl("https://aihubmix.com")
+                    .build())
+            .build();
+
+    @Test
+    @Disabled
+    public void testCall() {
+        // 准备参数
+        List<Message> messages = new ArrayList<>();
+        messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
+        messages.add(new UserMessage("1 + 1 = ?"));
+
+        // 调用
+        ChatResponse response = chatModel.call(new Prompt(messages));
+        // 打印结果
+        System.out.println(response);
+    }
+
+    @Test
+    @Disabled
+    public void testStream() {
+        // 准备参数
+        List<Message> messages = new ArrayList<>();
+        messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
+        messages.add(new UserMessage("1 + 1 = ?"));
+
+        // 调用
+        Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
+        // 打印结果
+        flux.doOnNext(System.out::println).then().block();
+    }
+
+}

+ 5 - 2
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;
  */
 public class TongYiImagesModelTest {
 
-    private final DashScopeImageModel imageModel = new DashScopeImageModel(
-            new DashScopeImageApi("sk-7d903764249848cfa912733146da12d1"));
+    private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
+            .dashScopeApi(DashScopeImageApi.builder()
+                    .apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
+                    .build())
+            .build();
 
     @Test
     @Disabled

+ 2 - 1
yudao-server/src/main/resources/application.yaml

@@ -175,7 +175,8 @@ spring:
     azure: # OpenAI 微软
       openai:
         endpoint: https://eastusprejade.openai.azure.com
-        api-key: xxx
+    anthropic: # Anthropic Claude
+      api-key: sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942
     ollama:
       base-url: http://127.0.0.1:11434
       chat: