JAVA实现智能问答助手-GPT4o+向量数据库+FunctionCalling

本文基于上一篇文章GPT+向量数据库+Function calling=垂直领域小助手进行了改进,对其中的循环请求GPT、FuctionCalling循环请求、MSGList缩容等进行了修改和优化,使的相关请求更加抽象和方便后续做延伸。文章中涉及业务属性的内容已经进行了过滤,请忽略。代码中部分类工具类可能没有展示,但是注释层做了解释,请使用其他方案进行替换。

请求参数

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;/*** @author * @date 2024/3/14**/
@Getter
@Setter
@Accessors(chain = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class MsgDto {/*** databaseName  数据库名称*/private String databaseName = "";/*** collectionName 集合名称*/private String collectionName = "";/*** appCode*/private String appCode = "";/*** 子模型*/private String aiModel = "gpt-3.5-turbo";/*** 会话内容-把会话内容信息存到一起,可为空* 如果想持续获取内容,建议在初次生成后获取并存入*/private String sessionId;/*** 消息体内容*/private String prompt;/*** token数,可为空,默认300*/private Integer maxTokens;/*** 调节信息 ,可为空,默认0.0*/private Double temperature;/*** 输出Json ,默认True*/private Boolean outputJsonFlag = Boolean.TRUE;/*** 排名分数阈值(建议0.75)*/private String scoreFlag = "0.85";/*** 获取功能跳转链接和方式-排名分数阈值*/private String appPermissionsFunctionScoreFlag = "0.85";/*** 根据保险产品分类获取保险产品列表-排名分数阈值*/private String insuranceProductInfoScoreFlag = "0.8";/*** 是否返回所有linkList数据*/private Boolean linkListAllSwitch = Boolean.FALSE;
}

Apollo配置内容

可使用其他配置方式替代

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;/*** @author * @date 2024/5/19**/
@Getter
@Setter
@Accessors(chain = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class MsgConfigDto {/*** databaseName  数据库名称*/private String databaseName = "";/*** collectionName 集合名称*/private String collectionName = "";/*** appCode*/private String appCode = "";/*** 子模型* gpt-4o|gpt-3.5-turbo*/private String aiModel = "gpt-3.5-turbo";/*** token数,可为空,默认300*/private Integer maxTokens = 500;/*** 排名分数阈值(建议0.75)*/private String scoreFlag = "0.85";/*** 获取功能跳转链接和方式-排名分数阈值*/private String appPermissionsFunctionScoreFlag = "0.85";/*** 根据保险产品分类获取保险产品列表-排名分数阈值*/private String insuranceProductInfoScoreFlag = "0.8";/*** 文字转音频控制开关*/private Boolean textToSpeechFlag = Boolean.TRUE;/*** 文字转音频字数限制,当字数超过这个限制之后则不转换为音频*/private Integer textToSpeechLengthLimit = 200;/*** msgLinkedList超过该数量后开始做截断处理*/private Integer msgLinkedListLimit = 30;/*** 文字转语音对应的模型*/private String audioSpeechModel = "tts-1-hd";/*** 查询APP金刚位配置的collection名称*/private String appPermissionsFunctionConfigCollectionName = "";/*** 查询保险产品配置的collection名称*/private String insuranceProductInfoCollectionName = "";
}

请求体主要内容

 /*** 存放用户个人信息的地方 key为用户姓名*/private static Map<String, MsgUserInfoDto> USER_NAME_MAP = new HashMap<>(10);@Overridepublic Response<MsgResponseDto> innerChatCompletionsV2(MsgDto msgDto) {//参数判断-工具类不再添加,请自行做替换处理!!!CommonAssert.notNull(msgDto, ErrorCode.PARAMS_IS_NULL);CommonAssert.notBlank(msgDto.getDatabaseName(),ErrorCode.PARAMS_IS_NULL);CommonAssert.notBlank(msgDto.getCollectionName(),ErrorCode.PARAMS_IS_NULL);CommonAssert.notBlank(msgDto.getAppCode(),ErrorCode.PARAMS_IS_NULL);CommonAssert.notBlank(msgDto.getAiModel(),ErrorCode.PARAMS_IS_NULL);CommonAssert.notBlank(msgDto.getPrompt(),ErrorCode.PARAMS_IS_NULL);String sessionId = msgDto.getSessionId();if(StringUtils.isBlank(sessionId)){//唯一ID生成器,请自行替换处理!!!sessionId = uniqueCodeComponent.getUniqueCode();msgDto.setSessionId(sessionId);}//这里做了一个模拟的异步MQ通知,接收方接收到信息后会自动调用多智能体进行处理,该部分忽略!!try {Message<Long> message = Message.of(BrokerUserMQConstant.TOPIC_SDB_BROKER_USER, BrokerUserMQConstant.TAG_GPT_USER_MSG_INFO_TEST,sessionId, msgDto);MessageResult send = producer.send(message);log.info("innerChatCompletionsV2 send = {}", JsonUtil.getJsonString(send));} catch (Exception e) {log.error("innerChatCompletionsV2 has exception , msgDto = {}", JsonUtil.getJsonString(msgDto), e);}//覆盖请求中的参数体,这里是因为原请求方是原生APP,因此后续为了不用APP做升级改成了动态配置进行覆盖MsgConfigDto gptMsgConfig = apolloConfigHolder.getGptMsgConfig();MsgConfigDto msgConfigDto = CopyUtil.copyBean(gptMsgConfig, MsgConfigDto.class);this.buildMsgDto(msgDto,msgConfigDto);Database db = CLIENT.database(msgDto.getDatabaseName());Collection collection = db.collection(msgDto.getCollectionName());String prompt = msgDto.getPrompt();SearchByEmbeddingItemsParam searchByEmbeddingItemsParam = SearchByEmbeddingItemsParam.newBuilder().withEmbeddingItems(Collections.singletonList(prompt))// 若使用 HNSW 索引,则需要指定参数 ef,ef 越大,召回率越高,但也会影响检索速度.withParams(new HNSWSearchParams(200))// 设置标量字段的 Filter 表达式,过滤所需查询的文档.withRetrieveVector(false)// 指定 Top K 的 K 值.withLimit(3)// 使用 filter 过滤数据
//                .withFilter(new Filter(Filter.in("bookName", Arrays.asList("三国演义","西游记"))))// 指定返回的 fields
//                .withOutputFields(Arrays.asList("chapterName",  "lawText"))
//这里可以忽略哈,替换成自己的向量数据库参数后可使用自己的字段.withOutputFields(Arrays.asList("insuranceDesc", "insuranceProductName","insuranceProductSellingPoints","insuranceConsultantEnterpriseWeChatAccount","insuranceProductInfo")).build();SearchRes searchRes = collection.searchByEmbeddingItems(searchByEmbeddingItemsParam);AtomicReference searchFlag = new AtomicReference(Boolean.FALSE);if(Objects.equals(searchRes.getCode(),0) && CollectionUtils.isNotEmpty(searchRes.getDocuments())){log.info("VectorTestController  innerChatCompletionsV2 searchByEmbeddingItems -----------成功");StringBuilder promptBuilder = new StringBuilder();promptBuilder.append("提供的资料以\"...\"开头和结尾,请以提供的资料为参考进行问题的解答,如果提供的资料无法回答再根据用户实际问题进行谨慎回答。");promptBuilder.append("...开始\n");List<List<Document>> documentArray = searchRes.getDocuments();documentArray.forEach(documents -> {documents.forEach(document -> {if(document.getScore() < Double.parseDouble(msgDto.getScoreFlag())){return;}document.getDocFields().forEach(docField -> {promptBuilder.append(docField.getValue());promptBuilder.append("\n");searchFlag.set(Boolean.TRUE);});});});promptBuilder.append("...结束\n");promptBuilder.append("用户问题\n:");promptBuilder.append(prompt);promptBuilder.append("\n");if((Boolean)searchFlag.get()){prompt = promptBuilder.toString();}else {prompt = "在XX行业中," + prompt;}}else {prompt = "在XX行业中," + prompt;log.info("VectorTestController  innerChatCompletionsV2 searchByEmbeddingItems -----------失败,searchRes = {}, searchByEmbeddingItemsParam = {}", JsonUtil.getJsonString(searchRes),JsonUtil.getJsonString(searchByEmbeddingItemsParam));}log.info("innerChatCompletionsV2 sessionId = {}, msgDto = {}",sessionId,JsonUtil.getJsonString(msgDto));LinkedList<MessageV2> msgLinkedList = SESSION_MSG_MAP.get(sessionId);if(CollectionUtils.isEmpty(msgLinkedList)){msgLinkedList = new LinkedList<>();MessageV2 systemMessage = new MessageV2();systemMessage.setRole("system");String newSysMsg = sysMsgStr + "";systemMessage.setContent(newSysMsg);msgLinkedList.add(systemMessage);MessageV2 userMessage = new MessageV2();userMessage.setRole("user");userMessage.setContent(prompt);msgLinkedList.add(userMessage);SESSION_MSG_MAP.put(sessionId,msgLinkedList);}else{MessageV2 userMessage = new MessageV2();userMessage.setRole("user");userMessage.setContent(prompt);msgLinkedList.add(userMessage);}//构建GPT同样请求体ChatCompletionBodyV2 body = this.buildGptBody(msgDto,msgConfigDto,msgLinkedList);ChatCompletionResponseV2 gptResponse = this.gptRequestInvoke(msgDto, msgConfigDto, msgLinkedList, body);MsgResponseDto msgResponse = new MsgResponseDto();msgResponse.setRequestMsg(msgDto);msgResponse.setSessionId(sessionId);msgResponse.setResponseMsg(gptResponse);msgLinkedList = msgLinkedList.stream().peek(msgLinked -> {String content = msgLinked.getContent();String role = msgLinked.getRole();//app方法配置中返回内容做特殊处理if (Objects.equals(role,"assistant") && StringUtils.isNotBlank(content) && content.contains("appFunctionConfig")) {content.replaceAll("\\n", "");content.replaceAll("\\\"", "");}msgLinked.setContent(content);}).collect(Collectors.toCollection(LinkedList::new));MessageV2 lastMsg = msgLinkedList.getLast();//如果最后一个消息是GPT返回的且内容不为空,且内容长度符合要求,且文字转音频开关是打开的则转换音频数据if(Objects.nonNull(lastMsg)){String speechUrl = this.textToSpeech(lastMsg,msgConfigDto);if(StringUtils.isNotBlank(speechUrl)){msgResponse.setSpeechUrl(speechUrl);}}LinkedList<MessageV2> responseMsgLinkedList = new LinkedList<>();responseMsgLinkedList.add(lastMsg);msgResponse.setMsgLinkedList(responseMsgLinkedList);if(msgDto.getLinkListAllSwitch()){msgResponse.setMsgLinkedListAll(msgLinkedList);}log.info("innerChatCompletionsV2 SESSION_MSG_MAP = {}", JsonUtil.getJsonString(SESSION_MSG_MAP));return ResponseUtil.makeSuccess(msgResponse);}

构建GPT请求体

/*** 构建GPT同样请求体* @param msgDto* @param msgConfigDto* @param msgLinkedList* @return*/private ChatCompletionBodyV2 buildGptBody(MsgDto msgDto,MsgConfigDto msgConfigDto,LinkedList<MessageV2> msgLinkedList){log.info("VectorTestController buildGptBody param, msgDto = {},msgConfigDto = {},msgLinkedList = {}",JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(msgConfigDto),JsonUtil.getJsonString(msgLinkedList));ChatCompletionBodyV2 body = new ChatCompletionBodyV2();body.setLogit_bias(new HashMap<>());if(msgLinkedList.size() > msgConfigDto.getMsgLinkedListLimit()){//这里的处理方案可以再优化为过滤msg类型,只保留role类型为 user|system|assistant  ,把tolls的请求和返回内容进行过滤掉可以大大减少上线文内容。同时只保留指定数量的消息体内容List<MessageV2> msgLinkedListRequest = new ArrayList<>(6);msgLinkedListRequest.add(CopyUtil.copyBean(msgLinkedList.get(0),MessageV2.class));msgLinkedListRequest.add(CopyUtil.copyBean(msgLinkedList.get(msgLinkedList.size() - 5),MessageV2.class));msgLinkedListRequest.add(CopyUtil.copyBean(msgLinkedList.get(msgLinkedList.size() - 4),MessageV2.class));msgLinkedListRequest.add(CopyUtil.copyBean(msgLinkedList.get(msgLinkedList.size() - 3),MessageV2.class));msgLinkedListRequest.add(CopyUtil.copyBean(msgLinkedList.get(msgLinkedList.size() - 2),MessageV2.class));msgLinkedListRequest.add(CopyUtil.copyBean(msgLinkedList.get(msgLinkedList.size() - 1),MessageV2.class));body.setMessages(msgLinkedListRequest);}else {body.setMessages(msgLinkedList);}body.setModel(msgDto.getAiModel());body.setN(1);if(Objects.nonNull(msgDto.getTemperature())){body.setTemperature(msgDto.getTemperature());}else {body.setTemperature(0.0);}if(Objects.nonNull(msgDto.getMaxTokens())){body.setMax_tokens(msgDto.getMaxTokens());}else {body.setMax_tokens(300);}body.setStream(Boolean.FALSE);if (msgDto.getOutputJsonFlag()) {ResponseFormat responseFormat = new ResponseFormat();responseFormat.setType("json_object");body.setResponse_format(responseFormat);}body.setTool_choice("auto");List<Tool> toolList = new ArrayList<>(3);body.setTools(toolList);
//        toolList.add(this.buildBuyInsuranceProductUrl());
//        toolList.add(this.buildAppFunctionTools());toolList.add(this.buildSaveUserInfoTool());toolList.add(this.buildGetUserInfoTool());
//        toolList.add(this.buildSaveUserInsuranceCompanyPreferenceTool());
//        toolList.add(this.buildGetUserInsuranceCompanyPreferenceTool());
//        toolList.add(this.buildSaveUserInsurancePreferenceTool());
//        toolList.add(this.buildGetUserInsurancePreferenceTool());log.info("VectorTestController buildGptBody result,body = {} msgDto = {},msgConfigDto = {},msgLinkedList = {}",JsonUtil.getJsonString(body),JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(msgConfigDto),JsonUtil.getJsonString(msgLinkedList));return body;}

构建GPT请求方法

    /*** 执行GPT请求* @param msgDto 拥挤请求消息体* @param msgConfigDto 请求配置信息* @param msgLinkedList 消息体内容* @param body GPT请求体* @return*/private ChatCompletionResponseV2 gptRequestInvoke(MsgDto msgDto,MsgConfigDto msgConfigDto,LinkedList<MessageV2> msgLinkedList,ChatCompletionBodyV2 body){log.info("gptRequestInvoke request param, msgDto = {}, msgConfigDto = {},msgLinkedList = {}, body = {}",JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(msgConfigDto),JsonUtil.getJsonString(msgLinkedList),JsonUtil.getJsonString(body));String sessionId = msgDto.getSessionId();Boolean gptRunCheck = Boolean.TRUE;ChatCompletionResponseV2 gptResponse = null;//循环调用GPT,知道GPT没有进行toolCall回调为止;while (gptRunCheck){//构建GPT请求gptResponse = this.completionBuild(sessionId, msgDto.getAppCode(), body);if(Objects.nonNull(gptResponse)){List<ChoiceV2> choices = gptResponse.getChoices();for (ChoiceV2 choice : choices){ChoiceV2.ResMessage message = choice.getMessage();MessageV2 assistantMessage = new MessageV2();assistantMessage.setRole(message.getRole());if(StringUtils.isNotBlank(message.getContent())){assistantMessage.setContent(message.getContent());}msgLinkedList.add(assistantMessage);if(CollectionUtils.isEmpty(message.getTool_calls())){gptRunCheck = Boolean.FALSE;break;}List<ChoiceV2.ResToolCall> resToolCalls = message.getTool_calls();List<MessageV2.ToolCall> toolCalls = new ArrayList<>(resToolCalls.size());resToolCalls.forEach(callFunction -> {MessageV2.Function function = callFunction.getFunction();
//                        assistantMessage.setName(function.getName());
//                        assistantMessage.setTool_call_id(callFunction.getId());MessageV2.ToolCall toolCall = new MessageV2.ToolCall();toolCall.setId(callFunction.getId());toolCall.setType(callFunction.getType());toolCall.setFunction(function);toolCalls.add(toolCall);});assistantMessage.setTool_calls(toolCalls);for(ChoiceV2.ResToolCall toolCall : resToolCalls){MessageV2.Function function = toolCall.getFunction();if(Objects.isNull(function)|| StringUtils.isBlank(function.getName())|| StringUtils.isBlank(function.getArguments())){//没有GPT信息也进行中断循环返回log.error("gptRequestInvoke gptResponse function value is null sessionId = {}, msgDto = {} , gptResponse = {} , function = {}",sessionId,JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(gptResponse),JsonUtil.getJsonString(function));MessageV2 errorAssistantMessage = new MessageV2();errorAssistantMessage.setRole("assistant");errorAssistantMessage.setContent("信息好像丢失了,请更详细的描述您的要求并重试!");msgLinkedList.add(errorAssistantMessage);gptRunCheck = Boolean.FALSE;break;}String functionName = function.getName();if(functionName.contains("saveUserInfo")){String functionArguments = function.getArguments();//arguments value :{"searchKey":"蓝医保·长期医疗险(家庭版)"}JSONObject param = JSONObject.parseObject(functionArguments);String insuranceProductInfo = this.saveUserInfo(param.getString("username"),StringUtils.isNotBlank(param.getString("age")) ? Integer.parseInt(param.getString("age")) : null,param.getString("province"),param.getString("city"),param.getString("address"),param.getString("gender"),param.getString("socialSecurity"),param.getString("educationLevel"),param.getString("pastMedicalHistory"));MessageV2 functionReqMessage = new MessageV2();functionReqMessage.setRole("tool");functionReqMessage.setContent(insuranceProductInfo);functionReqMessage.setTool_call_id(toolCall.getId());functionReqMessage.setName(functionName);msgLinkedList.add(functionReqMessage);}else if(functionName.contains("getUserInfo")){String functionArguments = function.getArguments();//arguments value :{"searchKey":"蓝医保·长期医疗险(家庭版)"}JSONObject param = JSONObject.parseObject(functionArguments);String userInfo = this.getUserInfo(param.getString("username"));MessageV2 functionReqMessage = new MessageV2();functionReqMessage.setRole("tool");functionReqMessage.setContent(userInfo);functionReqMessage.setTool_call_id(toolCall.getId());functionReqMessage.setName(functionName);msgLinkedList.add(functionReqMessage);}}body.setMessages(new ArrayList<>(msgLinkedList));}log.info("gptRequestInvoke ResponseBody sessionId = {}, msgDto = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(gptResponse));} else{//没有GPT信息也进行中断循环返回log.error("gptRequestInvoke gptResponse value is null sessionId = {}, msgDto = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(gptResponse));MessageV2 errorAssistantMessage = new MessageV2();errorAssistantMessage.setRole("assistant");errorAssistantMessage.setContent("信息好像丢失了,请更详细的描述您的要求并重试!");msgLinkedList.add(errorAssistantMessage);gptResponse = new ChatCompletionResponseV2();gptResponse.setId(uniqueCodeComponent.getUniqueCode());List<ChoiceV2> choices = new ArrayList<>();gptResponse.setChoices(choices);ChoiceV2 choiceV2 = new ChoiceV2();choices.add(choiceV2);ChoiceV2.ResMessage message = new ChoiceV2.ResMessage();choiceV2.setMessage(message);message.setContent(errorAssistantMessage.getContent());message.setRole(errorAssistantMessage.getRole());gptRunCheck = Boolean.FALSE;break;}}//保证顺序为 user|assistant  交替进行MessageV2 last = msgLinkedList.getLast();MessageV2 messageV2 = msgLinkedList.get(msgLinkedList.size() - 2);if(Objects.equals(last.getRole(),"user") && Objects.equals(messageV2.getRole(),"assistant")){msgLinkedList.removeLast();}else if(Objects.equals(last.getRole(),"user") && Objects.equals(messageV2.getRole(),"system")){msgLinkedList.removeLast();}else if(Objects.equals(last.getRole(),"user") && Objects.equals(messageV2.getRole(),"function")){msgLinkedList.removeLast();}log.info("gptRequestInvoke request response, msgDto = {}, msgConfigDto = {},msgLinkedList = {}, body = {}",JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(msgConfigDto),JsonUtil.getJsonString(msgLinkedList),JsonUtil.getJsonString(body));return gptResponse;}/*** 构建GPT请求* @param sessionId 会话内容* @param appCode 租户编号* @param body 消息提提* @return*/private ChatCompletionResponseV2 completionBuild(String sessionId,String appCode, ChatCompletionBodyV2 body){SdbCommonAssert.notBlank(sessionId,ErrorCode.PARAMS_IS_NULL,"sessionId value not null");SdbCommonAssert.notBlank(appCode,ErrorCode.PARAMS_IS_NULL,"appCode value not null");SdbCommonAssert.notNull(body,ErrorCode.PARAMS_IS_NULL,"body value not null");ChatCompletionRequestV2 chatRequest = new ChatCompletionRequestV2();chatRequest.setAppCode(appCode);chatRequest.setChatCompletionBody(body);log.info("innerChatCompletionsV2 chatRequest sessionId = {}, appCode = {}, chatRequest = {}",sessionId,JsonUtil.getJsonString(appCode),JsonUtil.getJsonString(chatRequest));com.shuidihuzhu.common.web.model.Response<ChatCompletionResponseV2> gptResponse = null;try {#这里替换为GPT官方文流式|非流式请求接口gptResponse = client.innerChatCompletionsV2(chatRequest);}catch (Exception e){log.error("innerChatCompletionsV2 gptResponse value is null, sessionId = {}, chatRequest = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse),e);return null;}log.info("innerChatCompletionsV2 chatRequest result sessionId = {}, appCode = {}, chatRequest = {},gptResponse = {}",sessionId,JsonUtil.getJsonString(appCode),JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse));if(!Objects.equals(gptResponse.getCode(),0)|| Objects.isNull(gptResponse.getData())){log.error("innerChatCompletionsV2 gptResponse value is null, sessionId = {}, chatRequest = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse));return null;}List<ChoiceV2> choices = gptResponse.getData().getChoices();if(CollectionUtils.isEmpty(choices)){log.error("innerChatCompletionsV2 choices value is empty, sessionId = {}, chatRequest = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse));return null;}//检查内容 默认 TRUE 正确Boolean checkChoice = Boolean.TRUE;for (ChoiceV2 choice : choices){if(Objects.isNull(choice)|| Objects.isNull(choice.getMessage())){log.error("innerChatCompletionsV2 choice value is null, sessionId = {}, chatRequest = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse));checkChoice = Boolean.FALSE;continue;}ChoiceV2.ResMessage message = choice.getMessage();if(StringUtils.isBlank(message.getContent())&& CollectionUtils.isEmpty(message.getTool_calls())){log.error("innerChatCompletionsV2 choice value is null, sessionId = {}, chatRequest = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse));checkChoice = Boolean.FALSE;}}if(!checkChoice){log.error("innerChatCompletionsV2 choice value is null, sessionId = {}, chatRequest = {} , gptResponse = {}",sessionId,JsonUtil.getJsonString(chatRequest),JsonUtil.getJsonString(gptResponse));return null;}return gptResponse.getData();}

其他小方法

buildMsgDto

private void buildMsgDto (MsgDto msgDto,MsgConfigDto msgConfigDto){if(StringUtils.isNotBlank(msgConfigDto.getDatabaseName())){msgDto.setDatabaseName(msgConfigDto.getDatabaseName());}if(StringUtils.isNotBlank(msgConfigDto.getCollectionName())){msgDto.setCollectionName(msgConfigDto.getCollectionName());}if(StringUtils.isNotBlank(msgConfigDto.getAppCode())){msgDto.setAppCode(msgConfigDto.getAppCode());}if(StringUtils.isNotBlank(msgConfigDto.getAiModel())){msgDto.setAiModel(msgConfigDto.getAiModel());}if(Objects.nonNull(msgConfigDto.getMaxTokens())){msgDto.setMaxTokens(msgConfigDto.getMaxTokens());}if(StringUtils.isNotBlank(msgConfigDto.getScoreFlag())){msgDto.setScoreFlag(msgConfigDto.getScoreFlag());}if(StringUtils.isNotBlank(msgConfigDto.getAppPermissionsFunctionScoreFlag())){msgDto.setAppPermissionsFunctionScoreFlag(msgConfigDto.getAppPermissionsFunctionScoreFlag());}if(StringUtils.isNotBlank(msgConfigDto.getInsuranceProductInfoScoreFlag())){msgDto.setInsuranceProductInfoScoreFlag(msgConfigDto.getInsuranceProductInfoScoreFlag());}}

类初始化Client

/*** 链接信息*/private static VectorDBClient CLIENT = null;/*** 获取腾讯云client信息* @return client*/@PostConstructprivate void initVectorDBClient(){if(CLIENT == null){log.info("VectorTestController  buildVectorDBClient -----------开始");// 创建VectorDB ClientConnectParam connectParam = ConnectParam.newBuilder().withUrl(apolloConfigHolder.getDashVector2040312EndPoint()).withUsername(apolloConfigHolder.getDashVectorUserName2040312()).withKey(apolloConfigHolder.getDashVectorApiKey2040312()).withTimeout(30).build();log.info("VectorTestController  buildVectorDBClient -----------参数,connectParam = {}", JsonUtil.getJsonString(connectParam));CLIENT = new VectorDBClient(connectParam, ReadConsistencyEnum.EVENTUAL_CONSISTENCY);log.info("VectorTestController  buildVectorDBClient -----------成功");}}

buildSaveUserInfoTool

private Tool buildSaveUserInfoTool(){Tool saveUserInfoTool = new Tool();saveUserInfoTool.setType("function");Tool.ToolFunction saveUserInfoFunction = new Tool.ToolFunction();saveUserInfoFunction.setName("saveUserInfo");saveUserInfoFunction.setDescription("引导用户向该接口传入用户的基本信息,基本信息内容包括工号、姓名、年龄、省份、城市、地区、性别、是否有社保、学历等信息");JSONObject saveUserInfoJsonObject = new JSONObject();saveUserInfoFunction.setParameters(saveUserInfoJsonObject);saveUserInfoJsonObject.put("type","object");JSONObject saveUserInfoPropertiesObject = new JSONObject();saveUserInfoJsonObject.put("properties",saveUserInfoPropertiesObject);saveUserInfoJsonObject.put("required", new JSONArray(List.of("username")));JSONObject userNameParam = new JSONObject();userNameParam.put("type","string");userNameParam.put("description","姓名|用户信息|用户身份证姓名");saveUserInfoPropertiesObject.put("username",userNameParam);JSONObject ageParam = new JSONObject();ageParam.put("type","integer");ageParam.put("description","数字类型的年龄");saveUserInfoPropertiesObject.put("age",ageParam);JSONObject provinceParam = new JSONObject();provinceParam.put("type","string");provinceParam.put("description","用户所在的省份|指定用户所在的省份");saveUserInfoPropertiesObject.put("province",provinceParam);JSONObject cityParam = new JSONObject();cityParam.put("type","string");cityParam.put("description","用户所在的城市|指定用户所在的城市和位置");saveUserInfoPropertiesObject.put("city",cityParam);JSONObject addressParam = new JSONObject();addressParam.put("type","string");addressParam.put("description","用户所在的详细地址|指定用户的详细地址和详细家庭地址");saveUserInfoPropertiesObject.put("address",addressParam);JSONObject genderParam = new JSONObject();genderParam.put("type","string");genderParam.put("description","用户的性别,默认未知");genderParam.put("enum",List.of("男","女","未知"));saveUserInfoPropertiesObject.put("gender",genderParam);JSONObject socialSecurityParam = new JSONObject();socialSecurityParam.put("type","string");socialSecurityParam.put("description","用户是否缴纳了社保,默认为有社保");socialSecurityParam.put("enum",List.of("有社保","无社保","未知"));saveUserInfoPropertiesObject.put("socialSecurity",socialSecurityParam);JSONObject educationLevelParam = new JSONObject();educationLevelParam.put("type","string");educationLevelParam.put("description","用户的学习以及用户的受教育程度");educationLevelParam.put("enum",List.of("初中及以下学历","初中及同等学历","高中","大专","本科","硕士","博士及以上","中专","其他"));saveUserInfoPropertiesObject.put("educationLevel",educationLevelParam);saveUserInfoTool.setFunction(saveUserInfoFunction);return saveUserInfoTool;}

buildGetUserInfoTool

private Tool buildGetUserInfoTool(){Tool getUserInfoTool = new Tool();getUserInfoTool.setType("function");Tool.ToolFunction getUserInfoFunction = new Tool.ToolFunction();getUserInfoFunction.setName("getUserInfo");getUserInfoFunction.setDescription("当需要获取用户信息时,引导用户向该接口传入用户的姓名,可以获取到已经保存的用户信息,该信息内容包括年龄、省份、城市、地区、性别、学历等信息.虽然可以获取到这些字段,但是对应的字段值可能为空,如果为空可以重复引导用户调用\"saveUserInfo\"接口进行用户信息保存");JSONObject getUserInfoJsonObject = new JSONObject();getUserInfoFunction.setParameters(getUserInfoJsonObject);getUserInfoJsonObject.put("type","object");JSONObject buyInsuranceProductPropertiesObject = new JSONObject();getUserInfoJsonObject.put("properties",buyInsuranceProductPropertiesObject);getUserInfoJsonObject.put("required", new JSONArray(List.of("username")));JSONObject usernameParam = new JSONObject();buyInsuranceProductPropertiesObject.put("username",usernameParam);usernameParam.put("type","string");usernameParam.put("description","用户姓名和购买人姓名或者经纪人姓名");getUserInfoTool.setFunction(getUserInfoFunction);return getUserInfoTool;}

MsgUserInfoDto

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;/*** @author * @date 2024/5/10**/
@Getter
@Setter
@Accessors(chain = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class MsgUserInfoDto {/*** 工号*/private String businessCode;/*** 姓名*/private String username;/*** 年龄*/private Integer age;/*** 当前所处省份*/private String locationProvince;/*** 当前所处城市*/private String locationCity;/*** 当前所处详细地址*/private String locationAddress;/*** 性别 1.男【MALE】 2.女【FEMALE】 3.未知【UNKNOWN】*/private String gender;/*** 是否有社保 1.有社保【hasSocialSecurity】  2.无社保【notHadSocialSecurity】*/private String socialSecurity;/*** 学历* 1.初中及以下学历【JUNIOR01】* 2.初中及同等学历【JUNIOR】* 3.高中【HIGH】* 4.大专【COLLEGE】* 5.本科【BACHELOR】* 6.硕士【MASTER】* 7.博士及以上【DOCTOR】* 8.中专【SECONDARY】* 10.其他【OTHER】*/private String educationLevel;
}

saveUserInfo

/*** 保存用户信息 主键为用户姓名* @param username 用户姓名,不可为空* @param age 年龄* @param province 省份* @param city 城市* @param address 地址* @param gender 性别* @param socialSecurity 是否有社保* @param educationLevel  学历* @param pastMedicalHistory 既往病史:* @return*/private String saveUserInfo(String username,Integer age,String province,String city,String address,String gender,String socialSecurity,String educationLevel){if(StringUtils.isBlank(username)){return "用户没有输入姓名等关键字,请重新引导用户输入姓名,尽量用更加婉转的方式";}MsgUserInfoDto userInfoDto = USER_NAME_MAP.get(username);if(Objects.isNull(userInfoDto)){userInfoDto = new MsgUserInfoDto();userInfoDto.setUsername(username);}if(Objects.nonNull(age)){userInfoDto.setAge(age);}if(StringUtils.isNotBlank(province)){userInfoDto.setLocationProvince(province);}if(StringUtils.isNotBlank(city)){userInfoDto.setLocationCity(city);}if(StringUtils.isNotBlank(address)){userInfoDto.setLocationAddress(address);}if(StringUtils.isNotBlank(gender)){userInfoDto.setGender(gender);}if(StringUtils.isNotBlank(socialSecurity)){userInfoDto.setSocialSecurity(socialSecurity);}if(StringUtils.isNotBlank(educationLevel)){userInfoDto.setEducationLevel(educationLevel);}USER_NAME_MAP.put(username,userInfoDto);return JsonUtil.getJsonString(userInfoDto);}

getUserInfo

/*** 获取用户信息 主键为用户姓名* @param username 用户姓名,不可为空* @return*/private String getUserInfo(String username){if(StringUtils.isBlank(username)){return "用户没有输入姓名等关键字,请重新引导用户输入姓名,尽量用更加婉转的方式";}MsgUserInfoDto userInfoDto = USER_NAME_MAP.get(username);if(Objects.isNull(userInfoDto)){return "该用户还没有保存个人信息,请引导用户向该接口传入用户的基本信息,基本信息内容包括姓名、年龄、省份、城市、地区、性别、是否有社保、学历等,可以通过多轮访问多轮问询的方式,滚动存储";}return JsonUtil.getJsonString(userInfoDto);}

MsgResponseDto


import com.shuidihuzhu.ai.alps.client.model.completions.v2.ChatCompletionResponseV2;
import com.shuidihuzhu.ai.alps.client.model.completions.v2.MessageV2;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;import java.util.LinkedList;/*** @author * @date 2024/3/14**/
@Getter
@Setter
@Accessors(chain = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class MsgResponseDto {/*** 传入的消息体*/private MsgDto requestMsg;/*** 返回的内容*/private ChatCompletionResponseV2 responseMsg;/*** 生成或者传入的消息体ID*/private String sessionId;/*** 目前该SessionId下存储的消息内容*/private LinkedList<MessageV2> msgLinkedList;/*** 目前该SessionId下存储的消息内容*/private LinkedList<MessageV2> msgLinkedListAll;/*** 音频地址*/private String speechUrl;
}

文字转语音

    /*** 返回音频地址* @param lastMsg 最后一条消息内容* @return*/private String textToSpeech(MessageV2 lastMsg, MsgConfigDto msgConfigDto){String speechUrl = null;if(Objects.equals(lastMsg.getRole(),"assistant")&& StringUtils.isNotBlank(lastMsg.getContent())&& lastMsg.getContent().length() <= msgConfigDto.getTextToSpeechLengthLimit()&& msgConfigDto.getTextToSpeechFlag()){AudioSpeechRequest audioSpeechRequest = new AudioSpeechRequest();audioSpeechRequest.setModel(msgConfigDto.getAudioSpeechModel());audioSpeechRequest.setInput(lastMsg.getContent());audioSpeechRequest.setVoice("onyx");com.shuidihuzhu.common.web.model.Response<String> speechResponse = null;try {#这里替换为GPT官方文档的文字转语音接口speechResponse = client.innerAudioSpeech(msgConfigDto.getAppCode(), audioSpeechRequest);}catch (Exception e){log.error("innerChatCompletionsV2 textToSpeech innerAudioSpeech has exception, lastMsg = {}, msgConfigDto = {} , audioSpeechRequest = {} , speechResponse = {}",JsonUtil.getJsonString(lastMsg),JsonUtil.getJsonString(msgConfigDto),JsonUtil.getJsonString(audioSpeechRequest),JsonUtil.getJsonString(speechResponse));return null;}if(!Objects.equals(speechResponse.getCode(),0)|| StringUtils.isBlank(speechResponse.getData())){log.error("innerChatCompletionsV2 textToSpeech speechResponse value is null, lastMsg = {}, msgConfigDto = {} , audioSpeechRequest = {} , speechResponse = {}",JsonUtil.getJsonString(lastMsg),JsonUtil.getJsonString(msgConfigDto),JsonUtil.getJsonString(audioSpeechRequest),JsonUtil.getJsonString(speechResponse));return null;}speechUrl = speechResponse.getData();}return speechUrl;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/869916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Visutal Studio 2022中完成D3D12初始化

在Visutal Studio 2022中完成DirectX设备初始化 1 DirectX121.1 DirectX 简介1.2 DirectX SDK安装2 D3D12初始化2.1 创建Windwos桌面项目2.2 修改符合模式2.3 下载d3dx12.h文件2.4 创建一个异常类D3DException,定义抛出异常实例的宏ThrowIfFailed3 D3D12的初始化步骤3.1 初始化…

pytorch实现水果2分类(蓝莓,苹果)

1.数据集的路径&#xff0c;结构 dataset.py 目的&#xff1a; 输入&#xff1a;没有输入&#xff0c;路径是写死了的。 输出&#xff1a;返回的是一个对象&#xff0c;里面有self.data。self.data是一个列表&#xff0c;里面是&#xff08;图片路径.jpg&#xff0c;标签&…

JMH325【剑侠情缘3】第2版80级橙武网游单机更稳定亲测视频安装教学更新整合收集各类修改教学补丁兴趣可以慢慢探索

资源介绍&#xff1a; 是否需要虚拟机&#xff1a;是 文件大小&#xff1a;压缩包约14G 支持系统&#xff1a;win10、win11 硬件需求&#xff1a;运行内存8G 4核及以上CPU独立显卡 下载方式&#xff1a;百度网盘 任务修复&#xff1a; 1&#xff0c;掌门任务&#xff08…

【Android组件】封装加载弹框

&#x1f4d6;封装加载弹框 ✅1. 构造LoadingDialog✅2. 调用LoadingDialog 效果&#xff1a; ✅1. 构造LoadingDialog 构造LoadingDialog类涉及到设计模式中的建造者模式&#xff0c;进行链式调用&#xff0c;注重的是构建的过程&#xff0c;设置需要的属性。 步骤一&#x…

[数据结构] 归并排序快速排序 及非递归实现

&#xff08;&#xff09;标题&#xff1a;[数据结构] 归并排序&&快速排序 及非递归实现 水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 (一)快速排序 类比递归谋划非递归 快速排序的非递归实现&#xff1a; &#xff08;二&#xff09;归并排序 归…

Elasticsearch文档_id以数组方式返回

背景需求是只需要文档的_id字段&#xff0c;并且_id组装成一个数组。 在搜索请求中使用 script_fields 来整理 _id 为数组输出&#xff1a; POST goods_info/_search?size0 {"query": {"term": {"brand": {"value": "MGC"…

[240710] Workspaice:人机协作,共同创造 | 如何利用生成式 AI 自动化网络安全防御

目录 Workspaice&#xff1a;人机协作&#xff0c;共同创造如何利用生成式 AI 自动化网络安全防御 Workspaice&#xff1a;人机协作&#xff0c;共同创造 一、项目介绍 Workspaice 是一款本地运行的应用程序&#xff0c;旨在结合人类创造力和 AI 辅助功能。它不仅仅是一个代码…

明白这两大关键点,轻松脱单不再是难题!

很多未婚男女都渴望找到心仪的伴侣&#xff0c;建立稳定的情感关系&#xff0c;但往往在脱单的过程中跌跌撞撞。平时与同学、同事之间相处得很融洽&#xff0c;一旦遇到心仪的异性&#xff0c;情商直接掉线&#xff0c;难道情商也会选择性地发挥作用吗&#xff1f;其实&#xf…

什么牌子的开放式耳机好用?南卡、Cleer、小米、开石超值机型力荐!

​开放式耳机在如今社会中已经迅速成为大家购买耳机的新趋势&#xff0c;深受喜欢听歌和热爱运动的人群欢迎。当大家谈到佩戴的稳固性时&#xff0c;开放式耳机都会收到一致好评。对于热爱运动的人士而言&#xff0c;高品质的开放式耳机无疑是理想之选。特别是在近年来的一些骑…

AnimateLCM:高效生成连贯真实的视频

视频扩散模型因其能够生成连贯且高保真的视频而日益受到关注。然而&#xff0c;迭代去噪过程使得这类模型计算密集且耗时&#xff0c;限制了其应用范围。香港中文大学 MMLab、Avolution AI、上海人工智能实验室和商汤科技公司的研究团队提出了AnimateLCM&#xff0c;这是一种允…

电子电气架构 --- 关于DoIP的一些闲思 上

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

JavaDS —— 单链表 与 LinkedList

顺序表和链表区别 ArrayList &#xff1a; 底层使用连续的空间&#xff0c;可以随机访问某下标的元素&#xff0c;时间复杂度为O&#xff08;1&#xff09; 但是在插入和删除操作的时候&#xff0c;需要将该位置的后序元素整体往前或者向后移动&#xff0c;时间复杂度为O&…

扫描服务器端口(Python)

目录 1 背景2 代码2.1 单线程扫描2.2 多线程扫描 1 背景 如果只知道服务器的地址&#xff0c;不知道其提供服务端口号&#xff0c;可以通过扫描所有端口方式发现服务器提供哪些端口。下面使用Python编写脚本扫描服务器端口。 2 代码 服务器有效端口1-65535 2.1 单线程扫描 …

什么是智能制造?

科技的每一次飞跃都深刻改变着我们的生产生活方式。其中&#xff0c;智能制造作为工业4.0的核心概念&#xff0c;正引领着全球制造业向更加高效、灵活、智能的方向迈进。那么&#xff0c;究竟什么是智能制造&#xff1f;它如何重塑我们的工业版图&#xff0c;又将对未来社会产生…

TTT架构超越Transformer,ML模型替代RNN隐藏状态!

目录 01 算法原理 02 骨干架构 03 实验结果 一种崭新的大语言模型&#xff08;LLM&#xff09;架构有望取代当前主导 AI 领域的 Transformer&#xff0c;并在性能上超越 Mamba。 论文地址&#xff1a;https://arxiv.org/abs/2407.04620 本周一&#xff0c;关于 Test-Time Tr…

修复 Ubuntu 24.04 Dock 丢失应用程序图标

找出应用程序窗口的类名 首先&#xff0c;您需要启动应用程序窗口。然后&#xff0c;按 Alt F2 启动“运行 Command”对话框。当对话框打开时&#xff0c;输入 lg 并按 Enter 键。 在该窗口中&#xff0c;单击Windows按钮&#xff0c;然后找出目标应用程序窗口的类名称。 在/…

Jinja2模板引擎使用指南

文章目录 官网链接引言Jinja2 原理基础使用安装 Jinja2基本示例 高级使用宏&#xff08;Macros&#xff09;过滤器&#xff08;Filters&#xff09;继承&#xff08;Inheritance&#xff09; 结论 官网链接 Jinja2 官网 引言 Jinja2 是一个现代的、设计师友好的模板引擎&…

Flutter——最详细(Table)网格、表格组件使用教程

背景 用于展示表格组件&#xff0c;可指定线宽、列宽、文字方向等属性 属性作用columnWidths列的宽度defaultVerticalAlignment网格内部组件摆放方向border网格样式修改children表格里面的组件textDirection文本排序方向 import package:flutter/material.dart;class CustomTa…

公众号运营秘籍:8 大策略让你的粉丝翻倍!

在当今信息爆炸的时代&#xff0c;微信公众号的运营者们面临着前所未有的挑战&#xff1a;如何在这个充满竞争的红海中脱颖而出&#xff0c;吸引并留住粉丝&#xff1f;事实上&#xff0c;微信公众号的红利期并未完全过去&#xff0c;关键在于我们如何策略性地运营&#xff0c;…

使用PEFT库进行ChatGLM3-6B模型的QLORA高效微调

PEFT库进行ChatGLM3-6B模型QLORA高效微调 QLORA微调ChatGLM3-6B模型安装相关库使用ChatGLM3-6B模型GPU显存占用准备数据集加载数据集数据处理数据集处理加载量化模型-4bit预处理量化模型配置LoRA适配器训练超参数配置开始训练保存LoRA模型模型推理合并模型使用微调后的模型 QLO…