Commit 1828d1953ab15beb501720e2a066f7ce7d8f8069

Authored by cherishsince
1 parent f6ea1bda

迁移文心一言

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
  1 +package cn.iocoder.yudao.framework.ai.chatyiyan.api;
  2 +
  3 +/**
  4 + * author: fansili
  5 + * time: 2024/3/9 10:37
  6 + */
  7 +public class YiYanChatCompletionMessage {
  8 +}
... ...
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
... ...