当前位置: 首页 > news >正文

GPT+向量数据库+Function calling=垂直领域小助手

引言

将 GPT、向量数据库和 Function calling 结合起来,可以构建一个垂直领域小助手。例如,我们可以使用 GPT 来处理自然语言任务,使用向量数据库来存储和管理领域相关的数据,使用 Function calling 来实现领域相关的推理和计算规则。这样,我们就可以构建一个针对特定领域的小助手,例如医疗保健、金融服务、法律咨询等。
今天为大家分享一个保险领域AI小助手的DEMO展示,含代码!!!

工具介绍

GPT

GPT(Generative Pretrained Transformer)是一种基于 Transformer 架构的大型语言模型,通过在大量文本上进行无监督学习,模型学习到了语言的统计规律和语义表示,从而能够处理各式各样的自然语言任务,例如文本生成、知识问答、推理计算、阅读理解等。
本文使用模型:gpt-3.5-turbo
本文使用GPT方法:Chat Completions API

向量数据库

向量数据库是一种用于存储和管理向量数据的数据仓库,其中向量是一种将文本、图像、音频等非结构化数据转换为可计算的稠密向量表示的技术。通过使用向量数据库,我们可以快速地查找和比较相似的向量,从而实现诸如文本分类、聚类、推荐系统等应用。
本文使用腾讯云向量数据库

Function calling

Function calling 是一种在编程语言中调用函数的机制。通过函数调用,我们可以将复杂的任务分解为多个简单的函数,并通过调用这些函数来完成任务。在自然语言处理中,我们可以使用 Function calling 来实现自定义的推理和计算规则。
本文使用:gpt-3.5的Function calling

代码:

向腾讯云向量向量数据库构建数据

0、maven依赖

<vectordatabase-sdk-java.version>1.2.0</vectordatabase-sdk-java.version>
<okhttp.version>4.9.2</okhttp.version>
<dependency><groupId>com.tencent.tcvectordb</groupId><artifactId>vectordatabase-sdk-java</artifactId><version>${vectordatabase-sdk-java.version}</version><exclusions><!--因为我项目依赖了log4j相关其他包所以这里对impl包进行了排除 --><exclusion><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId></exclusion></exclusions></dependency>
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>${okhttp.version}</version></dependency>

1、获取腾讯云client信息
这里的相关Url和相关账户请替换成自己的


