diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
index cb4ca4c77..dc1af4213 100644
--- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
+++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
@@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenOptions;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -33,6 +32,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
+import org.springframework.ai.qianfan.QianFanChatOptions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
@@ -191,8 +191,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
case OLLAMA:
return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens);
case YI_YAN:
- // TODO @fan:增加一个 model
- return new YiYanChatOptions().setTemperature(temperatureF).setMaxOutputTokens(maxTokens);
+ // TODO 芋艿:貌似 model 只要一设置,就报错
+// return QianFanChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
+ return QianFanChatOptions.builder().withTemperature(temperatureF).withMaxTokens(maxTokens).build();
case XING_HUO:
return new XingHuoOptions().setChatModel(XingHuoChatModel.valueOfModel(model)).setTemperature(temperatureF)
.setMaxTokens(maxTokens);
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml b/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
index 2cea7a4ad..143049c58 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
@@ -43,6 +43,13 @@
yudao-common
+
+
+ group.springframework.ai
+ spring-ai-qianfan-spring-boot-starter
+ 1.1.0
+
+
com.alibaba
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
index d62861571..1119bb915 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
@@ -11,9 +11,6 @@ import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XingHuoApi;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -78,27 +75,6 @@ public class YudaoAiAutoConfiguration {
);
}
- @Bean
- @ConditionalOnProperty(value = "yudao.ai.yiyan.enable", havingValue = "true")
- public YiYanChatClient yiYanChatClient(YudaoAiProperties yudaoAiProperties) {
- YudaoAiProperties.YiYanProperties yiYanProperties = yudaoAiProperties.getYiyan();
- // 转换配置
- YiYanChatOptions yiYanOptions = new YiYanChatOptions();
-// yiYanOptions.setTopK(yiYanProperties.getTopK()); TODO 芋艿:后续弄
- yiYanOptions.setTopP(yiYanProperties.getTopP());
- yiYanOptions.setTemperature(yiYanProperties.getTemperature());
- yiYanOptions.setMaxOutputTokens(yiYanProperties.getMaxTokens());
- return new YiYanChatClient(
- new YiYanApi(
- yiYanProperties.getAppKey(),
- yiYanProperties.getSecretKey(),
- yiYanProperties.getModel(),
- yiYanProperties.getRefreshTokenSecondTime()
- ),
- yiYanOptions
- );
- }
-
@Bean
@ConditionalOnProperty(value = "yudao.ai.midjourney.enable", havingValue = "true")
public MidjourneyApi midjourneyApi(YudaoAiProperties yudaoAiProperties) {
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java
index ac2d5ce7d..ef1663f28 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiProperties.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.ai.config;
import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.ai.autoconfigure.openai.OpenAiImageProperties;
@@ -23,7 +22,6 @@ public class YudaoAiProperties {
private QianWenProperties qianwen;
private XingHuoProperties xinghuo;
- private YiYanProperties yiyan;
private OpenAiImageProperties openAiImage;
private MidjourneyProperties midjourney;
private SunoProperties suno;
@@ -63,7 +61,6 @@ public class YudaoAiProperties {
}
@Data
- @Accessors(chain = true)
public static class XingHuoProperties extends ChatProperties {
private String appId;
@@ -73,28 +70,6 @@ public class YudaoAiProperties {
}
- @Data
- @Accessors(chain = true)
- public static class YiYanProperties extends ChatProperties {
-
- /**
- * appKey
- */
- private String appKey;
- /**
- * secretKey
- */
- private String secretKey;
- /**
- * 模型
- */
- private YiYanChatModel model = YiYanChatModel.ERNIE4_3_5_8K;
- /**
- * token 刷新时间(默认 86400 = 24小时)
- */
- private int refreshTokenSecondTime = 86400;
- }
-
@Data
public static class MidjourneyProperties {
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java
index e72bc866a..0e6597a6b 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java
@@ -16,10 +16,11 @@ import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal;
import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatClient;
import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XingHuoApi;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;
import org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration;
import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
+import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration;
+import org.springframework.ai.autoconfigure.qianfan.QianFanChatProperties;
+import org.springframework.ai.autoconfigure.qianfan.QianFanConnectionProperties;
import org.springframework.ai.chat.model.StreamingChatModel;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.ollama.OllamaChatModel;
@@ -29,8 +30,12 @@ import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.api.ApiUtils;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiImageApi;
+import org.springframework.ai.qianfan.QianFanChatModel;
+import org.springframework.ai.qianfan.api.QianFanApi;
import org.springframework.ai.stabilityai.StabilityAiImageModel;
import org.springframework.ai.stabilityai.api.StabilityAiApi;
+import org.springframework.retry.support.RetryTemplate;
+import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
import java.util.List;
@@ -75,7 +80,7 @@ public class AiClientFactoryImpl implements AiClientFactory {
case OLLAMA:
return SpringUtil.getBean(OllamaChatModel.class);
case YI_YAN:
- return SpringUtil.getBean(YiYanChatClient.class);
+ return SpringUtil.getBean(QianFanChatModel.class);
case XING_HUO:
return SpringUtil.getBean(XingHuoChatClient.class);
case QIAN_WEN:
@@ -153,15 +158,16 @@ public class AiClientFactoryImpl implements AiClientFactory {
}
/**
- * 可参考 {@link YudaoAiAutoConfiguration#yiYanChatClient(YudaoAiProperties)}
+ * 可参考 {@link QianFanAutoConfiguration#qianFanChatModel(QianFanConnectionProperties, QianFanChatProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)}
*/
- private static YiYanChatClient buildYiYanChatClient(String key) {
+ private static QianFanChatModel buildYiYanChatClient(String key) {
+ // TODO 芋艿:貌似目前设置,request 势必会报错
List keys = StrUtil.split(key, '|');
Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
String appKey = keys.get(0);
String secretKey = keys.get(1);
- YiYanApi yiYanApi = new YiYanApi(appKey, secretKey, YiYanApi.DEFAULT_CHAT_MODEL, 0);
- return new YiYanChatClient(yiYanApi);
+ QianFanApi qianFanApi = new QianFanApi(appKey, secretKey);
+ return new QianFanChatModel(qianFanApi);
}
/**
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/tongyi/QianWenChatClient.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/tongyi/QianWenChatClient.java
index c3f4b4a5b..b10532a4f 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/tongyi/QianWenChatClient.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/tongyi/QianWenChatClient.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.framework.ai.core.model.tongyi;
import cn.iocoder.yudao.framework.ai.core.exception.ChatException;
import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.exception.YiYanApiException;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.common.Message;
@@ -59,7 +58,7 @@ public class QianWenChatClient implements ChatModel, StreamingChatModel {
public final RetryTemplate retryTemplate = RetryTemplate.builder()
// 最大重试次数 10
.maxAttempts(10)
- .retryOn(YiYanApiException.class)
+ .retryOn(Exception.class) // TODO 芋艿:临时这么写
// 最大重试5次,第一次间隔3000ms,第二次3000ms * 2,第三次3000ms * 3,以此类推,最大间隔3 * 60000ms
.exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000))
.withListener(new RetryListener() {
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatClient.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatClient.java
deleted file mode 100644
index a4fa1d3f5..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatClient.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.iocoder.yudao.framework.ai.core.exception.ChatException;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatCompletionRequest;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatCompletionResponse;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.exception.YiYanApiException;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.ai.chat.client.ChatClient;
-import org.springframework.ai.chat.messages.Message;
-import org.springframework.ai.chat.messages.MessageType;
-import org.springframework.ai.chat.model.ChatModel;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.model.Generation;
-import org.springframework.ai.chat.model.StreamingChatModel;
-import org.springframework.ai.chat.prompt.ChatOptions;
-import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.http.ResponseEntity;
-import org.springframework.retry.RetryCallback;
-import org.springframework.retry.RetryContext;
-import org.springframework.retry.RetryListener;
-import org.springframework.retry.support.RetryTemplate;
-import org.springframework.util.Assert;
-import reactor.core.publisher.Flux;
-
-import java.time.Duration;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * 文心一言的 {@link ChatClient} 实现类
- *
- * @author fansili
- */
-@Slf4j
-public class YiYanChatClient implements ChatModel, StreamingChatModel {
-
- private final YiYanApi yiYanApi;
-
- private YiYanChatOptions defaultOptions;
-
- // TODO @fan:参考 OpenAiChatClient 调整下 retryTemplate;使用 RetryUtils.DEFAULT_RETRY_TEMPLATE;加允许传入?
-
- public YiYanChatClient(YiYanApi yiYanApi) {
- this.yiYanApi = yiYanApi;
- // TODO @fan:这个情况,是不是搞个 defaultOptions;OpenAiChatOptions.builder().withModel(OpenAiApi.DEFAULT_CHAT_MODEL).withTemperature(0.7f).build()
- }
-
- public YiYanChatClient(YiYanApi yiYanApi, YiYanChatOptions defaultOptions) {
- Assert.notNull(yiYanApi, "OllamaApi must not be null");
- Assert.notNull(defaultOptions, "DefaultOptions must not be null");
- this.yiYanApi = yiYanApi;
- this.defaultOptions = defaultOptions;
- }
-
- public final RetryTemplate retryTemplate = RetryTemplate.builder()
- .maxAttempts(10)
- .retryOn(YiYanApiException.class)
- .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000))
- .withListener(new RetryListener() {
-
- @Override
- public void onError(RetryContext context,
- RetryCallback callback, Throwable throwable) {
- log.warn("重试异常:" + context.getRetryCount(), throwable);
- }
-
- })
- .build();
-
- @Override
- public ChatResponse call(Prompt prompt) {
- YiYanChatCompletionRequest request = createRequest(prompt, false);
- return this.retryTemplate.execute(ctx -> {
- // 发送请求
- ResponseEntity response = yiYanApi.chatCompletionEntity(request);
- // 获取结果封装 ChatResponse
- YiYanChatCompletionResponse chatCompletion = response.getBody();
- if (chatCompletion == null) {
- log.warn("No chat completion returned for prompt: {}", prompt);
- return new ChatResponse(List.of());
- } else {
- // TODO @fan:chatResponseMetadata,参考 OpenAiChatResponseMetadata.from(completionEntity.getBody())
- return new ChatResponse(List.of(new Generation(chatCompletion.getResult())));
- }
- });
- }
-
- @Override
- public ChatOptions getDefaultOptions() {
- // TODO 芋艿:需要跟进下
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Flux stream(Prompt prompt) {
- YiYanChatCompletionRequest request = this.createRequest(prompt, true);
- return this.retryTemplate.execute(ctx -> {
- // 调用 callWithFunctionSupport 发送请求
- Flux response = this.yiYanApi.chatCompletionStream(request);
- return response.map(chunk -> {
- // TODO @fan:ChatResponseMetadata chatResponseMetadata
- return new ChatResponse(List.of(new Generation(chunk.getResult())));
- });
- });
- }
-
- private YiYanChatCompletionRequest createRequest(Prompt prompt, boolean stream) {
- // 参考 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t 文档,system 是独立字段
- // 1.1 获取 user 和 assistant
- List messageList = prompt.getInstructions().stream()
- // 过滤 system
- .filter(msg -> MessageType.SYSTEM != msg.getMessageType())
- .map(message -> new YiYanChatCompletionRequest.Message()
- .setRole(message.getMessageType().getValue()).setContent(message.getContent())
- ).toList();
- // 1.2 获取 system
- String systemPrompt = prompt.getInstructions().stream()
- .filter(message -> MessageType.SYSTEM == message.getMessageType())
- .map(Message::getContent)
- .collect(Collectors.joining());
-
- // 3. 创建 request
- YiYanChatCompletionRequest request = new YiYanChatCompletionRequest(messageList);
- // 复制 YiYanOptions 属性,到 request 中(这里 options 属性和 request 基本保持一致)
- YiYanChatOptions useOptions = getYiYanOptions(prompt);
- BeanUtil.copyProperties(useOptions, request);
- request.setTopP(useOptions.getTopP())
- .setMaxOutputTokens(useOptions.getMaxOutputTokens())
- .setTemperature(useOptions.getTemperature())
- .setSystem(systemPrompt)
- .setStream(stream);
- return request;
- }
-
- // TODO @fan:Options 的处理,参考下 OpenAiChatClient 的 createRequest
- private YiYanChatOptions getYiYanOptions(Prompt prompt) {
- // 两个都为null 则没有配置文件
- if (defaultOptions == null && prompt.getOptions() == null) {
- // TODO @fan:IllegalArgumentException 参数更好哈
- throw new ChatException("ChatOptions 未配置参数!");
- }
- // 优先使用 Prompt 里面的 ChatOptions
- ChatOptions options = defaultOptions;
- if (prompt.getOptions() != null) {
- options = (ChatOptions) prompt.getOptions();
- }
- // Prompt 里面是一个 ChatOptions,用户可以随意传入,这里做一下判断
- if (!(options instanceof YiYanChatOptions)) {
- // TODO @fan:IllegalArgumentException 参数更好哈
- // TODO @fan:需要兼容 ChatOptionsBuilder 创建出来的
- throw new ChatException("Prompt 传入的不是 YiYanOptions!");
- }
- // 转换 YiYanOptions
- return (YiYanChatOptions) options;
- }
-
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatOptions.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatOptions.java
deleted file mode 100644
index 817063c8f..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/YiYanChatOptions.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan;
-
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatCompletionRequest;
-import lombok.Data;
-import org.springframework.ai.chat.prompt.ChatOptions;
-
-import java.util.List;
-
-/**
- * 文心一言的 {@link ChatOptions} 实现类
- *
- * 字段说明:参考 ERNIE-4.0-8K
- *
- * @author fansili
- */
-@Data
-public class YiYanChatOptions implements ChatOptions {
-
- /**
- * functions 函数
- */
- private List functions;
- /**
- * temperature
- */
- private Float temperature;
- /**
- * topP
- */
- private Float topP;
- /**
- * 通过对已生成的token增加惩罚,减少重复生成的现象
- */
- private Float penaltyScore;
- /**
- * stream 模式请求
- */
- private Boolean stream;
- /**
- * system 提示
- */
- private String system;
- /**
- * 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成
- */
- private List stop;
- /**
- * 是否强制关闭实时搜索功能
- */
- private Boolean disableSearch;
- /**
- * 是否开启上角标返回
- */
- private Boolean enableCitation;
- /**
- * 输出最大 token
- */
- private Integer maxOutputTokens;
- /**
- * 响应格式 text、json_object
- */
- private String responseFormat;
- /**
- * 用户id
- */
- private String userId;
- /**
- * 在函数调用场景下,提示大模型选择指定的函数(非强制),说明:指定的函数名必须在functions中存在
- * tip: ERNIE-4.0-8K 模型没有这个字段
- */
- private String toolChoice;
-
- @Override
- public Float getTemperature() {
- return this.temperature;
- }
-
- @Override
- public Float getTopP() {
- return topP;
- }
-
- /**
- * 百度么有 topK
- */
- @Override
- public Integer getTopK() {
- return null;
- }
-
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanApi.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanApi.java
deleted file mode 100644
index 1de119bf7..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanApi.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;
-
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.exception.YiYanApiException;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import org.springframework.http.HttpStatusCode;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-/**
- * 文心一言 API
- *
- * @author fansili
- */
-public class YiYanApi {
-
- private static final String DEFAULT_BASE_URL = "https://aip.baidubce.com";
-
- private static final String AUTH_2_TOKEN_URI = "/oauth/2.0/token";
-
- public static final YiYanChatModel DEFAULT_CHAT_MODEL = YiYanChatModel.ERNIE4_0;
-
- private final String appKey;
- private final String secretKey;
- /**
- * TODO fan:这个是不是要有个刷新机制哈;如果目前不需要,可以删除掉 refreshTokenSecondTime;整体更简洁;
- */
- private final String token;
- /**
- * token 刷新时间(秒)
- */
- private int refreshTokenSecondTime;
- /**
- * 发送请求 webClient
- */
- private final WebClient webClient;
- /**
- * 使用的模型
- */
- private final YiYanChatModel useChatModel;
-
- // TODO fan:看看是不是去掉 refreshTokenSecondTime 字段
- public YiYanApi(String appKey, String secretKey, YiYanChatModel useChatModel, int refreshTokenSecondTime) {
- this.appKey = appKey;
- this.secretKey = secretKey;
- this.useChatModel = useChatModel;
- this.refreshTokenSecondTime = refreshTokenSecondTime;
- this.webClient = WebClient.builder().baseUrl(DEFAULT_BASE_URL).build();
- // 获取访问令牌
- token = getToken();
- }
-
- /**
- * 获得访问令牌
- *
- * @see 文档地址>
- * @return 访问令牌
- */
- private String getToken() {
- ResponseEntity response = this.webClient.post()
- .uri(uriBuilder -> uriBuilder.path(AUTH_2_TOKEN_URI)
- .queryParam("grant_type", "client_credentials")
- .queryParam("client_id", appKey)
- .queryParam("client_secret", secretKey)
- .build()
- )
- .retrieve()
- .toEntity(YiYanAuthResponse.class)
- .block();
- // 检查请求状态
- // TODO @fan:可以使用 response.getStatusCode().is2xxSuccessful()
- if (HttpStatusCode.valueOf(200) != response.getStatusCode()
- || response.getBody() == null) {
- // TODO @fan:可以使用 IllegalStateException 替代;另外,最好打印下返回;方便排错;
- throw new YiYanApiException("一言认证失败! api:https://aip.baidubce.com/oauth/2.0/token 请检查 client_id、client_secret 是否正确!");
- }
- return response.getBody().getAccess_token();
- }
-
- public ResponseEntity chatCompletionEntity(YiYanChatCompletionRequest request) {
- // TODO: 2024/3/10 小范 这里错误信息返回的结构不一样
-// {"error_code":17,"error_msg":"Open api daily request limit reached"}
- return this.webClient.post()
- .uri(uriBuilder
- -> uriBuilder.path(useChatModel.getUri())
- .queryParam("access_token", token)
- .build())
- .body(Mono.just(JsonUtils.toJsonString(request)), String.class)
- .retrieve()
- .toEntity(YiYanChatCompletionResponse.class)
- .block();
- }
-
- public Flux chatCompletionStream(YiYanChatCompletionRequest request) {
- return this.webClient.post()
- .uri(uriBuilder
- -> uriBuilder.path(useChatModel.getUri())
- .queryParam("access_token", token)
- .build())
- .body(Mono.just(request), YiYanChatCompletionRequest.class)
- .retrieve()
- .bodyToFlux(YiYanChatCompletionResponse.class);
- }
-
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanAuthResponse.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanAuthResponse.java
deleted file mode 100644
index 134b33994..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanAuthResponse.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;
-
-import lombok.Data;
-
-// TODO @fan:字段驼峰;字段注释都可以删除,贴个链接就好;
-/**
- * 获取文心一言的 access_token 的 Response
- *
- * @author fansili
- */
-@Data
-public class YiYanAuthResponse {
-
- /**
- * 访问凭证
- */
- private String access_token;
- /**
- * 有效期,Access Token的有效期。
- * 说明:单位是秒,有效期30天
- */
- private int expires_in;
- /**
- * 错误码,说明:响应失败时返回该字段,成功时不返回
- */
- private String error;
- /**
- * 错误描述信息,帮助理解和解决发生的错误
- * 说明:响应失败时返回该字段,成功时不返回
- */
- private String error_description;
- /**
- * 暂时未使用,可忽略
- */
- private String session_key;
- /**
- * 暂时未使用,可忽略
- */
- private String refresh_token;
- /**
- * 暂时未使用,可忽略
- */
- private String scope;
- /**
- * 暂时未使用,可忽略
- */
- private String session_secret;
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionRequest.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionRequest.java
deleted file mode 100644
index d496beae2..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionRequest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * 文心一言 Completion Request
- *
- * 百度千帆文档:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11
- *
- * @author fansili
- */
-@Data
-public class YiYanChatCompletionRequest {
-
- public YiYanChatCompletionRequest(List messages) {
- this.messages = messages;
- }
-
- /**
- * 聊天上下文信息
- */
- private List messages;
- /**
- * functions 函数
- */
- private List functions;
- /**
- * temperature
- */
- private Float temperature;
- /**
- * topP
- */
- @JsonProperty("top_p")
- private Float topP;
- /**
- * 通过对已生成的token增加惩罚,减少重复生成的现象
- */
- @JsonProperty("penalty_score")
- private Float penaltyScore;
- /**
- * stream 模式
- */
- private Boolean stream;
- /**
- * system 预设角色
- */
- private String system;
- /**
- * 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成
- */
- private List stop;
- /**
- * 是否强制关闭实时搜索功能
- */
- @JsonProperty("disable_search")
- private Boolean disableSearch;
- /**
- * 是否开启上角标返回
- */
- @JsonProperty("enable_citation")
- private Boolean enableCitation;
- /**
- * 最大输出 token 数
- */
- @JsonProperty("max_output_tokens")
- private Integer maxOutputTokens;
- /**
- * 返回格式 text、json_object
- */
- @JsonProperty("response_format")
- private String responseFormat;
- /**
- * 用户 id
- */
- @JsonProperty("user_id")
- private String userId;
- /**
- * 在函数调用场景下,提示大模型选择指定的函数(非强制),说明:指定的函数名必须在functions中存在
- * tip: ERNIE-4.0-8K 模型没有这个字段
- */
- @JsonProperty("tool_choice")
- private String toolChoice;
-
-
- @Data
- public static class Message {
-
- private String role;
-
- private String content;
-
- }
-
- @Data
- public static class ToolChoice {
- /**
- * 指定工具类型,function
- * 必填: 是
- */
- private String type;
- /**
- * 指定要使用的函数
- * 必填: 是
- */
- private Function function;
- /**
- * 指定要使用的函数名
- * 必填: 是
- */
- private String name;
- }
-
- @Data
- public static class Function {
- /**
- * 函数名
- * 必填: 是
- */
- private String name;
- /**
- * 函数描述
- * 必填: 是
- */
- private String description;
- /**
- * 函数请求参数,说明:
- * (1)JSON Schema 格式,参考JSON Schema描述
- * (2)如果函数没有请求参数,parameters值格式如下:
- * {"type": "object","properties": {}}
- * 必填: 是
- */
- private String parameters;
- /**
- * 函数响应参数,JSON Schema 格式,参考JSON Schema描述
- * 必填: 否
- */
- private String responses;
- /**
- * function调用的一些历史示例,说明:
- * (1)可以提供正例(正常触发)和反例(无需触发)的example
- * ·正例:从历史请求数据中获取
- * ·反例:
- * 当role = user,不会触发请求的query
- * 当role = assistant,有固定的格式。function_call的name为空,arguments是空对象:"{}",thought可以填固定的:"我不需要调用任何工具"
- * (2)兼容之前的 List(example) 格式
- */
- private String examples;
- }
-
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionResponse.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionResponse.java
deleted file mode 100644
index 5082302f8..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatCompletionResponse.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;
-
-import lombok.Data;
-
-/**
- * 文心一言 Completion Response
- *
- * 百度链接: https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t
- *
- * @author fansili
- */
-@Data
-public class YiYanChatCompletionResponse {
-
- /**
- * 本轮对话的id
- */
- private String id;
- /**
- * 回包类型,chat.completion:多轮对话返回
- */
- private String object;
- /**
- * 时间戳
- */
- private int created;
- /**
- * 表示当前子句的序号。只有在流式接口模式下会返回该字段
- */
- private int sentence_id;
- /**
- * 表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段
- */
- private boolean is_end;
- /**
- * 当前生成的结果是否被截断
- */
- private boolean is_truncated;
- /**
- * 输出内容标识,说明:
- * · normal:输出内容完全由大模型生成,未触发截断、替换
- * · stop:输出结果命中入参stop中指定的字段后被截断
- * · length:达到了最大的token数,根据EB返回结果is_truncated来截断
- * · content_filter:输出内容被截断、兜底、替换为**等
- */
- private String finish_reason;
- /**
- * 搜索数据,当请求参数enable_citation为true并且触发搜索时,会返回该字段
- */
- private String search_info;
- /**
- * 对话返回结果
- */
- private String result;
- /**
- * 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息
- * true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息
- * false:否,表示用户输入无安全风险
- */
- private boolean need_clear_history;
- /**
- * 说明:
- * · 0:正常返回
- * · 其他:非正常
- */
- private int flag;
- /**
- * 当need_clear_history为true时,此字段会告知第几轮对话有敏感信息,如果是当前问题,ban_round=-1
- */
- private int ban_round;
- /**
- * token统计信息
- */
- private Usage usage;
-
- @Data
- public static class Usage {
- /**
- * 问题tokens数
- */
- private int prompt_tokens;
- /**
- * 回答tokens数
- */
- private int completion_tokens;
- /**
- * tokens总数
- */
- private int total_tokens;
- }
-
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatModel.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatModel.java
deleted file mode 100644
index 9b400cdad..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/api/YiYanChatModel.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan.api;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 文心一言的模型枚举
- *
- * 可参考 百度文档>
- *
- * @author fansili
- */
-@Getter
-@AllArgsConstructor
-public enum YiYanChatModel {
-
- ERNIE4_0("ERNIE 4.0", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro"),
- ERNIE4_3_5_8K("ERNIE-3.5-8K", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"),
- ERNIE4_3_5_8K_0205("ERNIE-3.5-8K-0205", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-8k-0205"),
- ERNIE4_3_5_8K_1222("ERNIE-3.5-8K-1222", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-8k-1222"),
- ERNIE4_BOT_8K("ERNIE-Bot-8K", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie_bot_8k"),
- ERNIE4_3_5_4K_0205("ERNIE-3.5-4K-0205", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-4k-0205"),
- ;
-
- /**
- * 模型名
- */
- private final String model;
- /**
- * API URL
- */
- private final String uri;
-
- public static YiYanChatModel valueOfModel(String model) {
- for (YiYanChatModel modelEnum : YiYanChatModel.values()) {
- if (modelEnum.getModel().equals(model)) {
- return modelEnum;
- }
- }
- throw new IllegalArgumentException("Invalid MessageType value: " + model);
- }
-}
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/exception/YiYanApiException.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/exception/YiYanApiException.java
deleted file mode 100644
index f61badfcb..000000000
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/yiyan/exception/YiYanApiException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cn.iocoder.yudao.framework.ai.core.model.yiyan.exception;
-
-/**
- * 一言 api 调用异常
- */
-public class YiYanApiException extends RuntimeException {
-
- public YiYanApiException(String message) {
- super(message);
- }
-
- public YiYanApiException(String message, Throwable cause) {
- super(message, cause);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatTests.java
index 9b1d37d45..e0e708105 100644
--- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatTests.java
+++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/YiYanChatTests.java
@@ -1,21 +1,21 @@
package cn.iocoder.yudao.framework.ai.chat;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;
-import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel;
-import org.junit.Before;
-import org.junit.Test;
-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;
-import java.util.Scanner;
+//import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatClient;
+//import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions;
+//import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanApi;
+//import cn.iocoder.yudao.framework.ai.core.model.yiyan.api.YiYanChatModel;
+//import org.junit.Before;
+//import org.junit.Test;
+//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;
+//import java.util.Scanner;
// TODO 芋艿:整理单测
/**
@@ -26,49 +26,49 @@ import java.util.Scanner;
*/
public class YiYanChatTests {
- private YiYanChatClient yiYanChatClient;
-
- @Before
- public void setup() {
- YiYanApi yiYanApi = new YiYanApi(
- "x0cuLZ7XsaTCU08vuJWO87Lg",
- "R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK",
- YiYanChatModel.ERNIE4_3_5_8K,
- 86400
- );
- YiYanChatOptions yiYanOptions = new YiYanChatOptions();
- yiYanOptions.setMaxOutputTokens(2048);
- yiYanOptions.setTopP(0.6f);
- yiYanOptions.setTemperature(0.85f);
- yiYanChatClient = new YiYanChatClient(
- yiYanApi,
- yiYanOptions
- );
- }
-
- @Test
- public void callTest() {
-
- // tip: 百度的message 有特殊规则(最后一个message为当前请求的信息,前面的message为历史对话信息)
- // tip: 地址 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11
- List messages = new ArrayList<>();
- messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));
- messages.add(new UserMessage("长沙怎么样?"));
-
- ChatResponse call = yiYanChatClient.call(new Prompt(messages));
- System.err.println(call.getResult());
- }
-
- @Test
- public void streamTest() {
- List messages = new ArrayList<>();
- messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));
- messages.add(new UserMessage("长沙怎么样?"));
-
- Flux fluxResponse = yiYanChatClient.stream(new Prompt(messages));
- fluxResponse.subscribe(chatResponse -> System.err.print(chatResponse.getResult().getOutput().getContent()));
- // 阻止退出
- Scanner scanner = new Scanner(System.in);
- scanner.nextLine();
- }
+// private YiYanChatClient yiYanChatClient;
+//
+// @Before
+// public void setup() {
+// YiYanApi yiYanApi = new YiYanApi(
+// "x0cuLZ7XsaTCU08vuJWO87Lg",
+// "R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK",
+// YiYanChatModel.ERNIE4_3_5_8K,
+// 86400
+// );
+// YiYanChatOptions yiYanOptions = new YiYanChatOptions();
+// yiYanOptions.setMaxOutputTokens(2048);
+// yiYanOptions.setTopP(0.6f);
+// yiYanOptions.setTemperature(0.85f);
+// yiYanChatClient = new YiYanChatClient(
+// yiYanApi,
+// yiYanOptions
+// );
+// }
+//
+// @Test
+// public void callTest() {
+//
+// // tip: 百度的message 有特殊规则(最后一个message为当前请求的信息,前面的message为历史对话信息)
+// // tip: 地址 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11
+// List messages = new ArrayList<>();
+// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));
+// messages.add(new UserMessage("长沙怎么样?"));
+//
+// ChatResponse call = yiYanChatClient.call(new Prompt(messages));
+// System.err.println(call.getResult());
+// }
+//
+// @Test
+// public void streamTest() {
+// List messages = new ArrayList<>();
+// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景,所有问题都采用文言文回答。"));
+// messages.add(new UserMessage("长沙怎么样?"));
+//
+// Flux fluxResponse = yiYanChatClient.stream(new Prompt(messages));
+// fluxResponse.subscribe(chatResponse -> System.err.print(chatResponse.getResult().getOutput().getContent()));
+// // 阻止退出
+// Scanner scanner = new Scanner(System.in);
+// scanner.nextLine();
+// }
}
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index b0b1d9b1e..9a51df672 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -160,19 +160,11 @@ spring:
gemini:
project-id: 1 # TODO 芋艿:缺配置
location: 2
+ qianfan: # 文心一言
+ api-key: x0cuLZ7XsaTCU08vuJWO87Lg
+ secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
yudao.ai:
- yiyan:
- enable: true
- aiPlatform: YI_YAN # TODO @fan:建议每个都独立配置属性类
- max-tokens: 1500
- temperature: 0.85
- topP: 0.8
- topK: 0
- appKey: x0cuLZ7XsaTCU08vuJWO87Lg
- secretKey: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
- refreshTokenSecondTime: 86400
- model: ERNIE4_3_5_8K
xinghuo:
enable: true
aiPlatform: XING_HUO # TODO @fan:建议每个都独立配置属性类