Commit 96a743157d481ef742f7237b9e30a8f453bb0fb5
1 parent
2fbb9f88
feat:【ai 大模型】增加 anthropic 接入
Showing
7 changed files
with
98 additions
and
3 deletions
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<String> { |
| 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: | ... | ... |