/*** 链接信息*/private static VectorDBClient CLIENT = null;/*** 存放消息体的地方-模拟数据库,因为是DEMO所以没有接数据库只在自己内存用一下*/private static Map<String, LinkedList<MessageV2>> SESSION_MSG_MAP = new HashMap<>(10);/*** 获取腾讯云client信息* @return client*/@PostConstructprivate void initVectorDBClient(){if(CLIENT == null){log.info("VectorTestController  buildVectorDBClient -----------开始");// 创建VectorDB Client 这里的相关Url和相关账户请替换成自己的ConnectParam 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 -----------成功");}}

2、创建腾讯云数据库

/*** 创建腾讯云数据库* @param databaseName* @return*/private Database buildDatabase(String databaseName){log.info("VectorTestController  createDatabase -----------开始 , databaseName = {}", databaseName);SdbCommonAssert.notBlank(databaseName, ErrorCode.PARAMS_IS_NULL);Database db = CLIENT.createDatabase(databaseName);log.info("VectorTestController  createDatabase -----------成功 , databaseName = {}", databaseName);return db;}

3、向指定数据库和分区构建初始化数据

/*** databaseName=zzz* collectionName=zzz* 向指定分区构建初始化数据* @return 初始化数据与否*/@RequestMapping("test/initXXX")public com.shuidihuzhu.sdb.models.Response<Boolean> initCollection(@RequestParam(name = "databaseName",required = true) String databaseName,@RequestParam(name = "collectionName",required = true) String collectionName){SdbCommonAssert.notBlank(databaseName, ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(collectionName, ErrorCode.PARAMS_IS_NULL);List<String> listDatabase = CLIENT.listDatabase();Boolean clientBuildFlag = Boolean.FALSE;for (String database : listDatabase){if(Objects.equals(database,databaseName)){clientBuildFlag = Boolean.TRUE;}}Database db = null;if(!clientBuildFlag){db = this.buildDatabase(databaseName);}else {db = CLIENT.database(databaseName);}Boolean collectionFlag = Boolean.FALSE;Collection collection = null;List<Collection> collections = db.listCollections();for(Collection collectionItem : collections){if(Objects.equals(collectionItem.getCollection(),collectionName)){collectionFlag = Boolean.TRUE;collection = collectionItem;}}if(!collectionFlag){CreateCollectionParam collectionParam = CreateCollectionParam.newBuilder().withName(collectionName).withReplicaNum(2).withShardNum(1).withDescription("小超公司基本法信息章节存储表,存储小超公司历史基本法信息及基本法版本信息").addField(new FilterIndex("id", FieldType.String, IndexType.PRIMARY_KEY)).addField(new FilterIndex("chapterName", FieldType.String, IndexType.FILTER)).addField(new FilterIndex("pageNo", FieldType.Uint64, IndexType.FILTER)).addField(new FilterIndex("chapterNo", FieldType.Uint64, IndexType.FILTER)).addField(new FilterIndex("parentChapterNo", FieldType.Uint64, IndexType.FILTER)).addField(new VectorIndex("vector", 768, IndexType.HNSW, MetricType.COSINE, new HNSWParams(16, 200))).withEmbedding(Embedding.newBuilder().withModel(EmbeddingModelEnum.BGE_BASE_ZH).withField("lawText").withVectorField("vector").build()).build();collection = db.createCollection(collectionParam);AffectRes affectRes = db.setAlias(collectionName, collectionName);if(Objects.equals(affectRes.getCode(),0)){log.info("VectorTestController  initCollection setAlias -----------成功 , collectionName = {}", collectionName);}else {log.info("VectorTestController   initCollection setAlias -----------失败 , collectionName = {} ,affectRes = {}", collectionName,JsonUtil.getJsonString(affectRes));}}//该信息为虚拟信息,不能产生任何价值也不代表任何利益相关,纯粹是虚拟构建Document doc1 = Document.newBuilder().withId("test0001").addDocField(new DocField("chapterName","首年度佣金发放规则")).addDocField(new DocField("pageNo",13)).addDocField(new DocField("chapterNo",22)).addDocField(new DocField("parentChapterNo",5)).addDocField(new DocField("lawText","首年度佣金发放规则:一、保单在当月最后一天(含)前承保(包括当月承保及之前月份承保未核发佣金的保单);二、保单在次月XX日(含)前回访成功;三、保单在次月XX日(含)前完成《委托协议书》及《客户告知书》的签署;四、保单在次月XX日(含)前为非犹豫期退保状态;五、依据当地监管要求,保单在下月XX日(含)前完成质检;")).build();//该信息为虚拟信息,不能产生任何价值也不代表任何利益相关,纯粹是虚拟构建Document doc13 = Document.newBuilder().withId("test0013").addDocField(new DocField("chapterName","产品名称:XX保意外险")).addDocField(new DocField("pageNo",45)).addDocField(new DocField("chapterNo",76)).addDocField(new DocField("parentChapterNo",1)).addDocField(new DocField("lawText","商品编码:rbywx\t\n" +"产品名称:xXX保意外险\n" +"保司简称:XXX保财险\n" +"长短险标志:长险\n" +"险种标志:意外\n" +"等待期天数:30\n" +"犹豫期天数:30\n" +"宽限期天数:60\n" +"一句话卖点:全面升级,保障更加多元\n" +"产品卖点:[\"意外伤害保额最高XX万\",\"因为意外情况住院不会限制社保的报销范围\",\"因为意外住院享受住院津贴,因为意外骨折后后相关保障计划\"]\n" +"最低保费描述:XX元起\n" +"最高保费:XX\n" +"职业范围描述:1-6类\n" +"投保最小年龄限制(岁):X2\n" +"投保最大年龄限制(岁):X1\n" +"健康告知及注意事项:常见健康告知xxxxxx\n")).build();InsertParam insertParam = InsertParam.newBuilder().addDocument(doc1).addDocument(doc13).withBuildIndex(true).build();AffectRes affectRes = collection.upsert(insertParam);if(Objects.equals(affectRes.getCode(),0)){log.info("VectorTestController  initCollection collectionUpsert -----------成功 , affectRes = {}", affectRes);}else {log.info("VectorTestController   initCollection collectionUpsert -----------失败 , insertParam = {} ,affectRes = {}", JsonUtil.getJsonString(insertParam),JsonUtil.getJsonString(affectRes));}return ResponseUtil.makeSuccess(Boolean.TRUE);}

清除指定构建的数据

/*** 清空指定集合* @return 初始化数据与否*/@RequestMapping("test/cleanXXX")public com.shuidihuzhu.sdb.models.Response<Boolean> cleanCollection(@RequestParam(name = "databaseName",required = true) String databaseName,@RequestParam(name = "collectionName",required = true) String collectionName){SdbCommonAssert.notBlank(databaseName, ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(collectionName, ErrorCode.PARAMS_IS_NULL);List<String> stringList = CLIENT.listDatabase();Boolean clientBuildFlag = Boolean.FALSE;for (String database : stringList){if(Objects.equals(database,databaseName)){clientBuildFlag = Boolean.TRUE;}}Database db = null;if(!clientBuildFlag){db = this.buildDatabase(databaseName);}else {db = CLIENT.database(databaseName);}AffectRes affectRes = db.truncateCollections(collectionName);log.info("cleanCollection result, affectRes = {}",JsonUtil.getJsonString(affectRes));return ResponseUtil.makeSuccess(Objects.equals(affectRes.getCode(),0));}

GPT交互接口

1、请求体
这里是请求GPT交互接口的请求体

/*** @author chao* @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 Double scoreFlag = 0.77;}

2、GPT请求接口
这里是构建GPT会话信息属于公共方法。
相关GPT的请求类和消息体类请自己根据官方文档进行包装,这里没有进行包装。

/*** 构建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));Response<ChatCompletionResponseV2> gptResponse = chatGptOverseaClient.innerChatCompletionsV2(chatRequest);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();}

3、GPT交互接口
真实的GPT交互接口

    /*** GPT交互接口* @param msgDto* @return*/@RequestMapping("test/gptXXX")public com.shuidihuzhu.sdb.models.Response<MsgResponseDto> innerChatCompletionsV2(@RequestBody(required = true) MsgDto msgDto){SdbCommonAssert.notNull(msgDto, ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(msgDto.getDatabaseName(),ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(msgDto.getCollectionName(),ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(msgDto.getAppCode(),ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(msgDto.getAiModel(),ErrorCode.PARAMS_IS_NULL);SdbCommonAssert.notBlank(msgDto.getPrompt(),ErrorCode.PARAMS_IS_NULL);String sessionId = msgDto.getSessionId();if(StringUtils.isBlank(sessionId)){//唯一串生成代码,请替换成自己的或使用UUIDsessionId = uniqueCodeComponent.getUniqueCode();msgDto.setSessionId(sessionId);}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")).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() < 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 = "在保险行业中," + prompt;}}else {prompt = "在保险行业中," + 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);}ChatCompletionBodyV2 body = new ChatCompletionBodyV2();body.setLogit_bias(new HashMap<>());body.setMessages(new ArrayList<>(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<>(1);Tool tool = new Tool();toolList.add(tool);tool.setType("function");Tool.ToolFunction toolFunction = new Tool.ToolFunction();toolFunction.setName("buyInsuranceProduct");toolFunction.setDescription("向这个接口传入保险产品编码或者保险产品名称,可以获得该保险产品的下单链接以及相关宣传信息");JSONObject jsonObject = new JSONObject();toolFunction.setParameters(jsonObject);jsonObject.put("type","object");JSONObject propertiesObject = new JSONObject();jsonObject.put("properties",propertiesObject);jsonObject.put("required", new JSONArray(List.of("searchKey")));JSONObject searchKeyParam = new JSONObject();propertiesObject.put("searchKey",searchKeyParam);searchKeyParam.put("type","string");searchKeyParam.put("description","保险产品名称或者保险产品编码");tool.setFunction(toolFunction);body.setTools(toolList);//构建GPT请求ChatCompletionResponseV2 gptResponse = this.completionBuild(sessionId, msgDto.getAppCode(), body);MsgResponseDto msgResponse = new MsgResponseDto();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.isNotEmpty(message.getTool_calls())){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.nonNull(function)&& StringUtils.isNotBlank(function.getName())&& StringUtils.isNotBlank(function.getArguments())){String functionName = function.getName();if(Objects.equals(functionName,"buyInsuranceProduct")){String functionArguments = function.getArguments();//arguments value :{"searchKey":"XXX医疗险(家庭版)"}JSONObject param = JSONObject.parseObject(functionArguments);String insuranceProductInfo = this.getInsuranceProductInfo(param.getString("searchKey"));MessageV2 functionReqMessage = new MessageV2();functionReqMessage.setRole("tool");functionReqMessage.setContent(insuranceProductInfo);functionReqMessage.setTool_call_id(toolCall.getId());functionReqMessage.setName(functionName);msgLinkedList.add(functionReqMessage);}}}body.setMessages(new ArrayList<>(msgLinkedList));//构建GPT请求ChatCompletionResponseV2 functionGptResponse = this.completionBuild(sessionId, msgDto.getAppCode(), body);if(Objects.nonNull(functionGptResponse)){gptResponse = functionGptResponse;List<ChoiceV2> functionChoices = functionGptResponse.getChoices();for (ChoiceV2 functionChoice : functionChoices){ChoiceV2.ResMessage functionResMessage = functionChoice.getMessage();MessageV2 functionAssistantResMessage = new MessageV2();functionAssistantResMessage.setRole(functionResMessage.getRole());functionAssistantResMessage.setContent(functionResMessage.getContent());msgLinkedList.add(functionAssistantResMessage);}}else{log.error("innerChatCompletionsV2 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);}}}log.info("innerChatCompletionsV2 ResponseBody sessionId = {}, msgDto = {} , msgResponse = {}",sessionId,JsonUtil.getJsonString(msgDto),JsonUtil.getJsonString(msgResponse));} else{log.error("innerChatCompletionsV2 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);}msgResponse.setRequestMsg(msgDto);msgResponse.setSessionId(sessionId);msgResponse.setMsgLinkedList(msgLinkedList);msgResponse.setResponseMsg(gptResponse);//保证顺序为 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("innerChatCompletionsV2 SESSION_MSG_MAP = {}", JsonUtil.getJsonString(SESSION_MSG_MAP));return ResponseUtil.makeSuccess(msgResponse);}

4、获取产品信息
这里模拟得数查询数据库信息后续可进行替换

    /*** 获取产品下单信息* @param productSearchKey 产品名称或者产品编码* @return*/private String getInsuranceProductInfo(String productSearchKey){log.info("innerChatCompletionsV2 getInsuranceProductInfo param,productSearchKey = {} ", productSearchKey);JSONObject rbdjJsonObject = new JSONObject();rbdjJsonObject.put("productName","xXX保意外险");rbdjJsonObject.put("productDesc","这是xXX保意外险的产品描述");rbdjJsonObject.put("productOrderUrl","www.baidu.com/XXX_XXYWX_XXYWX");JSONObject ygrsJsonObject = new JSONObject();ygrsJsonObject.put("productName","SDFSDF人寿SDFFD高端SDFSDF保险");ygrsJsonObject.put("productDesc","这是SDFSDF人寿SDFFD高端SDFSDF保险的产品描述");ygrsJsonObject.put("productOrderUrl","www.baidu.com/SDF_SDSDFrs_SDDFSFFSDFSDlbx");JSONObject ygrszzJsonObject = new JSONObject();ygrszzJsonObject.put("productName","阳光XSDSDSXX臻享XXDSDX高端XXSDSSDDX保险");ygrszzJsonObject.put("productDesc","这是阳光XXDX臻享XXSDDX高端XSDSDXX保险的产品描述");ygrszzJsonObject.put("productOrderUrl","www.baidu.com/XX_ygXXXs_zzSADSFADFgdylbx");JSONObject lybJsonObject = new JSONObject();lybJsonObject.put("productName","XXX·XX医疗险(XXX版)");lybJsonObject.put("productDesc","这是XXX·XX医疗险(XXX版)的产品描述");lybJsonObject.put("productOrderUrl","www.baidu.com/fXX_lXASDXXcqXXXSDFXlx_jXXtXXXb");JSONObject sdhsjJsonObject = new JSONObject();sdhsjJsonObject.put("productName","XXX护身甲XXX意外险");sdhsjJsonObject.put("productDesc","这是XASDXX护身甲XXASX意外险的产品描述");sdhsjJsonObject.put("productOrderUrl","www.baidu.com/zXXXDSAXx_XDASXhsXFDGjXXX");JSONArray array = new JSONArray();array.add(rbdjJsonObject);array.add(ygrsJsonObject);array.add(ygrszzJsonObject);array.add(lybJsonObject);array.add(sdhsjJsonObject);log.info("innerChatCompletionsV2 getInsuranceProductInfo result,array = {} ", array);return array.toString();}

5、返回的消息体
相关GPT的请求类和消息体类请自己根据官方文档进行包装,这里没有进行包装。

/*** @author chao* @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;
}

相关文章:

GPT+向量数据库+Function calling=垂直领域小助手

引言 将 GPT、向量数据库和 Function calling 结合起来&#xff0c;可以构建一个垂直领域小助手。例如&#xff0c;我们可以使用 GPT 来处理自然语言任务&#xff0c;使用向量数据库来存储和管理领域相关的数据&#xff0c;使用 Function calling 来实现领域相关的推理和计算规…...

DeepSeek-coder 微调训练记录

简介 微调过程不再细说, 参考link进行即可. 主要是数据集. 1.3b模型微调训练占用资源信息 top信息 评估 根据DeepSeek-coder的Evaluation试进行对微调后的模型进行评估. 其中的评估库主要是evol-teacher和human-eval. 新建一个eval_ins.sh文件, 填入以下内容 LANG"…...

【Android】【Bluetooth Stack】蓝牙音乐协议分析之音频控制与信息加载(超详细)

1. 精讲蓝牙协议栈(Bluetooth Stack):SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅,【蓝牙协议栈】和【Android Bluetooth Stack】专栏会持续更新中.....敬请期待! 目录 1. 音乐信息加载 1.1 歌曲信息 1.1.1 key_c…...

ChatGPT无法登录,提示我们检测到可疑的登录行为?如何解决?

OnlyFans 订阅教程移步&#xff1a;【保姆级】2024年最新Onlyfans订阅教程 Midjourney 订阅教程移步&#xff1a; 【一看就会】五分钟完成MidJourney订阅 GPT-4.0 升级教程移步&#xff1a;五分钟开通GPT4.0 如果你需要使用Wildcard开通GPT4、Midjourney或是Onlyfans的话&am…...

程序员表白

啥&#xff1f;&#xff01;你说程序员老实&#xff0c;认真工作&#xff0c;根本不会什么表白&#xff01;那你就错了&#xff01;(除了我) 那今天我们就来讲一下这几个代码&#xff01;赶紧复制下来&#xff0c;这些代码肯定有你有用的时候&#xff01; 1.Python爱心代码 im…...

CSS的使用与方法

什么是CSS CSS是层叠样式表。它是一种用于描述网页或者文档外观和样式的标记语言。 层级样式表&#xff1a;就是给HTML标签加样式的。 如果说HTML是个游戏英雄 、那么CSS就是游戏皮肤。 【一】注释语法 /* 注释 */ 【二】CSS的语法结构 选择符 {样式属性: 样式属性值;样…...

(保姆级)离线安装mongoDB集群

Docker搭建MongoDB集群 副本集模式&#xff08;Replica Set&#xff09; 是一种互为主从的关系&#xff0c; Replica Set 将数据复制多份保存&#xff0c;不同服务器保存同一份数据&#xff0c;在出现故障时自动切换&#xff0c;实现故障转移。 此集群拥有一个主节点和多个从…...

面试笔记——MySQL(主从同步原理、分库分表)

主从同步原理 主从同步结构&#xff1a;主库负责写数据&#xff0c;从库负责读数据&#xff0c;如图—— MySQL主从复制的核心就是二进制日志&#xff08;BINLOG&#xff09;&#xff0c;它记录了所有的 DDL&#xff08;数据定义语言&#xff09;语句和 DML&#xff08;数据操…...

面试题2.0

目录 css 动画 深拷贝和浅拷贝 ES6新特性 事件循环 vue-router原理 flex布局 session和local storage分别是用来干嘛的&#xff1f; http状态码 原型链 虚拟dom vuex的五个属性 vue路由跳转的四种方式 vue生命周期 link和import的区别 GET 与 POST 的区别 fle…...

【剑指offer】53. 最小的k个数(java选手)(优先队列+快排+快速选择)

题目链接 题目链接 力扣题目链接 题目描述 输入 n个整数&#xff0c;找出其中最小的 k 个数。 注意&#xff1a; 输出数组内元素请按从小到大顺序排序; 数据范围 1≤k≤n≤1000 样例 输入&#xff1a;[1,2,3,4,5,6,7,8] , k4 输出&#xff1a;[1,2,3,4] 题目分析 排序算法…...

带有GUI界面的电机故障诊断(MSCNN-BILSTM-ATTENTION模型,TensorFlow框架,有中文注释,带有六种结果可视化)

本次创作最主要是在MSCNN-BILSTM-ATTENTION模型&#xff08;可轻松替换为其它模型&#xff09;基础上&#xff0c;搭建GUI测试界面&#xff0c;方便对你想要测试的数据的进行测试&#xff0c;同时进行了全面的结果可视化&#xff1a;1.训练集和测试集的准确率曲线&#xff0c;2…...

【技术栈】Spring Cache 简化 Redis 缓存使用

​ SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 ​ 本文封面由 凯楠&#x1f4f8; 友情提供 目录 本栏传送门 1. Spring Cache 介绍 2. Spring Cache 常用注解 注&#xff1a;手机端浏览本文章…...

解决wrap_socket() got an unexpected keyword argument ‘ciphers‘

看报错本以为是一个简单的传参问题&#xff0c;没想到查到盘丝洞。 # 报错信息 wrap_socket() got an unexpected keyword argument ciphers# 报错代码段 _exception_handler() def connect(self):u"""连接MySQL数据库"""self.config_connect_a…...

【力扣hot100】128.最长连续序列

给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [100,4,200,1,3,2] 输出&#xff1a;4 解…...

css的text-shadow详解

CSS的text-shadow属性用于为文本添加阴影效果&#xff0c;以增强文本的立体感和印刷品质感。该属性可以接受多个值&#xff0c;每个值通过空格分隔&#xff0c;以定义阴影的各个方面。以下是text-shadow属性的详细介绍&#xff1a; 阴影颜色 (Color): 这是阴影的颜色值。它可以…...

Qt 利用共享内存实现一次只能启动一个程序(单实例运行)

Qt 利用共享内存实现一次只能启动一个程序 文章目录 Qt 利用共享内存实现一次只能启动一个程序摘要利用共享内存实现一次只能启动一个程序示例代码 关键字&#xff1a; Qt、 unique、 单一、 QSharedMemory、 共享内存 摘要 今天接着在公司搞我的屎山代码&#xff0c;按照…...

【生活知识-茶叶】

生活知识-茶叶 茶 茶 茶叶分类代表茶名功效绿茶龙井碧螺春 毛峰清热解毒、降脂减肥、提神醒脑、改善肝功能、减轻肝脏负担乌龙茶铁观音武夷岩茶冻顶乌龙茶清心明目、提神醒脑、促进新陈代谢、维护肝脏健康白茶白毫银针白牡丹贡眉清热降火、抗氧化、保护心血管、提高免疫力黄茶…...

[AIGC] 在Spring Boot中指定请求体格式

在使用Spring Boot开发Web应用的时候&#xff0c;我们经常会遇到需要接收并处理HTTP请求的情况。一个HTTP请求通常包括一个请求行、若干请求头和一个请求体。请求体在POST和PUT请求中特别重要&#xff0c;因为它通常用于向服务器传递数据。 文章目录 创建并使用一个Java Bean指…...

4核16G服务器租用优惠价格,26.52元1个月,半年149元

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年&#xff0c;配置为阿里云服务器ECS经济型e实例ecs.e-c1m4.xlarge&#xff0c;4核16G、按固定带宽 10Mbs、100GB ESSD Entry系统盘&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接打开如下图&a…...

2024 Mazing 3 中文版新功能介绍Windows and macOS

iMazing 3中文版(ios设备管理软件)是一款管理苹果设备的软件&#xff0c; Windows 平台上的一款帮助用户管理 IOS 手机的应用程序。iMazing中文版与苹果设备连接后&#xff0c;可以轻松传输文件&#xff0c;浏览保存信息等&#xff0c;软件功能非常强大&#xff0c;界面简洁明晰…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...