Commit 83bd96d6725b0769808ea5c83b43d54e04859c6e
1 parent
b4538568
【功能新增】AI:集成 Azure 的 OpenAI 模型
Showing
7 changed files
with
47 additions
and
6 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/DocServiceImpl.java
| ... | ... | @@ -7,7 +7,6 @@ import org.springframework.ai.reader.tika.TikaDocumentReader; |
| 7 | 7 | import org.springframework.ai.transformer.splitter.TokenTextSplitter; |
| 8 | 8 | import org.springframework.ai.vectorstore.RedisVectorStore; |
| 9 | 9 | import org.springframework.beans.factory.annotation.Value; |
| 10 | -import org.springframework.stereotype.Service; | |
| 11 | 10 | |
| 12 | 11 | import java.util.List; |
| 13 | 12 | |
| ... | ... | @@ -16,7 +15,7 @@ import java.util.List; |
| 16 | 15 | * |
| 17 | 16 | * @author xiaoxin |
| 18 | 17 | */ |
| 19 | -@Service | |
| 18 | +//@Service // TODO 芋艿:临时注释,避免无法启动 | |
| 20 | 19 | @Slf4j |
| 21 | 20 | public class DocServiceImpl implements DocService { |
| 22 | 21 | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
| ... | ... | @@ -23,7 +23,6 @@ |
| 23 | 23 | <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId> |
| 24 | 24 | <version>${spring-ai.version}</version> |
| 25 | 25 | </dependency> |
| 26 | - | |
| 27 | 26 | <dependency> |
| 28 | 27 | <groupId>org.springframework.ai</groupId> |
| 29 | 28 | <artifactId>spring-ai-openai-spring-boot-starter</artifactId> |
| ... | ... | @@ -31,6 +30,11 @@ |
| 31 | 30 | </dependency> |
| 32 | 31 | <dependency> |
| 33 | 32 | <groupId>org.springframework.ai</groupId> |
| 33 | + <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId> | |
| 34 | + <version>${spring-ai.version}</version> | |
| 35 | + </dependency> | |
| 36 | + <dependency> | |
| 37 | + <groupId>org.springframework.ai</groupId> | |
| 34 | 38 | <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> |
| 35 | 39 | <version>${spring-ai.version}</version> |
| 36 | 40 | </dependency> | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
| ... | ... | @@ -12,6 +12,7 @@ import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration; |
| 12 | 12 | import lombok.extern.slf4j.Slf4j; |
| 13 | 13 | import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties; |
| 14 | 14 | import org.springframework.ai.document.MetadataMode; |
| 15 | +import org.springframework.ai.embedding.EmbeddingModel; | |
| 15 | 16 | import org.springframework.ai.transformer.splitter.TokenTextSplitter; |
| 16 | 17 | import org.springframework.ai.transformers.TransformersEmbeddingModel; |
| 17 | 18 | import org.springframework.ai.vectorstore.RedisVectorStore; |
| ... | ... | @@ -21,6 +22,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisProperties; |
| 21 | 22 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| 22 | 23 | import org.springframework.context.annotation.Bean; |
| 23 | 24 | import org.springframework.context.annotation.Import; |
| 25 | +import org.springframework.context.annotation.Lazy; | |
| 24 | 26 | import redis.clients.jedis.JedisPooled; |
| 25 | 27 | |
| 26 | 28 | /** |
| ... | ... | @@ -82,7 +84,8 @@ public class YudaoAiAutoConfiguration { |
| 82 | 84 | |
| 83 | 85 | // ========== rag 相关 ========== |
| 84 | 86 | @Bean |
| 85 | - public TransformersEmbeddingModel transformersEmbeddingClient() { | |
| 87 | + @Lazy // TODO 芋艿:临时注释,避免无法启动 | |
| 88 | + public EmbeddingModel transformersEmbeddingClient() { | |
| 86 | 89 | return new TransformersEmbeddingModel(MetadataMode.EMBED); |
| 87 | 90 | } |
| 88 | 91 | |
| ... | ... | @@ -90,6 +93,7 @@ public class YudaoAiAutoConfiguration { |
| 90 | 93 | * 我们启动有加载很多 Embedding 模型,不晓得取哪个好,先 new 个 TransformersEmbeddingModel 跑 |
| 91 | 94 | */ |
| 92 | 95 | @Bean |
| 96 | + @Lazy // TODO 芋艿:临时注释,避免无法启动 | |
| 93 | 97 | public RedisVectorStore vectorStore(TransformersEmbeddingModel transformersEmbeddingModel, RedisVectorStoreProperties properties, |
| 94 | 98 | RedisProperties redisProperties) { |
| 95 | 99 | var config = RedisVectorStore.RedisVectorStoreConfig.builder() |
| ... | ... | @@ -105,6 +109,7 @@ public class YudaoAiAutoConfiguration { |
| 105 | 109 | } |
| 106 | 110 | |
| 107 | 111 | @Bean |
| 112 | + @Lazy // TODO 芋艿:临时注释,避免无法启动 | |
| 108 | 113 | public TokenTextSplitter tokenTextSplitter() { |
| 109 | 114 | return new TokenTextSplitter(500, 100, 5, 10000, true); |
| 110 | 115 | } | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java
| ... | ... | @@ -22,7 +22,8 @@ public enum AiPlatformEnum { |
| 22 | 22 | |
| 23 | 23 | // ========== 国外平台 ========== |
| 24 | 24 | |
| 25 | - OPENAI("OpenAI", "OpenAI"), | |
| 25 | + OPENAI("OpenAI", "OpenAI"), // OpenAI 官方 | |
| 26 | + AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软 | |
| 26 | 27 | OLLAMA("Ollama", "Ollama"), |
| 27 | 28 | |
| 28 | 29 | STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
| ... | ... | @@ -21,6 +21,10 @@ import com.alibaba.cloud.ai.tongyi.image.TongYiImagesModel; |
| 21 | 21 | import com.alibaba.cloud.ai.tongyi.image.TongYiImagesProperties; |
| 22 | 22 | import com.alibaba.dashscope.aigc.generation.Generation; |
| 23 | 23 | import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis; |
| 24 | +import com.azure.ai.openai.OpenAIClient; | |
| 25 | +import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration; | |
| 26 | +import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties; | |
| 27 | +import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiConnectionProperties; | |
| 24 | 28 | import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration; |
| 25 | 29 | import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration; |
| 26 | 30 | import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration; |
| ... | ... | @@ -31,6 +35,7 @@ import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiAutoConfiguration; |
| 31 | 35 | import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiChatProperties; |
| 32 | 36 | import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties; |
| 33 | 37 | import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiImageProperties; |
| 38 | +import org.springframework.ai.azure.openai.AzureOpenAiChatModel; | |
| 34 | 39 | import org.springframework.ai.chat.model.ChatModel; |
| 35 | 40 | import org.springframework.ai.image.ImageModel; |
| 36 | 41 | import org.springframework.ai.model.function.FunctionCallbackContext; |
| ... | ... | @@ -82,6 +87,8 @@ public class AiModelFactoryImpl implements AiModelFactory { |
| 82 | 87 | return buildXingHuoChatModel(apiKey); |
| 83 | 88 | case OPENAI: |
| 84 | 89 | return buildOpenAiChatModel(apiKey, url); |
| 90 | + case AZURE_OPENAI: | |
| 91 | + return buildAzureOpenAiChatModel(apiKey, url); | |
| 85 | 92 | case OLLAMA: |
| 86 | 93 | return buildOllamaChatModel(url); |
| 87 | 94 | default: |
| ... | ... | @@ -106,6 +113,8 @@ public class AiModelFactoryImpl implements AiModelFactory { |
| 106 | 113 | return SpringUtil.getBean(XingHuoChatModel.class); |
| 107 | 114 | case OPENAI: |
| 108 | 115 | return SpringUtil.getBean(OpenAiChatModel.class); |
| 116 | + case AZURE_OPENAI: | |
| 117 | + return SpringUtil.getBean(AzureOpenAiChatModel.class); | |
| 109 | 118 | case OLLAMA: |
| 110 | 119 | return SpringUtil.getBean(OllamaChatModel.class); |
| 111 | 120 | default: |
| ... | ... | @@ -269,6 +278,21 @@ public class AiModelFactoryImpl implements AiModelFactory { |
| 269 | 278 | } |
| 270 | 279 | |
| 271 | 280 | /** |
| 281 | + * 可参考 {@link AzureOpenAiAutoConfiguration} | |
| 282 | + */ | |
| 283 | + private static AzureOpenAiChatModel buildAzureOpenAiChatModel(String apiKey, String url) { | |
| 284 | + AzureOpenAiAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiAutoConfiguration(); | |
| 285 | + // 创建 OpenAIClient 对象 | |
| 286 | + AzureOpenAiConnectionProperties connectionProperties = new AzureOpenAiConnectionProperties(); | |
| 287 | + connectionProperties.setApiKey(apiKey); | |
| 288 | + connectionProperties.setEndpoint(url); | |
| 289 | + OpenAIClient openAIClient = azureOpenAiAutoConfiguration.openAIClient(connectionProperties); | |
| 290 | + // 获取 AzureOpenAiChatProperties 对象 | |
| 291 | + AzureOpenAiChatProperties chatProperties = SpringUtil.getBean(AzureOpenAiChatProperties.class); | |
| 292 | + return azureOpenAiAutoConfiguration.azureOpenAiChatModel(openAIClient, chatProperties, null, null); | |
| 293 | + } | |
| 294 | + | |
| 295 | + /** | |
| 272 | 296 | * 可参考 {@link OpenAiAutoConfiguration} |
| 273 | 297 | */ |
| 274 | 298 | private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) { | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; |
| 5 | 5 | import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions; |
| 6 | 6 | import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions; |
| 7 | 7 | import com.alibaba.cloud.ai.tongyi.chat.TongYiChatOptions; |
| 8 | +import org.springframework.ai.azure.openai.AzureOpenAiChatOptions; | |
| 8 | 9 | import org.springframework.ai.chat.messages.*; |
| 9 | 10 | import org.springframework.ai.chat.prompt.ChatOptions; |
| 10 | 11 | import org.springframework.ai.ollama.api.OllamaOptions; |
| ... | ... | @@ -35,6 +36,9 @@ public class AiUtils { |
| 35 | 36 | return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build(); |
| 36 | 37 | case OPENAI: |
| 37 | 38 | return OpenAiChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build(); |
| 39 | + case AZURE_OPENAI: | |
| 40 | + // TODO 芋艿:貌似没 model 字段???! | |
| 41 | + return AzureOpenAiChatOptions.builder().withDeploymentName(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build(); | |
| 38 | 42 | case OLLAMA: |
| 39 | 43 | return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens); |
| 40 | 44 | default: | ... | ... |
yudao-server/src/main/resources/application.yaml
| ... | ... | @@ -162,9 +162,13 @@ spring: |
| 162 | 162 | secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK |
| 163 | 163 | zhipuai: # 智谱 AI |
| 164 | 164 | api-key: 32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs |
| 165 | - openai: | |
| 165 | + openai: # OpenAI 官方 | |
| 166 | 166 | api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z |
| 167 | 167 | base-url: https://api.gptsapi.net |
| 168 | + azure: # OpenAI 微软 | |
| 169 | + openai: | |
| 170 | + endpoint: https://eastusprejade.openai.azure.com | |
| 171 | + api-key: xxx | |
| 168 | 172 | ollama: |
| 169 | 173 | base-url: http://127.0.0.1:11434 |
| 170 | 174 | chat: | ... | ... |