Commit 1828d1953ab15beb501720e2a066f7ce7d8f8069
1 parent
f6ea1bda
迁移文心一言
Showing
8 changed files
with
608 additions
and
0 deletions
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/YiYanApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanAuthRes; | |
| 4 | +import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletion; | |
| 5 | +import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletionRequest; | |
| 6 | +import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException; | |
| 7 | +import lombok.Data; | |
| 8 | +import org.springframework.http.HttpStatusCode; | |
| 9 | +import org.springframework.http.ResponseEntity; | |
| 10 | +import org.springframework.web.reactive.function.client.WebClient; | |
| 11 | +import reactor.core.publisher.Flux; | |
| 12 | +import reactor.core.publisher.Mono; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 文心一言 | |
| 16 | + * <p> | |
| 17 | + * author: fansili | |
| 18 | + * time: 2024/3/8 21:47 | |
| 19 | + */ | |
| 20 | +@Data | |
| 21 | +public class YiYanApi { | |
| 22 | + | |
| 23 | + private static final String DEFAULT_BASE_URL = "https://aip.baidubce.com"; | |
| 24 | + | |
| 25 | + private static final String AUTH_2_TOKEN_URI = "/oauth/2.0/token"; | |
| 26 | + | |
| 27 | + public static final String DEFAULT_CHAT_MODEL = "ERNIE 4.0"; | |
| 28 | + | |
| 29 | + // 获取access_token流程 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Ilkkrb0i5 | |
| 30 | + private String appKey; | |
| 31 | + private String secretKey; | |
| 32 | + private String token; | |
| 33 | + // token刷新时间(秒) | |
| 34 | + private int refreshTokenSecondTime; | |
| 35 | + // 发送请求 webClient | |
| 36 | + private final WebClient webClient; | |
| 37 | + // 使用的模型 | |
| 38 | + private YiYanChatModel useChatModel; | |
| 39 | + | |
| 40 | + public YiYanApi(String appKey, String secretKey, YiYanChatModel useChatModel, int refreshTokenSecondTime) { | |
| 41 | + this.appKey = appKey; | |
| 42 | + this.secretKey = secretKey; | |
| 43 | + this.useChatModel = useChatModel; | |
| 44 | + this.refreshTokenSecondTime = refreshTokenSecondTime; | |
| 45 | + | |
| 46 | + this.webClient = WebClient.builder() | |
| 47 | + .baseUrl(DEFAULT_BASE_URL) | |
| 48 | + .build(); | |
| 49 | + | |
| 50 | + token = getToken(); | |
| 51 | + } | |
| 52 | + | |
| 53 | + private String getToken() { | |
| 54 | + // 文档地址: https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Ilkkrb0i5 | |
| 55 | + ResponseEntity<YiYanAuthRes> response = this.webClient.post() | |
| 56 | + .uri(uriBuilder -> uriBuilder.path(AUTH_2_TOKEN_URI) | |
| 57 | + .queryParam("grant_type", "client_credentials") | |
| 58 | + .queryParam("client_id", appKey) | |
| 59 | + .queryParam("client_secret", secretKey) | |
| 60 | + .build() | |
| 61 | + ) | |
| 62 | + .retrieve() | |
| 63 | + .toEntity(YiYanAuthRes.class) | |
| 64 | + .block(); | |
| 65 | + // 检查请求状态 | |
| 66 | + if (HttpStatusCode.valueOf(200) != response.getStatusCode()) { | |
| 67 | + throw new YiYanApiException("一言认证失败! api:https://aip.baidubce.com/oauth/2.0/token 请检查 client_id、client_secret 是否正确!"); | |
| 68 | + } | |
| 69 | + YiYanAuthRes body = response.getBody(); | |
| 70 | + return body.getAccess_token(); | |
| 71 | + } | |
| 72 | + | |
| 73 | + public ResponseEntity<YiYanChatCompletion> chatCompletionEntity(YiYanChatCompletionRequest request) { | |
| 74 | + // TODO: 2024/3/10 小范 这里错误信息返回的结构不一样 | |
| 75 | +// {"error_code":17,"error_msg":"Open api daily request limit reached"} | |
| 76 | + return this.webClient.post() | |
| 77 | + .uri(uriBuilder | |
| 78 | + -> uriBuilder.path(useChatModel.getUri()) | |
| 79 | + .queryParam("access_token", token) | |
| 80 | + .build()) | |
| 81 | + .body(Mono.just(request), YiYanChatCompletionRequest.class) | |
| 82 | + .retrieve() | |
| 83 | + .toEntity(YiYanChatCompletion.class) | |
| 84 | + .block(); | |
| 85 | + } | |
| 86 | + | |
| 87 | + public Flux<YiYanChatCompletion> chatCompletionStream(YiYanChatCompletionRequest request) { | |
| 88 | + return this.webClient.post() | |
| 89 | + .uri(uriBuilder | |
| 90 | + -> uriBuilder.path(useChatModel.getUri()) | |
| 91 | + .queryParam("access_token", token) | |
| 92 | + .build()) | |
| 93 | + .body(Mono.just(request), YiYanChatCompletionRequest.class) | |
| 94 | + .retrieve() | |
| 95 | + .bodyToFlux(YiYanChatCompletion.class); | |
| 96 | + } | |
| 97 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/YiYanChatClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.ai.chat.ChatClient; | |
| 4 | +import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | |
| 5 | +import cn.iocoder.yudao.framework.ai.chat.Generation; | |
| 6 | +import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient; | |
| 7 | +import cn.iocoder.yudao.framework.ai.chat.messages.Message; | |
| 8 | +import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | |
| 9 | +import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletion; | |
| 10 | +import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletionMessage; | |
| 11 | +import cn.iocoder.yudao.framework.ai.chatyiyan.api.YiYanChatCompletionRequest; | |
| 12 | +import cn.iocoder.yudao.framework.ai.chatyiyan.exception.YiYanApiException; | |
| 13 | +import cn.iocoder.yudao.framework.ai.model.function.AbstractFunctionCallSupport; | |
| 14 | +import cn.iocoder.yudao.framework.ai.model.function.FunctionCallbackContext; | |
| 15 | +import lombok.extern.slf4j.Slf4j; | |
| 16 | + | |
| 17 | +import org.springframework.http.ResponseEntity; | |
| 18 | +import org.springframework.retry.RetryCallback; | |
| 19 | +import org.springframework.retry.RetryContext; | |
| 20 | +import org.springframework.retry.RetryListener; | |
| 21 | +import org.springframework.retry.support.RetryTemplate; | |
| 22 | +import reactor.core.publisher.Flux; | |
| 23 | + | |
| 24 | +import java.time.Duration; | |
| 25 | +import java.util.ArrayList; | |
| 26 | +import java.util.List; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * 文心一言 | |
| 30 | + * | |
| 31 | + * author: fansili | |
| 32 | + * time: 2024/3/8 19:11 | |
| 33 | + */ | |
| 34 | +@Slf4j | |
| 35 | +public class YiYanChatClient | |
| 36 | + extends AbstractFunctionCallSupport<YiYanChatCompletionMessage, YiYanChatCompletionRequest, ResponseEntity<YiYanChatCompletion>> | |
| 37 | + implements ChatClient, StreamingChatClient { | |
| 38 | + | |
| 39 | + private YiYanApi yiYanApi; | |
| 40 | + | |
| 41 | + public YiYanChatClient(YiYanApi yiYanApi) { | |
| 42 | + super(new FunctionCallbackContext()); | |
| 43 | + this.yiYanApi = yiYanApi; | |
| 44 | + } | |
| 45 | + | |
| 46 | + public final RetryTemplate retryTemplate = RetryTemplate.builder() | |
| 47 | + // 最大重试次数 10 | |
| 48 | + .maxAttempts(10) | |
| 49 | + .retryOn(YiYanApiException.class) | |
| 50 | + // 最大重试5次,第一次间隔3000ms,第二次3000ms * 2,第三次3000ms * 3,以此类推,最大间隔3 * 60000ms | |
| 51 | + .exponentialBackoff(Duration.ofMillis(3000), 2, Duration.ofMillis(3 * 60000)) | |
| 52 | + .withListener(new RetryListener() { | |
| 53 | + @Override | |
| 54 | + public <T extends Object, E extends Throwable> void onError(RetryContext context, | |
| 55 | + RetryCallback<T, E> callback, Throwable throwable) { | |
| 56 | + log.warn("重试异常:" + context.getRetryCount(), throwable); | |
| 57 | + }; | |
| 58 | + }) | |
| 59 | + .build(); | |
| 60 | + | |
| 61 | + @Override | |
| 62 | + public String call(String message) { | |
| 63 | + return ChatClient.super.call(message); | |
| 64 | + } | |
| 65 | + | |
| 66 | + @Override | |
| 67 | + public ChatResponse call(Prompt prompt) { | |
| 68 | + return this.retryTemplate.execute(ctx -> { | |
| 69 | + // ctx 会有重试的信息 | |
| 70 | + // 创建 request 请求,stream模式需要供应商支持 | |
| 71 | + YiYanChatCompletionRequest request = this.createRequest(prompt, false); | |
| 72 | + // 调用 callWithFunctionSupport 发送请求 | |
| 73 | + ResponseEntity<YiYanChatCompletion> response = this.callWithFunctionSupport(request); | |
| 74 | + // 获取结果封装 ChatResponse | |
| 75 | + YiYanChatCompletion chatCompletion = response.getBody(); | |
| 76 | + return new ChatResponse(List.of(new Generation(chatCompletion.getResult()))); | |
| 77 | + }); | |
| 78 | + } | |
| 79 | + | |
| 80 | + private YiYanChatCompletionRequest createRequest(Prompt prompt, boolean stream) { | |
| 81 | + List<YiYanChatCompletionRequest.Message> messages = new ArrayList<>(); | |
| 82 | + List<Message> instructions = prompt.getInstructions(); | |
| 83 | + for (Message instruction : instructions) { | |
| 84 | + YiYanChatCompletionRequest.Message message = new YiYanChatCompletionRequest.Message(); | |
| 85 | + message.setContent(instruction.getContent()); | |
| 86 | + message.setRole(instruction.getMessageType().getValue()); | |
| 87 | + messages.add(message); | |
| 88 | + } | |
| 89 | + YiYanChatCompletionRequest request = new YiYanChatCompletionRequest(messages); | |
| 90 | + request.setStream(stream); | |
| 91 | + return request; | |
| 92 | + } | |
| 93 | + | |
| 94 | + @Override | |
| 95 | + public Flux<ChatResponse> stream(Prompt prompt) { | |
| 96 | + // ctx 会有重试的信息 | |
| 97 | + // 创建 request 请求,stream模式需要供应商支持 | |
| 98 | + YiYanChatCompletionRequest request = this.createRequest(prompt, true); | |
| 99 | + // 调用 callWithFunctionSupport 发送请求 | |
| 100 | + Flux<YiYanChatCompletion> response = this.yiYanApi.chatCompletionStream(request); | |
| 101 | +// response.subscribe(new Consumer<YiYanChatCompletion>() { | |
| 102 | +// @Override | |
| 103 | +// public void accept(YiYanChatCompletion chatCompletion) { | |
| 104 | +// // {"id":"as-p0nfjuuasg","object":"chat.completion","created":1710033402,"sentence_id":0,"is_end":false,"is_truncated":false,"result":"编程语","need_clear_history":false,"finish_reason":"normal","usage":{"prompt_tokens":5,"completion_tokens":0,"total_tokens":5}} | |
| 105 | +// System.err.println(chatCompletion); | |
| 106 | +// } | |
| 107 | +// }); | |
| 108 | + return response.map(res -> { | |
| 109 | + return new ChatResponse(List.of(new Generation(res.getResult()))); | |
| 110 | + }); | |
| 111 | + } | |
| 112 | + | |
| 113 | + @Override | |
| 114 | + protected YiYanChatCompletionRequest doCreateToolResponseRequest(YiYanChatCompletionRequest previousRequest, YiYanChatCompletionMessage responseMessage, List<YiYanChatCompletionMessage> conversationHistory) { | |
| 115 | + return null; | |
| 116 | + } | |
| 117 | + | |
| 118 | + @Override | |
| 119 | + protected List<YiYanChatCompletionMessage> doGetUserMessages(YiYanChatCompletionRequest request) { | |
| 120 | + return null; | |
| 121 | + } | |
| 122 | + | |
| 123 | + @Override | |
| 124 | + protected YiYanChatCompletionMessage doGetToolResponseMessage(ResponseEntity<YiYanChatCompletion> response) { | |
| 125 | + return null; | |
| 126 | + } | |
| 127 | + | |
| 128 | + @Override | |
| 129 | + protected ResponseEntity<YiYanChatCompletion> doChatCompletion(YiYanChatCompletionRequest request) { | |
| 130 | + return yiYanApi.chatCompletionEntity(request); | |
| 131 | + } | |
| 132 | + | |
| 133 | + @Override | |
| 134 | + protected boolean isToolFunctionCall(ResponseEntity<YiYanChatCompletion> response) { | |
| 135 | + return false; | |
| 136 | + } | |
| 137 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/YiYanChatModel.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan; | |
| 2 | + | |
| 3 | +import lombok.Getter; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 一言模型 | |
| 7 | + * | |
| 8 | + * 可参考百度文档:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t | |
| 9 | + * | |
| 10 | + * author: fansili | |
| 11 | + * time: 2024/3/9 12:01 | |
| 12 | + */ | |
| 13 | +@Getter | |
| 14 | +public enum YiYanChatModel { | |
| 15 | + | |
| 16 | + ERNIE4_0("ERNIE 4.0", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro"), | |
| 17 | + ERNIE4_3_5_8K("ERNIE-3.5-8K", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"), | |
| 18 | + ERNIE4_3_5_8K_0205("ERNIE-3.5-8K-0205", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-8k-0205"), | |
| 19 | + | |
| 20 | + ERNIE4_3_5_8K_1222("ERNIE-3.5-8K-1222", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-8k-1222"), | |
| 21 | + ERNIE4_BOT_8K("ERNIE-Bot-8K", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie_bot_8k"), | |
| 22 | + ERNIE4_3_5_4K_0205("ERNIE-3.5-4K-0205", "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-3.5-4k-0205"), | |
| 23 | + | |
| 24 | + ; | |
| 25 | + | |
| 26 | + YiYanChatModel(String value, String uri) { | |
| 27 | + this.value = value; | |
| 28 | + this.uri = uri; | |
| 29 | + } | |
| 30 | + | |
| 31 | + private String value; | |
| 32 | + | |
| 33 | + private String uri; | |
| 34 | + | |
| 35 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/api/YiYanAuthRes.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan.api; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 一言 获取access_token | |
| 7 | + * | |
| 8 | + * author: fansili | |
| 9 | + * time: 2024/3/10 08:51 | |
| 10 | + */ | |
| 11 | +@Data | |
| 12 | +public class YiYanAuthRes { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 访问凭证 | |
| 16 | + */ | |
| 17 | + private String access_token; | |
| 18 | + /** | |
| 19 | + * 有效期,Access Token的有效期。 | |
| 20 | + * 说明:单位是秒,有效期30天 | |
| 21 | + */ | |
| 22 | + private int expires_in; | |
| 23 | + /** | |
| 24 | + * 错误码,说明:响应失败时返回该字段,成功时不返回 | |
| 25 | + */ | |
| 26 | + private String error; | |
| 27 | + /** | |
| 28 | + * 错误描述信息,帮助理解和解决发生的错误 | |
| 29 | + * 说明:响应失败时返回该字段,成功时不返回 | |
| 30 | + */ | |
| 31 | + private String error_description; | |
| 32 | + /** | |
| 33 | + * 暂时未使用,可忽略 | |
| 34 | + */ | |
| 35 | + private String session_key; | |
| 36 | + /** | |
| 37 | + * 暂时未使用,可忽略 | |
| 38 | + */ | |
| 39 | + private String refresh_token; | |
| 40 | + /** | |
| 41 | + * 暂时未使用,可忽略 | |
| 42 | + */ | |
| 43 | + private String scope; | |
| 44 | + /** | |
| 45 | + * 暂时未使用,可忽略 | |
| 46 | + */ | |
| 47 | + private String session_secret; | |
| 48 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/api/YiYanChatCompletion.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan.api; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 聊天返回 | |
| 7 | + * 百度链接: https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t | |
| 8 | + * | |
| 9 | + * author: fansili | |
| 10 | + * time: 2024/3/9 10:34 | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +public class YiYanChatCompletion { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 本轮对话的id | |
| 17 | + */ | |
| 18 | + private String id; | |
| 19 | + /** | |
| 20 | + * 回包类型,chat.completion:多轮对话返回 | |
| 21 | + */ | |
| 22 | + private String object; | |
| 23 | + /** | |
| 24 | + * 时间戳 | |
| 25 | + */ | |
| 26 | + private int created; | |
| 27 | + /** | |
| 28 | + * 表示当前子句的序号。只有在流式接口模式下会返回该字段 | |
| 29 | + */ | |
| 30 | + private int sentence_id; | |
| 31 | + /** | |
| 32 | + * 表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段 | |
| 33 | + */ | |
| 34 | + private boolean is_end; | |
| 35 | + /** | |
| 36 | + * 当前生成的结果是否被截断 | |
| 37 | + */ | |
| 38 | + private boolean is_truncated; | |
| 39 | + /** | |
| 40 | + * 输出内容标识,说明: | |
| 41 | + * · normal:输出内容完全由大模型生成,未触发截断、替换 | |
| 42 | + * · stop:输出结果命中入参stop中指定的字段后被截断 | |
| 43 | + * · length:达到了最大的token数,根据EB返回结果is_truncated来截断 | |
| 44 | + * · content_filter:输出内容被截断、兜底、替换为**等 | |
| 45 | + */ | |
| 46 | + private String finish_reason; | |
| 47 | + /** | |
| 48 | + * 搜索数据,当请求参数enable_citation为true并且触发搜索时,会返回该字段 | |
| 49 | + */ | |
| 50 | + private String search_info; | |
| 51 | + /** | |
| 52 | + * 对话返回结果 | |
| 53 | + */ | |
| 54 | + private String result; | |
| 55 | + /** | |
| 56 | + * 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息 | |
| 57 | + * true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息 | |
| 58 | + * false:否,表示用户输入无安全风险 | |
| 59 | + */ | |
| 60 | + private boolean need_clear_history; | |
| 61 | + /** | |
| 62 | + * 说明: | |
| 63 | + * · 0:正常返回 | |
| 64 | + * · 其他:非正常 | |
| 65 | + */ | |
| 66 | + private int flag; | |
| 67 | + /** | |
| 68 | + * 当need_clear_history为true时,此字段会告知第几轮对话有敏感信息,如果是当前问题,ban_round=-1 | |
| 69 | + */ | |
| 70 | + private int ban_round; | |
| 71 | + /** | |
| 72 | + * token统计信息 | |
| 73 | + */ | |
| 74 | + private Usage usage; | |
| 75 | + | |
| 76 | + @Data | |
| 77 | + public static class Usage { | |
| 78 | + /** | |
| 79 | + * 问题tokens数 | |
| 80 | + */ | |
| 81 | + private int prompt_tokens; | |
| 82 | + /** | |
| 83 | + * 回答tokens数 | |
| 84 | + */ | |
| 85 | + private int completion_tokens; | |
| 86 | + /** | |
| 87 | + * tokens总数 | |
| 88 | + */ | |
| 89 | + private int total_tokens; | |
| 90 | + } | |
| 91 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/api/YiYanChatCompletionMessage.java
0 → 100644
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/api/YiYanChatCompletionRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan.api; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 一言 Completion req | |
| 9 | + * | |
| 10 | + * 百度千帆文档:https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11 | |
| 11 | + * | |
| 12 | + * author: fansili | |
| 13 | + * time: 2024/3/9 10:34 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +public class YiYanChatCompletionRequest { | |
| 17 | + | |
| 18 | + public YiYanChatCompletionRequest(List<Message> messages) { | |
| 19 | + this.messages = messages; | |
| 20 | + } | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 聊天上下文信息。 | |
| 24 | + * 必填:是 | |
| 25 | + */ | |
| 26 | + private List<Message> messages; | |
| 27 | + /** | |
| 28 | + * 一个可触发函数的描述列表,说明: | |
| 29 | + * (1)支持的function数量无限制 | |
| 30 | + * (2)长度限制,最后一个message的content长度(即此轮对话的问题)、functions和system字段总内容不能超过20480 个字符,且不能超过5120 tokens | |
| 31 | + * 必填:否 | |
| 32 | + */ | |
| 33 | + private List<Function> functions; | |
| 34 | + /** | |
| 35 | + * 说明: | |
| 36 | + * (1)较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定 | |
| 37 | + * (2)默认0.8,范围 (0, 1.0],不能为0 | |
| 38 | + * 必填:否 | |
| 39 | + */ | |
| 40 | + private String temperature; | |
| 41 | + /** | |
| 42 | + * 说明: | |
| 43 | + * (1)影响输出文本的多样性,取值越大,生成文本的多样性越强 | |
| 44 | + * (2)默认0.8,取值范围 [0, 1.0] | |
| 45 | + * 必填:否 | |
| 46 | + */ | |
| 47 | + private String top_p; | |
| 48 | + /** | |
| 49 | + * 通过对已生成的token增加惩罚,减少重复生成的现象。说明: | |
| 50 | + * (1)值越大表示惩罚越大 | |
| 51 | + * (2)默认1.0,取值范围:[1.0, 2.0] | |
| 52 | + * | |
| 53 | + * 必填:否 | |
| 54 | + */ | |
| 55 | + private String penalty_score; | |
| 56 | + /** | |
| 57 | + * 是否以流式接口的形式返回数据,默认false | |
| 58 | + * 必填:否 | |
| 59 | + */ | |
| 60 | + private Boolean stream; | |
| 61 | + /** | |
| 62 | + * 模型人设,主要用于人设设定,例如,你是xxx公司制作的AI助手,说明: | |
| 63 | + * (1)长度限制,最后一个message的content长度(即此轮对话的问题)、functions和system字段总内容不能超过20480 个字符,且不能超过5120 tokens | |
| 64 | + * (2)如果同时使用system和functions,可能暂无法保证使用效果,持续进行优化 | |
| 65 | + * 必填:否 | |
| 66 | + */ | |
| 67 | + private String system; | |
| 68 | + /** | |
| 69 | + * 生成停止标识,当模型生成结果以stop中某个元素结尾时,停止文本生成。说明: | |
| 70 | + * (1)每个元素长度不超过20字符 | |
| 71 | + * (2)最多4个元素 | |
| 72 | + * 必填:否 | |
| 73 | + */ | |
| 74 | + private String stop; | |
| 75 | + /** | |
| 76 | + * 是否强制关闭实时搜索功能,默认false,表示不关闭 | |
| 77 | + * 必填:否 | |
| 78 | + */ | |
| 79 | + private Boolean disable_search; | |
| 80 | + /** | |
| 81 | + * 是否开启上角标返回,说明: | |
| 82 | + * (1)开启后,有概率触发搜索溯源信息search_info,search_info内容见响应参数介绍 | |
| 83 | + * (2)默认false,不开启 | |
| 84 | + * 必填:否 | |
| 85 | + */ | |
| 86 | + private Boolean enable_citation; | |
| 87 | + /** | |
| 88 | + * 指定模型最大输出token数,范围[2, 2048] | |
| 89 | + * 必填:否 | |
| 90 | + */ | |
| 91 | + private Integer max_output_tokens; | |
| 92 | + /** | |
| 93 | + * 指定响应内容的格式,说明: | |
| 94 | + * (1)可选值: | |
| 95 | + * · json_object:以json格式返回,可能出现不满足效果情况 | |
| 96 | + * · text:以文本格式返回 | |
| 97 | + * (2)如果不填写参数response_format值,默认为text | |
| 98 | + * 必填:否 | |
| 99 | + */ | |
| 100 | + private String response_format; | |
| 101 | + /** | |
| 102 | + * 表示最终用户的唯一标识符 | |
| 103 | + * 必填:否 | |
| 104 | + */ | |
| 105 | + private String user_id; | |
| 106 | + /** | |
| 107 | + * 在函数调用场景下,提示大模型选择指定的函数(非强制),说明:指定的函数名必须在functions中存在 | |
| 108 | + * 必填:否 | |
| 109 | + */ | |
| 110 | + private String tool_choice; | |
| 111 | + | |
| 112 | + | |
| 113 | + @Data | |
| 114 | + public static class Message { | |
| 115 | + private String role; | |
| 116 | + | |
| 117 | + private String content; | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Data | |
| 121 | + public static class ToolChoice { | |
| 122 | + /** | |
| 123 | + * 指定工具类型,function | |
| 124 | + * 必填: 是 | |
| 125 | + */ | |
| 126 | + private String type; | |
| 127 | + /** | |
| 128 | + * 指定要使用的函数 | |
| 129 | + * 必填: 是 | |
| 130 | + */ | |
| 131 | + private Function function; | |
| 132 | + /** | |
| 133 | + * 指定要使用的函数名 | |
| 134 | + * 必填: 是 | |
| 135 | + */ | |
| 136 | + private String name; | |
| 137 | + } | |
| 138 | + | |
| 139 | + @Data | |
| 140 | + public static class Function { | |
| 141 | + /** | |
| 142 | + * 函数名 | |
| 143 | + * 必填: 是 | |
| 144 | + */ | |
| 145 | + private String name; | |
| 146 | + /** | |
| 147 | + * 函数描述 | |
| 148 | + * 必填: 是 | |
| 149 | + */ | |
| 150 | + private String description; | |
| 151 | + /** | |
| 152 | + * 函数请求参数,说明: | |
| 153 | + * (1)JSON Schema 格式,参考JSON Schema描述 | |
| 154 | + * (2)如果函数没有请求参数,parameters值格式如下: | |
| 155 | + * {"type": "object","properties": {}} | |
| 156 | + * 必填: 是 | |
| 157 | + */ | |
| 158 | + private String parameters; | |
| 159 | + /** | |
| 160 | + * 函数响应参数,JSON Schema 格式,参考JSON Schema描述 | |
| 161 | + * 必填: 否 | |
| 162 | + */ | |
| 163 | + private String responses; | |
| 164 | + /** | |
| 165 | + * function调用的一些历史示例,说明: | |
| 166 | + * (1)可以提供正例(正常触发)和反例(无需触发)的example | |
| 167 | + * ·正例:从历史请求数据中获取 | |
| 168 | + * ·反例: | |
| 169 | + * 当role = user,不会触发请求的query | |
| 170 | + * 当role = assistant,有固定的格式。function_call的name为空,arguments是空对象:"{}",thought可以填固定的:"我不需要调用任何工具" | |
| 171 | + * (2)兼容之前的 List(example) 格式 | |
| 172 | + */ | |
| 173 | + private String examples; | |
| 174 | + } | |
| 175 | + | |
| 176 | +} | ... | ... |
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/chatyiyan/exception/YiYanApiException.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.ai.chatyiyan.exception; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 一言 api 调用异常 | |
| 5 | + */ | |
| 6 | +public class YiYanApiException extends RuntimeException { | |
| 7 | + | |
| 8 | + public YiYanApiException(String message) { | |
| 9 | + super(message); | |
| 10 | + } | |
| 11 | + | |
| 12 | + public YiYanApiException(String message, Throwable cause) { | |
| 13 | + super(message, cause); | |
| 14 | + } | |
| 15 | + | |
| 16 | +} | |
| 0 | 17 | \ No newline at end of file | ... | ... |