From 1e883b8732167b201831fd6778ec87d8398b50c0 Mon Sep 17 00:00:00 2001 From: liu Date: Mon, 15 Apr 2024 16:50:25 +0800 Subject: [PATCH] =?UTF-8?q?KBQA=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../supervision/controller/AskController.java | 11 +- .../dto/roundAsk/SessionParamDTO.java | 5 + .../com/supervision/enums/RetireRoleEnum.java | 39 +++++ .../handler/gpt/AnswerQuestionHandler.java | 20 ++- .../com/supervision/service/AskService.java | 9 +- .../service/impl/AskServiceImpl.java | 143 +++++++++++------- .../java/com/supervision/vo/RoleSetReqVO.java | 20 +++ .../java/com/supervision/vo/RoleSetResVO.java | 16 ++ .../com/supervision/vo/UserParamReqVO.java | 15 -- 9 files changed, 196 insertions(+), 82 deletions(-) create mode 100644 kbqa-graph/src/main/java/com/supervision/enums/RetireRoleEnum.java create mode 100644 kbqa-graph/src/main/java/com/supervision/vo/RoleSetReqVO.java create mode 100644 kbqa-graph/src/main/java/com/supervision/vo/RoleSetResVO.java delete mode 100644 kbqa-graph/src/main/java/com/supervision/vo/UserParamReqVO.java diff --git a/kbqa-graph/src/main/java/com/supervision/controller/AskController.java b/kbqa-graph/src/main/java/com/supervision/controller/AskController.java index 2c2e76c..0fa45fd 100644 --- a/kbqa-graph/src/main/java/com/supervision/controller/AskController.java +++ b/kbqa-graph/src/main/java/com/supervision/controller/AskController.java @@ -3,9 +3,10 @@ package com.supervision.controller; import cn.hutool.core.util.StrUtil; import com.supervision.exception.BusinessException; import com.supervision.service.AskService; +import com.supervision.vo.RoleSetResVO; import com.supervision.vo.RoundTalkReqVO; import com.supervision.vo.RoundTalkResVO; -import com.supervision.vo.UserParamReqVO; +import com.supervision.vo.RoleSetReqVO; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -30,15 +31,15 @@ public class AskController { return askService.roundTalk(roundTalkReqVO); } - @ApiOperation("多轮对话中用户手动填写参数") + @ApiOperation("多轮对话中用户手动填写参数,可能直接返回结果") @PostMapping("saveUserParam") - public void saveUserParam(@RequestBody UserParamReqVO paramReqVO) { - askService.saveUserParam(paramReqVO); + public RoundTalkResVO saveUserParam(@RequestBody RoleSetReqVO paramReqVO) { + return askService.saveUserParam(paramReqVO); } @ApiOperation("查询多轮对话中用户需要填写的参数") @GetMapping("queryUserNeedParam") - public Set queryUserNeedParam(String sessionId) { + public RoleSetResVO queryUserNeedParam(String sessionId) { return askService.queryUserNeedParam(sessionId); } } diff --git a/kbqa-graph/src/main/java/com/supervision/dto/roundAsk/SessionParamDTO.java b/kbqa-graph/src/main/java/com/supervision/dto/roundAsk/SessionParamDTO.java index adbbc8b..c4650c5 100644 --- a/kbqa-graph/src/main/java/com/supervision/dto/roundAsk/SessionParamDTO.java +++ b/kbqa-graph/src/main/java/com/supervision/dto/roundAsk/SessionParamDTO.java @@ -63,5 +63,10 @@ public class SessionParamDTO { */ private EntityQuestionDTO currentEntity; + /** + * 多轮对话中的历史记录,key是服务端主动问的问题,value是用户的回答 + */ + private Map talkRecord; + } diff --git a/kbqa-graph/src/main/java/com/supervision/enums/RetireRoleEnum.java b/kbqa-graph/src/main/java/com/supervision/enums/RetireRoleEnum.java new file mode 100644 index 0000000..324583e --- /dev/null +++ b/kbqa-graph/src/main/java/com/supervision/enums/RetireRoleEnum.java @@ -0,0 +1,39 @@ +package com.supervision.enums; + +public enum RetireRoleEnum { + + sex("sex", "性别", null), + job("job", "职业", null), + age("age", "年龄", EntityQuestionEnum.年龄), + residentLocation("residentLocation", "户口所在地", EntityQuestionEnum.户口所在地), + offsiteSocialSecurityInfo("offsiteSocialSecurityInfo", "异地社保转入情况", null), + lastInsuredPlace("lastInsuredPlace", "最后参保地", null), + pensionPaymentPeriod("pensionPaymentPeriod", "养老缴费年限", EntityQuestionEnum.缴费年限); + + private final String code; + + private final String name; + + /** + * 关联的实体类型 + */ + private final EntityQuestionEnum entityEnum; + + RetireRoleEnum(String code, String name, EntityQuestionEnum entityEnum) { + this.code = code; + this.name = name; + this.entityEnum = entityEnum; + } + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + public EntityQuestionEnum getEntityEnum() { + return entityEnum; + } +} diff --git a/kbqa-graph/src/main/java/com/supervision/handler/gpt/AnswerQuestionHandler.java b/kbqa-graph/src/main/java/com/supervision/handler/gpt/AnswerQuestionHandler.java index 36664c0..4a13dff 100644 --- a/kbqa-graph/src/main/java/com/supervision/handler/gpt/AnswerQuestionHandler.java +++ b/kbqa-graph/src/main/java/com/supervision/handler/gpt/AnswerQuestionHandler.java @@ -10,24 +10,32 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +import java.util.Map; @Slf4j @Component public class AnswerQuestionHandler { - public String answerQuestion(String question, List detailList) { + public String answerQuestion(String question, List detailList, Map talkRecord) { List messageList = new ArrayList<>(); messageList.add(new MessageDTO("system", "现在你是一个政务事项领域的问答大模型.\n" + - "我现在给一些政务文件的内容,再给你一个问题,请根据给你的文件内容,针对性的对问题进行解答.\n" + - "请严格按照文件内容进行回答,不要有文件内容之外的理解.\n" + - "除了解答的内容,什么其他的都不要说.\n" + - "如果你从文件内容中,没有提取到回答,你就回复:我暂时还不会这个问题哦!")); + "现在有一个问题,根据这个问题我查到了政策内容,并提供了用户问询过程中的对话记录,可供参考;\n" + + "请你根据政策内容回答这个问题,请不要有文件内容之外的内容或加入你自己的话")); messageList.add(new MessageDTO("assistant", "好的")); messageList.add(new MessageDTO("user", StrUtil.format("政务文件内容:[{}]", CollUtil.join(detailList, ";")))); messageList.add(new MessageDTO("assistant", "继续")); messageList.add(new MessageDTO("user", StrUtil.format("问题:{}", question))); messageList.add(new MessageDTO("assistant", "继续")); - messageList.add(new MessageDTO("user", StrUtil.format("现在你可以回答了"))); + if (CollUtil.isNotEmpty(talkRecord)) { + List record = new ArrayList<>(); + for (Map.Entry entry : talkRecord.entrySet()) { + record.add("询问用户:" + entry.getKey()); + record.add("用户回答:" + entry.getValue()); + } + messageList.add(new MessageDTO("user", "下面是用户回答过程中的对话记录,可供参考,并提供更精确的回答:{" + CollUtil.join(record, ";") + "}")); + messageList.add(new MessageDTO("assistant", "继续")); + } + messageList.add(new MessageDTO("user", StrUtil.format("现在你可以回答了,如果你从文件内容中,没有提取到回答,你就回复:我暂时还不会这个问题哦!"))); log.info("answerQuestion的prompt是:{}", JSONUtil.toJsonStr(messageList)); String answer = AiUtil.chatByMessage(messageList); log.info("answerQuestion的答案是:{}", answer); diff --git a/kbqa-graph/src/main/java/com/supervision/service/AskService.java b/kbqa-graph/src/main/java/com/supervision/service/AskService.java index d1bd026..a06b3c4 100644 --- a/kbqa-graph/src/main/java/com/supervision/service/AskService.java +++ b/kbqa-graph/src/main/java/com/supervision/service/AskService.java @@ -1,18 +1,17 @@ package com.supervision.service; +import com.supervision.vo.RoleSetResVO; import com.supervision.vo.RoundTalkReqVO; import com.supervision.vo.RoundTalkResVO; -import com.supervision.vo.UserParamReqVO; -import org.springframework.web.bind.annotation.RequestBody; +import com.supervision.vo.RoleSetReqVO; -import java.util.List; import java.util.Set; public interface AskService { RoundTalkResVO roundTalk(RoundTalkReqVO roundTalkReqVO); - void saveUserParam(UserParamReqVO paramReqVO); + RoundTalkResVO saveUserParam(RoleSetReqVO paramReqVO); - Set queryUserNeedParam(String sessionId); + RoleSetResVO queryUserNeedParam(String sessionId); } diff --git a/kbqa-graph/src/main/java/com/supervision/service/impl/AskServiceImpl.java b/kbqa-graph/src/main/java/com/supervision/service/impl/AskServiceImpl.java index 07f0c92..91fa288 100644 --- a/kbqa-graph/src/main/java/com/supervision/service/impl/AskServiceImpl.java +++ b/kbqa-graph/src/main/java/com/supervision/service/impl/AskServiceImpl.java @@ -5,10 +5,10 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.supervision.dto.roundAsk.EntityQuestionDTO; -import com.supervision.dto.roundAsk.ItemNodeDTO; import com.supervision.dto.roundAsk.SessionParamDTO; import com.supervision.enums.EntityQuestionEnum; import com.supervision.enums.IdentifyIntentEnum; +import com.supervision.enums.RetireRoleEnum; import com.supervision.exception.BusinessException; import com.supervision.handler.gpt.AnswerQuestionHandler; import com.supervision.handler.gpt.ConditionJudgeHandler; @@ -20,14 +20,14 @@ import com.supervision.handler.graph.FindItemNodeHandler; import com.supervision.ngbatis.domain.tag.Condition; import com.supervision.ngbatis.domain.tag.ItemLeaf; import com.supervision.service.AskService; +import com.supervision.vo.RoleSetResVO; import com.supervision.vo.RoundTalkReqVO; import com.supervision.vo.RoundTalkResVO; -import com.supervision.vo.UserParamReqVO; +import com.supervision.vo.RoleSetReqVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.RequestBody; import java.util.*; import java.util.function.Function; @@ -59,7 +59,7 @@ public class AskServiceImpl implements AskService { private static final String SESSION_PARAM = "KBQA:ASK:SESSION_PARAM:"; - private static final String USER_PARAM = "KBQA:ASK:USER_PARAM:"; + private static final String USER_PARAM = "KBQA:ASK:USER_ROLE:"; /** @@ -79,6 +79,7 @@ public class AskServiceImpl implements AskService { sessionParamDTO.setOriginalQuestion(roundTalkReqVO.getUserTalk()); sessionParamDTO.setSessionId(sessionId); sessionParamDTO.setAlreadyMatchEntitySet(new HashSet<>()); + sessionParamDTO.setTalkRecord(new HashMap<>()); redisTemplate.opsForValue().set(SESSION_PARAM + sessionId, sessionParamDTO); } else { sessionParamDTO = BeanUtil.toBean(cache, SessionParamDTO.class); @@ -92,9 +93,9 @@ public class AskServiceImpl implements AskService { // 识别出来意图之后,再去判断是否识别过实体 if (CollUtil.isEmpty(sessionParamDTO.getEntityValueByExtract())) { // 识别实体(先从图中获取所有的节点名称,然后识别) - List allItemNode = findItemNodeHandler.findAllItemNode(); + // List allItemNode = findItemNodeHandler.findAllItemNode(); //List extractValue = itemExtractHandler.itemExtractByPossibleItem(sessionParamDTO.getOriginalQuestion(), allItemNode); - // 换了另外一种匹配方式 + // 识别问题中,用户可能问的业务是什么 String extractValue = itemExtractHandler.itemExtractBusiness(sessionParamDTO.getOriginalQuestion()); sessionParamDTO.setEntityValueByExtract(Collections.singletonList(extractValue)); // 根据提取的内容,开始在知识图谱中寻找节点(首先找叶子节点,如果叶子节点有数据,直接返回,如果叶子节点没数据,再去找分支节点) @@ -147,33 +148,8 @@ public class AskServiceImpl implements AskService { // 判断待匹配的节点是不是只有一个了,如果有多个,就从路径中选择一个问题问前端 if (sessionParamDTO.getWaitMatchItemLeafMap().size() != 1) { if (ObjectUtil.isNotEmpty(sessionParamDTO.getCurrentEntity())) { - // 如果当前对话实体不为空,说明当前问答就是上一个问题的回复,这个时候,就去GPT中进行匹配 - // 遍历所有的path,找到回答 - Map>> conditionPathMap = sessionParamDTO.getConditionPathMap(); - Set possibleAnswerSet = new HashSet<>(); - for (Map.Entry>> entry : conditionPathMap.entrySet()) { - List> conditionPath = entry.getValue(); - // 遍历所有的路径,找到回答 - for (List conditions : conditionPath) { - // 遍历所有的条件,找到回答 - for (Condition condition : conditions) { - // 如果当前对话实体和条件中的实体类型相同,就添加到possibleAnswerSet中 - if (sessionParamDTO.getCurrentEntity().getCurrentEntityType().equals(condition.getEntityType())) { - possibleAnswerSet.add(condition.getCondition()); - } - } - } - } - Set judgeResultSet = conditionJudgeHandler.newConditionJudge(sessionParamDTO.getCurrentEntity().getCurrentQuestion(), - possibleAnswerSet, - roundTalkReqVO.getUserTalk(), - sessionParamDTO.getCurrentEntity().getCurrentEntityType()); - // 筛选路径,如果某个路径的结果不在比较结果中,说明这个结果不对,排除这个路径 - pathFilterByJudgeResult(sessionParamDTO.getCurrentEntity().getCurrentEntityType(), judgeResultSet, sessionParamDTO); - filterNotMatchNode(sessionParamDTO); - // 加到已匹配的实体类型,下次不再匹配 - sessionParamDTO.getAlreadyMatchEntitySet().add(sessionParamDTO.getCurrentEntity().getCurrentEntityType()); - redisTemplate.opsForValue().set(SESSION_PARAM + sessionId, sessionParamDTO); + // 如果当前对话实体不为空,说明当前问答就是上一个问题的回复,这个时候,就去GPT中进行匹配并排除路径 + filterPath(sessionParamDTO, roundTalkReqVO.getUserTalk()); // 如果排除后只剩一个了,这时跳出多轮问答 if (sessionParamDTO.getWaitMatchItemLeafMap().size() == 1) { sessionParamDTO.setMatchItemLeaf(sessionParamDTO.getWaitMatchItemLeafMap().values().iterator().next()); @@ -202,6 +178,13 @@ public class AskServiceImpl implements AskService { } // 走到这里,说明就只有一个节点了,那么就可以进行下一步了 log.info("走到这里,说明找到了匹配的节点,开始根据用户的意图生成"); + return afterMatchReturnAnswer(sessionParamDTO); + } + + /** + * 匹配完成之后,返回结果 + */ + private RoundTalkResVO afterMatchReturnAnswer(SessionParamDTO sessionParamDTO) { String intent = sessionParamDTO.getIntent(); ItemLeaf matchItemLeaf = sessionParamDTO.getMatchItemLeaf(); // 根据用户的意图找到对应的节点 @@ -212,14 +195,51 @@ public class AskServiceImpl implements AskService { // 根据意图和节点,找到对应的结果 List itemDetail = findItemDetailHandler.findItemDetail(matchItemLeaf.getVid(), intentEnum.getTagType(), intentEnum.getEdgeType()); if (CollUtil.isEmpty(itemDetail)) { - return RoundTalkResVO.builder().sessionId(sessionId).replyQuestion("暂不支持该意图的问答").build(); + return RoundTalkResVO.builder().sessionId(sessionParamDTO.getSessionId()).replyQuestion("暂不支持该意图的问答").build(); } // 提交GPT,问问题的答案 - String answer = answerQuestionHandler.answerQuestion(sessionParamDTO.getOriginalQuestion(), itemDetail); + String answer = answerQuestionHandler.answerQuestion(sessionParamDTO.getOriginalQuestion(), itemDetail, sessionParamDTO.getTalkRecord()); if (StrUtil.isBlank(answer)) { - return RoundTalkResVO.builder().sessionId(sessionId).replyQuestion("暂时还不会回答这个问题哦").build(); + return RoundTalkResVO.builder().sessionId(sessionParamDTO.getSessionId()).replyQuestion("暂时还不会回答这个问题哦").build(); } - return RoundTalkResVO.builder().sessionId(sessionId).replyQuestion(answer).build(); + return RoundTalkResVO.builder().sessionId(sessionParamDTO.getSessionId()).replyQuestion(answer).build(); + } + + private void filterPath(SessionParamDTO sessionParamDTO, String userTalk) { + // 遍历所有的path,找到回答 + Set possibleAnswerSet = findPossibleAnswerSet(sessionParamDTO); + Set judgeResultSet = conditionJudgeHandler.newConditionJudge(sessionParamDTO.getCurrentEntity().getCurrentQuestion(), + possibleAnswerSet, + userTalk, + sessionParamDTO.getCurrentEntity().getCurrentEntityType()); + // 筛选路径,如果某个路径的结果不在比较结果中,说明这个结果不对,排除这个路径 + pathFilterByJudgeResult(sessionParamDTO.getCurrentEntity().getCurrentEntityType(), judgeResultSet, sessionParamDTO); + filterNotMatchNode(sessionParamDTO); + // 加到已匹配的实体类型,下次不再匹配 + sessionParamDTO.getAlreadyMatchEntitySet().add(sessionParamDTO.getCurrentEntity().getCurrentEntityType()); + // 保存用户的对话记录 + sessionParamDTO.getTalkRecord().put(sessionParamDTO.getCurrentEntity().getCurrentEntityType(), userTalk); + // 缓存到Redis中 + redisTemplate.opsForValue().set(SESSION_PARAM + sessionParamDTO.getSessionId(), sessionParamDTO); + } + + private Set findPossibleAnswerSet(SessionParamDTO sessionParamDTO) { + Map>> conditionPathMap = sessionParamDTO.getConditionPathMap(); + Set possibleAnswerSet = new HashSet<>(); + for (Map.Entry>> entry : conditionPathMap.entrySet()) { + List> conditionPath = entry.getValue(); + // 遍历所有的路径,找到回答 + for (List conditions : conditionPath) { + // 遍历所有的条件,找到回答 + for (Condition condition : conditions) { + // 如果当前对话实体和条件中的实体类型相同,就添加到possibleAnswerSet中 + if (sessionParamDTO.getCurrentEntity().getCurrentEntityType().equals(condition.getEntityType())) { + possibleAnswerSet.add(condition.getCondition()); + } + } + } + } + return possibleAnswerSet; } private Map countCondition(SessionParamDTO sessionParamDTO) { @@ -260,12 +280,10 @@ public class AskServiceImpl implements AskService { break; } } - if (shouldRemove) { toRemove.add(conditions); } } - // 移除所有需要移除的路径 conditionPath.removeAll(toRemove); } @@ -296,22 +314,45 @@ public class AskServiceImpl implements AskService { } @Override - public void saveUserParam(UserParamReqVO paramReqVO) { + public RoundTalkResVO saveUserParam(RoleSetReqVO paramReqVO) { // 缓存到Redis中 - if (CollUtil.isNotEmpty(paramReqVO.getParamList()) && StrUtil.isNotBlank(paramReqVO.getSessionId())) { - redisTemplate.opsForValue().set(USER_PARAM + paramReqVO.getSessionId(), paramReqVO.getParamList()); + if (CollUtil.isNotEmpty(paramReqVO.getParamMap()) && StrUtil.isNotBlank(paramReqVO.getSessionId())) { + redisTemplate.opsForValue().set(USER_PARAM + paramReqVO.getSessionId(), paramReqVO.getParamMap()); + // 这里获取session进行筛选,将不匹配的路径移除掉 + Object cache = redisTemplate.opsForValue().get(SESSION_PARAM + paramReqVO.getSessionId()); + Optional.ofNullable(cache).orElseThrow(() -> new BusinessException("未找到的会话ID")); + SessionParamDTO sessionParamDTO = BeanUtil.toBean(cache, SessionParamDTO.class); + for (Map.Entry entry : paramReqVO.getParamMap().entrySet()) { + String key = entry.getKey(); + // 去枚举里面去找 + RetireRoleEnum roleEnum = Arrays.stream(RetireRoleEnum.values()).filter(e -> e.getCode().equals(key)).findFirst().orElseThrow(() -> new BusinessException("未找到的参数")); + // 如果匹配的实体不为空,就去校验是否存在该实体一致的判断对象 + if (null != roleEnum.getEntityEnum()) { + Map entityCountMap = sessionParamDTO.getEntityCountMap(); + // 如果包含,就去尝试排除路径 + if (entityCountMap.containsKey(roleEnum.getEntityEnum().getEntityType())) { + filterPath(sessionParamDTO, entry.getValue()); + } + } + } + // 在这里,判断是不是只生一个匹配的了,如果只剩一个匹配的了,就直接回复了,不需要再问了 + // 如果排除后只剩一个了,这时跳出多轮问答 + if (sessionParamDTO.getWaitMatchItemLeafMap().size() == 1) { + sessionParamDTO.setMatchItemLeaf(sessionParamDTO.getWaitMatchItemLeafMap().values().iterator().next()); + redisTemplate.opsForValue().set(SESSION_PARAM + paramReqVO.getSessionId(), sessionParamDTO); + return afterMatchReturnAnswer(sessionParamDTO); + } } - + return null; } @Override - public Set queryUserNeedParam(String sessionId) { - // 首先根据session获取需要判断的条件 - Object sessionCache = redisTemplate.opsForValue().get(SESSION_PARAM + sessionId); - SessionParamDTO sessionParamDTO = BeanUtil.toBean(sessionCache, SessionParamDTO.class); - // 然后获取里面的数据 - return sessionParamDTO.getEntityCountMap().keySet(); - - + public RoleSetResVO queryUserNeedParam(String sessionId) { + // 暂时是写死的退休的事项列表,后面再调整优化根据事项修改逻辑 + List itemList = Arrays.stream(RetireRoleEnum.values()).map(RetireRoleEnum::getCode).collect(Collectors.toList()); + RoleSetResVO roleSetResVO = new RoleSetResVO(); + roleSetResVO.setSessionId(sessionId); + roleSetResVO.setParam(itemList); + return roleSetResVO; } } diff --git a/kbqa-graph/src/main/java/com/supervision/vo/RoleSetReqVO.java b/kbqa-graph/src/main/java/com/supervision/vo/RoleSetReqVO.java new file mode 100644 index 0000000..1e6cbe3 --- /dev/null +++ b/kbqa-graph/src/main/java/com/supervision/vo/RoleSetReqVO.java @@ -0,0 +1,20 @@ +package com.supervision.vo; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class RoleSetReqVO { + + + private String sessionId; + + /** + * 用户填写的内容,key是该项code,value是用户填写的内容 + */ + private Map paramMap; + + +} diff --git a/kbqa-graph/src/main/java/com/supervision/vo/RoleSetResVO.java b/kbqa-graph/src/main/java/com/supervision/vo/RoleSetResVO.java new file mode 100644 index 0000000..65c316b --- /dev/null +++ b/kbqa-graph/src/main/java/com/supervision/vo/RoleSetResVO.java @@ -0,0 +1,16 @@ +package com.supervision.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class RoleSetResVO { + + + private String sessionId; + + private List param; + + +} diff --git a/kbqa-graph/src/main/java/com/supervision/vo/UserParamReqVO.java b/kbqa-graph/src/main/java/com/supervision/vo/UserParamReqVO.java deleted file mode 100644 index 17e78f5..0000000 --- a/kbqa-graph/src/main/java/com/supervision/vo/UserParamReqVO.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.supervision.vo; - -import com.supervision.dto.roundAsk.UserParamNode; -import lombok.Data; - -import java.util.List; - -@Data -public class UserParamReqVO { - - private String sessionId; - - List paramList; - -}