diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml
index 3270b44d1d..b81be3aa42 100644
--- a/yudao-module-ai/pom.xml
+++ b/yudao-module-ai/pom.xml
@@ -84,6 +84,11 @@
spring-ai-starter-model-azure-openai
${spring-ai.version}
+
+ org.springframework.ai
+ spring-ai-starter-model-anthropic
+ ${spring-ai.version}
+
org.springframework.ai
spring-ai-starter-model-deepseek
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
index cebe0b9568..aa0ef5d6e2 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
@@ -33,6 +33,7 @@ public enum AiPlatformEnum implements ArrayValuable {
OPENAI("OpenAI", "OpenAI"), // OpenAI 官方
AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软
+ ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude
OLLAMA("Ollama", "Ollama"),
STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
index 3387c9b6b1..d6a26ee0e3 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
+++ b/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 方法
*/
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
index 0744ff6307..624d07340b 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
+++ b/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();
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
new file mode 100644
index 0000000000..9bb98cf6ef
--- /dev/null
+++ b/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 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 messages = new ArrayList<>();
+ messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
+ messages.add(new UserMessage("1 + 1 = ?"));
+
+ // 调用
+ Flux flux = chatModel.stream(new Prompt(messages));
+ // 打印结果
+ flux.doOnNext(System.out::println).then().block();
+ }
+
+}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
index 1bfd9c8c05..b31c07696d 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
+++ b/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
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index c0d79ac881..b9cfd2ae67 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/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: