Commit a3e3d13989a505e3f50c1f87e48c99130946e2cb
1 parent
6886121d
AI添加问题 历史问题记录
Showing
5 changed files
with
246 additions
and
183 deletions
src/main/java/com/xly/agent/ErpAiAgent.java
| @@ -14,14 +14,23 @@ public interface ErpAiAgent { | @@ -14,14 +14,23 @@ public interface ErpAiAgent { | ||
| 14 | 1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下; | 14 | 1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下; |
| 15 | 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容; | 15 | 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容; |
| 16 | 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容; | 16 | 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容; |
| 17 | - 1.3 调用工具前,不需要询问用户提供缺失的参数 | ||
| 18 | 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下: | 17 | 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下: |
| 19 | 2.1 数字无引号,为空时禁止赋值0; | 18 | 2.1 数字无引号,为空时禁止赋值0; |
| 20 | 2.2 如果有空格需要去掉空格后再提取。 | 19 | 2.2 如果有空格需要去掉空格后再提取。 |
| 20 | + 2.3 每次都需要进行参数提取 | ||
| 21 | """) | 21 | """) |
| 22 | @UserMessage("用户输入:{{userInput}}") | 22 | @UserMessage("用户输入:{{userInput}}") |
| 23 | String chat(@MemoryId String userId, @V("userInput") String userInput); | 23 | String chat(@MemoryId String userId, @V("userInput") String userInput); |
| 24 | 24 | ||
| 25 | + @SystemMessage("{{stoolDesc}}") | ||
| 26 | + @UserMessage("用户输入:{{userInput}}") | ||
| 27 | + String chatCurrentTool(@MemoryId String userId, | ||
| 28 | + @V("userInput") String userInput, | ||
| 29 | + @V("sMethodNo") String sMethodNo, | ||
| 30 | + @V("sMethodName") String sMethodName, | ||
| 31 | + @V("stoolDesc") String stoolDesc | ||
| 32 | + ); | ||
| 33 | + | ||
| 25 | /** | 34 | /** |
| 26 | * 动态表结构:自然语言解释SQL执行结果 | 35 | * 动态表结构:自然语言解释SQL执行结果 |
| 27 | * 入参:用户问题、执行的SQL、表结构、JSON格式结果 | 36 | * 入参:用户问题、执行的SQL、表结构、JSON格式结果 |
src/main/java/com/xly/entity/UserSceneSession.java
| @@ -63,6 +63,9 @@ public class UserSceneSession { | @@ -63,6 +63,9 @@ public class UserSceneSession { | ||
| 63 | private String sFunPrompts; //方法返回的参数补全提示 | 63 | private String sFunPrompts; //方法返回的参数补全提示 |
| 64 | 64 | ||
| 65 | private Boolean bCleanMemory = false; | 65 | private Boolean bCleanMemory = false; |
| 66 | + | ||
| 67 | + private Map<String, Object> args; | ||
| 68 | + | ||
| 66 | /** | 69 | /** |
| 67 | * 构建场景选择提示语:展示权限内场景,引导用户选择 | 70 | * 构建场景选择提示语:展示权限内场景,引导用户选择 |
| 68 | * @return 自然语言提示语 | 71 | * @return 自然语言提示语 |
src/main/java/com/xly/service/XlyErpService.java
| @@ -83,11 +83,12 @@ public class XlyErpService { | @@ -83,11 +83,12 @@ public class XlyErpService { | ||
| 83 | String authorization) { | 83 | String authorization) { |
| 84 | String sceneName = StrUtil.EMPTY; | 84 | String sceneName = StrUtil.EMPTY; |
| 85 | String methodName = StrUtil.EMPTY; | 85 | String methodName = StrUtil.EMPTY; |
| 86 | + UserSceneSession session=null; | ||
| 86 | try { | 87 | try { |
| 87 | // 0. 预处理用户输入:去空格、转小写(方便匹配) | 88 | // 0. 预处理用户输入:去空格、转小写(方便匹配) |
| 88 | String input= InputPreprocessor.preprocessWithCommons(userInput); | 89 | String input= InputPreprocessor.preprocessWithCommons(userInput); |
| 89 | // 1. 初始化用户场景会话(权限内场景) | 90 | // 1. 初始化用户场景会话(权限内场景) |
| 90 | - UserSceneSession session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); | 91 | + session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); |
| 91 | session.setAuthorization(authorization); | 92 | session.setAuthorization(authorization); |
| 92 | session.setSFunPrompts(null); | 93 | session.setSFunPrompts(null); |
| 93 | sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY; | 94 | sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY; |
| @@ -102,9 +103,8 @@ public class XlyErpService { | @@ -102,9 +103,8 @@ public class XlyErpService { | ||
| 102 | if (session.getCurrentScene() != null | 103 | if (session.getCurrentScene() != null |
| 103 | && Objects.equals(session.getCurrentScene().getSSceneNo(), "ChatZone")) | 104 | && Objects.equals(session.getCurrentScene().getSSceneNo(), "ChatZone")) |
| 104 | { | 105 | { |
| 105 | - return getChatiAgent(input, session,StrUtil.EMPTY); | 106 | + return getChatiAgent(input, session); |
| 106 | } | 107 | } |
| 107 | - | ||
| 108 | // 3. 未选场景:先展示场景选择界面,处理用户序号选择 | 108 | // 3. 未选场景:先展示场景选择界面,处理用户序号选择 |
| 109 | if (!session.isSceneSelected() && ValiDataUtil.me().isPureNumber(input)){ | 109 | if (!session.isSceneSelected() && ValiDataUtil.me().isPureNumber(input)){ |
| 110 | // 3.1 尝试处理场景选择(输入序号则匹配,否则展示选择提示) | 110 | // 3.1 尝试处理场景选择(输入序号则匹配,否则展示选择提示) |
| @@ -114,49 +114,44 @@ public class XlyErpService { | @@ -114,49 +114,44 @@ public class XlyErpService { | ||
| 114 | ErpAiAgent aiAgent = createErpAiAgent(userId, input, session); | 114 | ErpAiAgent aiAgent = createErpAiAgent(userId, input, session); |
| 115 | // 没有选择到场景,进闲聊模式 | 115 | // 没有选择到场景,进闲聊模式 |
| 116 | if (aiAgent == null){ | 116 | if (aiAgent == null){ |
| 117 | - return getChatiAgent (input, session,StrUtil.EMPTY); | 117 | + return getChatiAgent (input,session); |
| 118 | } | 118 | } |
| 119 | -// List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | ||
| 120 | - String sResponMessage = aiAgent.chat(userId, input); | ||
| 121 | -// List<ChatMessage> chatMessage2 = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | ||
| 122 | - String sResponMessageOld = StrUtil.EMPTY; | ||
| 123 | -// 调用方法,参数缺失部分提示,就直接使用方法返回的 | ||
| 124 | - if(session.getCurrentTool() != null | ||
| 125 | - && session.getSFunPrompts()!=null | 119 | + //用户输入添加方法 |
| 120 | + String sResponMessage = StrUtil.EMPTY; | ||
| 121 | + if(ObjectUtil.isNotEmpty(session.getCurrentTool()) | ||
| 122 | + && !ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) | ||
| 126 | ){ | 123 | ){ |
| 127 | - // 缺失的参数明细 | ||
| 128 | - sResponMessage = session.getSFunPrompts(); | ||
| 129 | - } | ||
| 130 | - if (session.getCurrentTool()== null){ | ||
| 131 | - sResponMessageOld = sResponMessage; | ||
| 132 | - sResponMessage = StrUtil.EMPTY; | ||
| 133 | - } | ||
| 134 | - //5.执行工具方法后,清除记忆 | ||
| 135 | - if(session.getBCleanMemory()){ | ||
| 136 | - doCleanUserMemory(session,userId); | 124 | + input = session.getCurrentTool().getSMethodName()+","+input; |
| 125 | + sResponMessage = aiAgent.chatCurrentTool(userId, input,session.getCurrentTool().getSMethodNo(),session.getCurrentTool().getSMethodName(),session.getCurrentTool().getStoolDesc()); | ||
| 126 | + }else{ | ||
| 127 | + sResponMessage = aiAgent.chat(userId, input); | ||
| 137 | } | 128 | } |
| 138 | -// 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 | 129 | + |
| 130 | +// 1.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 | ||
| 139 | if((ObjectUtil.isNotEmpty(session.getCurrentTool()) | 131 | if((ObjectUtil.isNotEmpty(session.getCurrentTool()) |
| 140 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) | 132 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) |
| 141 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) | 133 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) |
| 142 | ){ | 134 | ){ |
| 143 | sResponMessage = getDynamicTableSql(session, input, userId, userInput,0,StrUtil.EMPTY,StrUtil.EMPTY,"0",StrUtil.EMPTY, aiAgent); | 135 | sResponMessage = getDynamicTableSql(session, input, userId, userInput,0,StrUtil.EMPTY,StrUtil.EMPTY,"0",StrUtil.EMPTY, aiAgent); |
| 144 | - } | ||
| 145 | - //如果返回空的进入闲聊模式 | ||
| 146 | - if (ObjectUtil.isEmpty(sResponMessage)){ | ||
| 147 | - return getChatiAgent (input, session,sResponMessageOld); | ||
| 148 | - } | ||
| 149 | - if (session.getCurrentScene()!= null ){ | ||
| 150 | - return AiResponseDTO.builder().aiText(sResponMessage) | ||
| 151 | - .sSceneName(session.getCurrentScene().getSSceneName()) | ||
| 152 | - .sMethodName((ObjectUtil.isEmpty(session.getCurrentTool()))?StrUtil.EMPTY:session.getCurrentTool().getSMethodName()) | ||
| 153 | - .sReturnType(ReturnTypeCode.MAKEDOWN.getCode()) | ||
| 154 | - .build(); | ||
| 155 | - }else { | 136 | + return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); |
| 137 | + } else if (ObjectUtil.isNotEmpty(session.getCurrentTool())) { | ||
| 138 | + //2.处理工具参数采集结束后业务逻辑处理 | ||
| 139 | + //调用方法,参数缺失部分提示,就直接使用方法返回的 | ||
| 140 | + sResponMessage = dynamicToolProvider.doDynamicTool(session.getCurrentTool(),session); | ||
| 141 | + return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); | ||
| 142 | + }else if(session.getCurrentScene()== null ){ | ||
| 156 | return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText("当前场景:没有选择 退回当前场景 请输入 "+ CommonConstant.RESET + sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); | 143 | return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText("当前场景:没有选择 退回当前场景 请输入 "+ CommonConstant.RESET + sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); |
| 144 | + }else{ | ||
| 145 | + return getChatiAgent (input, session); | ||
| 157 | } | 146 | } |
| 158 | } catch (Exception e) { | 147 | } catch (Exception e) { |
| 148 | + e.printStackTrace(); | ||
| 159 | return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText("系统异常:" + e.getMessage() + ",请稍后重试!").sReturnType(ReturnTypeCode.HTML.getCode()).build(); | 149 | return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText("系统异常:" + e.getMessage() + ",请稍后重试!").sReturnType(ReturnTypeCode.HTML.getCode()).build(); |
| 150 | + }finally { | ||
| 151 | + //5.执行工具方法后,清除记忆 | ||
| 152 | + if(session !=null && session.getBCleanMemory()){ | ||
| 153 | + doCleanUserMemory(session,userId); | ||
| 154 | + } | ||
| 160 | } | 155 | } |
| 161 | } | 156 | } |
| 162 | 157 | ||
| @@ -170,6 +165,7 @@ public class XlyErpService { | @@ -170,6 +165,7 @@ public class XlyErpService { | ||
| 170 | UserSceneSession session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); | 165 | UserSceneSession session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); |
| 171 | operableChatMemoryProvider.clearSpecifiedMemory(userId); | 166 | operableChatMemoryProvider.clearSpecifiedMemory(userId); |
| 172 | session.setCurrentTool(null); | 167 | session.setCurrentTool(null); |
| 168 | + session.setArgs(null); | ||
| 173 | session.setSUserQuestionList(new ArrayList<>()); | 169 | session.setSUserQuestionList(new ArrayList<>()); |
| 174 | UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); | 170 | UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); |
| 175 | UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); | 171 | UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); |
| @@ -246,6 +242,7 @@ public class XlyErpService { | @@ -246,6 +242,7 @@ public class XlyErpService { | ||
| 246 | operableChatMemoryProvider.clearSpecifiedMemory(userId); | 242 | operableChatMemoryProvider.clearSpecifiedMemory(userId); |
| 247 | session.setCurrentTool(null); | 243 | session.setCurrentTool(null); |
| 248 | session.setSUserQuestionList(new ArrayList<>()); | 244 | session.setSUserQuestionList(new ArrayList<>()); |
| 245 | + session.setArgs(new HashMap<>()); | ||
| 249 | // session.setSceneSelected(false); | 246 | // session.setSceneSelected(false); |
| 250 | UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); | 247 | UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); |
| 251 | UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); | 248 | UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); |
| @@ -593,12 +590,9 @@ public class XlyErpService { | @@ -593,12 +590,9 @@ public class XlyErpService { | ||
| 593 | * @return java.lang.String | 590 | * @return java.lang.String |
| 594 | * @Description 获取智普通智能体 | 591 | * @Description 获取智普通智能体 |
| 595 | **/ | 592 | **/ |
| 596 | - private AiResponseDTO getChatiAgent (String input,UserSceneSession session,String sResponMessageOld){ | 593 | + private AiResponseDTO getChatiAgent (String input,UserSceneSession session){ |
| 597 | String sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY; | 594 | String sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY; |
| 598 | String methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSMethodName():"随便聊聊"; | 595 | String methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSMethodName():"随便聊聊"; |
| 599 | - if(ObjectUtil.isNotEmpty(sResponMessageOld)){ | ||
| 600 | - return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sResponMessageOld).systemText(StrUtil.EMPTY).sReturnType(ReturnTypeCode.HTML.getCode()).build(); | ||
| 601 | - } | ||
| 602 | ChatiAgent chatiAgent = UserSceneSessionService.CHAT_AGENT_CACHE.get(session.getUserId()); | 596 | ChatiAgent chatiAgent = UserSceneSessionService.CHAT_AGENT_CACHE.get(session.getUserId()); |
| 603 | if(ObjectUtil.isEmpty(chatiAgent)){ | 597 | if(ObjectUtil.isEmpty(chatiAgent)){ |
| 604 | chatiAgent = AiServices.builder(ChatiAgent.class) | 598 | chatiAgent = AiServices.builder(ChatiAgent.class) |
src/main/java/com/xly/tool/DynamicToolProvider.java
| 1 | package com.xly.tool; | 1 | package com.xly.tool; |
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | +import cn.hutool.core.util.NumberUtil; | ||
| 4 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 6 | import cn.hutool.json.JSONUtil; | 7 | import cn.hutool.json.JSONUtil; |
| @@ -165,7 +166,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -165,7 +166,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 165 | pr.setSParamValue(sAIshowfieldShowAll.get(i).get("sName").toString()); | 166 | pr.setSParamValue(sAIshowfieldShowAll.get(i).get("sName").toString()); |
| 166 | pr.setSParam(sAIshowfieldShowAll.get(i).get("label").toString()); | 167 | pr.setSParam(sAIshowfieldShowAll.get(i).get("label").toString()); |
| 167 | pr.setBEmpty(false); | 168 | pr.setBEmpty(false); |
| 168 | - pr.setSType("array"); | 169 | + pr.setSType(getDefType(sAIshowfieldShowAll.get(i).get("sName").toString())); |
| 169 | if("sSlaveId".equals(sAIshowfieldShowAll.get(i).get("sName"))){ | 170 | if("sSlaveId".equals(sAIshowfieldShowAll.get(i).get("sName"))){ |
| 170 | pr.setSParam("sSlaveId"); | 171 | pr.setSParam("sSlaveId"); |
| 171 | } | 172 | } |
| @@ -186,35 +187,56 @@ public class DynamicToolProvider implements ToolProvider { | @@ -186,35 +187,56 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 186 | meta.setParamRuleListAll(paramRuleListAll); | 187 | meta.setParamRuleListAll(paramRuleListAll); |
| 187 | } | 188 | } |
| 188 | 189 | ||
| 190 | + private String getDefType(String sColumn){ | ||
| 191 | + if(sColumn.startsWith("d")){ | ||
| 192 | + return "double"; | ||
| 193 | + }else{ | ||
| 194 | + return "string"; | ||
| 195 | + } | ||
| 196 | + } | ||
| 189 | @Override | 197 | @Override |
| 190 | public ToolProviderResult provideTools(ToolProviderRequest request) { | 198 | public ToolProviderResult provideTools(ToolProviderRequest request) { |
| 191 | -// List<ToolSpecification> specs = new ArrayList<>(); | ||
| 192 | String sUserId = request.chatMemoryId().toString(); | 199 | String sUserId = request.chatMemoryId().toString(); |
| 193 | Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | 200 | Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); |
| 194 | - // sceneToolCacheMap.get(sSceneIdMap.get(sUserId)); | ||
| 195 | - //获取Session | 201 | + // 获取Session |
| 196 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); | 202 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); |
| 197 | - //过滤对应的权限方法 | 203 | + |
| 204 | + // 过滤对应的权限方法 | ||
| 198 | List<ToolSpecificationHolder> datalist = new ArrayList<>(); | 205 | List<ToolSpecificationHolder> datalist = new ArrayList<>(); |
| 199 | List<ToolMeta> toolMetaAll = new ArrayList<>(); | 206 | List<ToolMeta> toolMetaAll = new ArrayList<>(); |
| 200 | - if(session.getCurrentTool()!=null){ | 207 | + |
| 208 | + // 确保 currentTool 不为空,或者 authTool 有数据 | ||
| 209 | + if(session.getCurrentTool() != null){ | ||
| 201 | toolMetaAll.add(session.getCurrentTool()); | 210 | toolMetaAll.add(session.getCurrentTool()); |
| 202 | - }else{ | 211 | + log.info("使用 currentTool: {}", session.getCurrentTool().getSMethodNo()); |
| 212 | + } else { | ||
| 203 | toolMetaAll = session.getAuthTool(); | 213 | toolMetaAll = session.getAuthTool(); |
| 214 | + log.info("使用 authTool, 数量: {}", toolMetaAll.size()); | ||
| 204 | } | 215 | } |
| 216 | + | ||
| 205 | if(ObjectUtil.isNotEmpty(toolMetaAll)){ | 217 | if(ObjectUtil.isNotEmpty(toolMetaAll)){ |
| 206 | - toolMetaAll = toolMetaAll.stream().filter(to-> to.getSSceneId().equals(sSceneIdMap.get(sUserId))).collect(Collectors.toUnmodifiableList()); | 218 | + toolMetaAll = toolMetaAll.stream() |
| 219 | + .filter(to -> to.getSSceneId().equals(sSceneIdMap.get(sUserId))) | ||
| 220 | + .collect(Collectors.toUnmodifiableList()); | ||
| 221 | + | ||
| 207 | if(ObjectUtil.isNotEmpty(toolMetaAll)){ | 222 | if(ObjectUtil.isNotEmpty(toolMetaAll)){ |
| 208 | - toolMetaAll.forEach(to->{ | ||
| 209 | - datalist.add(toolCache.get(to.getSMethodNo())); | 223 | + toolMetaAll.forEach(to -> { |
| 224 | + ToolSpecificationHolder holder = toolCache.get(to.getSMethodNo()); | ||
| 225 | + if (holder != null) { | ||
| 226 | + datalist.add(holder); | ||
| 227 | + log.debug("添加工具到提供器: {}", to.getSMethodNo()); | ||
| 228 | + } else { | ||
| 229 | + log.warn("工具缓存缺失: {}", to.getSMethodNo()); | ||
| 230 | + } | ||
| 210 | }); | 231 | }); |
| 211 | } | 232 | } |
| 212 | } | 233 | } |
| 213 | - datalist.forEach(holder->{ | ||
| 214 | -// specs.add(holder.getToolSpecification()); | ||
| 215 | - executors.put(holder.getToolSpecification(),holder.getToolExecutor()); | ||
| 216 | -// executors.put(holder.getToolSpecification(), holder.getToolExecutor()); | 234 | + |
| 235 | + // 将工具添加到返回结果中 | ||
| 236 | + datalist.forEach(holder -> { | ||
| 237 | + executors.put(holder.getToolSpecification(), holder.getToolExecutor()); | ||
| 217 | }); | 238 | }); |
| 239 | + log.info("provideTools 返回工具数量: {}", executors.size()); | ||
| 218 | return ToolProviderResult.builder().addAll(executors).build(); | 240 | return ToolProviderResult.builder().addAll(executors).build(); |
| 219 | } | 241 | } |
| 220 | 242 | ||
| @@ -240,10 +262,10 @@ public class DynamicToolProvider implements ToolProvider { | @@ -240,10 +262,10 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 240 | // stoolDesc.append(",").append("并选择数据后执行["+meta.getSControlName()+"]操作"); | 262 | // stoolDesc.append(",").append("并选择数据后执行["+meta.getSControlName()+"]操作"); |
| 241 | // } | 263 | // } |
| 242 | stoolDesc.append("时,必须调用本工具").append(meta.getSMethodNo()).append(",").append(meta.getStoolDesc()); | 264 | stoolDesc.append("时,必须调用本工具").append(meta.getSMethodNo()).append(",").append(meta.getStoolDesc()); |
| 243 | - if (meta.getIBizType()==4){ | ||
| 244 | - stoolDesc.append(",").append("并选择数据后执行 "+meta.getSControlName()+" 操作"); | ||
| 245 | -// .append("1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"1,3行确认""); | ||
| 246 | - } | 265 | +// if (meta.getIBizType()==4){ |
| 266 | +// stoolDesc.append(",").append("并选择数据后执行 "+meta.getSControlName()+" 操作"); | ||
| 267 | +//// .append("1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"1,3行确认""); | ||
| 268 | +// } | ||
| 247 | } | 269 | } |
| 248 | 270 | ||
| 249 | try { | 271 | try { |
| @@ -504,115 +526,129 @@ public class DynamicToolProvider implements ToolProvider { | @@ -504,115 +526,129 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 504 | } | 526 | } |
| 505 | return paramRuleDataAll; | 527 | return paramRuleDataAll; |
| 506 | } | 528 | } |
| 507 | - | ||
| 508 | - | ||
| 509 | /*** | 529 | /*** |
| 510 | * @Author 钱豹 | 530 | * @Author 钱豹 |
| 511 | - * @Date 15:09 2026/1/30 | 531 | + * @Date 12:37 2026/3/16 |
| 512 | * @Param [meta] | 532 | * @Param [meta] |
| 513 | * @return dev.langchain4j.service.tool.ToolExecutor | 533 | * @return dev.langchain4j.service.tool.ToolExecutor |
| 514 | - * @Description 创建 ToolExecutor,内部包含参数自动补全与校验逻辑(创建执行器) | 534 | + * @Description 参数采集执行器 |
| 515 | **/ | 535 | **/ |
| 516 | private ToolExecutor createToolExecutor(ToolMeta meta) { | 536 | private ToolExecutor createToolExecutor(ToolMeta meta) { |
| 537 | + log.info("创建工具执行器: {}", meta.getSMethodNo()); | ||
| 538 | + | ||
| 517 | return (toolExecutionRequest, memoryId) -> { | 539 | return (toolExecutionRequest, memoryId) -> { |
| 540 | + log.info("===== 工具执行器开始执行 ====="); | ||
| 541 | + log.info("工具编号: {}", meta.getSMethodNo()); | ||
| 542 | + log.info("工具名称: {}", meta.getSMethodName()); | ||
| 543 | + log.info("memoryId: {}", memoryId); | ||
| 544 | + log.info("请求参数: {}", toolExecutionRequest.arguments()); | ||
| 545 | + | ||
| 518 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); | 546 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); |
| 519 | - session.setCurrentTool(meta); // 标记一下找到了相应方法 | ||
| 520 | - session.setSFunPrompts(null); | ||
| 521 | - // 检查条件 - 如果条件满足,直接返回成功结果,不再执行后续逻辑 | ||
| 522 | - if (ObjectUtil.isNotEmpty(meta.getSInputTabelName()) | ||
| 523 | - && ObjectUtil.isNotEmpty(meta.getSStructureMemo())) { | ||
| 524 | - // 直接返回成功结果,阻止后续执行 | ||
| 525 | - return createEarlySuccessResult(toolExecutionRequest, "执行成功,终止后续执行"); | ||
| 526 | - } | 547 | + session.setCurrentTool(meta); // 标记当前工具 |
| 527 | 548 | ||
| 528 | - // 1. 解析模型传入的参数 | ||
| 529 | - Map<String, Object> args; | 549 | + // 1. 解析参数 |
| 550 | + Map<String, Object> argsNew; | ||
| 530 | try { | 551 | try { |
| 531 | - args = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); | 552 | + argsNew = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); |
| 553 | + log.info("解析后的参数: {}", argsNew); | ||
| 532 | } catch (Exception e) { | 554 | } catch (Exception e) { |
| 533 | - String errorMsg = "参数 JSON 解析失败,请检查参数格式是否正确。" | ||
| 534 | - + "错误详情:" + e.getMessage(); | ||
| 535 | - log.warn("参数解析失败,tool={}, args={}", meta.getSMethodNo(), toolExecutionRequest.arguments(), e); | 555 | + log.error("参数解析失败", e); |
| 556 | + String errorMsg = "参数解析失败,请重新输入"; | ||
| 536 | return String.valueOf(errorResult(toolExecutionRequest, errorMsg)); | 557 | return String.valueOf(errorResult(toolExecutionRequest, errorMsg)); |
| 537 | } | 558 | } |
| 538 | -// Map<String, Object> argsOld = DeepCopyUtils.deepCopy(args); | ||
| 539 | - List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | ||
| 540 | - | ||
| 541 | - // 2 【补全动态参数】动态参数补全 | ||
| 542 | - try{ | ||
| 543 | - args = applyValues(args, meta.getParamRuleListCheck()); | ||
| 544 | - }catch (Exception e){ | ||
| 545 | - log.error("返回信息",e); | ||
| 546 | - String sTsMsg = e.getMessage(); | ||
| 547 | - session.setSFunPrompts(sTsMsg); | ||
| 548 | - //存在多个数据返回大模型,需要继续盘问选择出唯一结果 | ||
| 549 | - return String.valueOf(askUserResult(toolExecutionRequest, sTsMsg)); | ||
| 550 | - } | ||
| 551 | - | ||
| 552 | - // 2.1 【自动补全】应用参数的默认值 | ||
| 553 | - args = applyDefaultValues(args, paramRuleData); | ||
| 554 | - | ||
| 555 | - // 3. 【自动校验】检查必填项 | ||
| 556 | - List<String> missing = checkRequiredParams(args, paramRuleData); | ||
| 557 | - if (!missing.isEmpty()) { | ||
| 558 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 559 | - String askMsg = buildAskUserMessage(meta, missing,args); | ||
| 560 | - session.setSFunPrompts(askMsg); | ||
| 561 | - return String.valueOf(askUserResult(toolExecutionRequest, askMsg)); | 559 | + Map<String, Object> args = session.getArgs(); |
| 560 | + if(ObjectUtil.isEmpty(args)){ | ||
| 561 | + args = new HashMap<>(); | ||
| 562 | } | 562 | } |
| 563 | + Map<String, Object> finalArgs = args; | ||
| 564 | + argsNew.forEach((k, v)->{ | ||
| 565 | + //获取对应的英文参数 | ||
| 566 | + List<ParamRule> data = meta.getParamRuleList().stream().filter(one->one.getSParam().equals(k)).collect(Collectors.toUnmodifiableList()); | ||
| 567 | + if(ObjectUtil.isNotEmpty(data) && data.size()>0){ | ||
| 568 | + finalArgs.remove(data.get(0).getSParamValue()); | ||
| 569 | + finalArgs.remove(data.get(0).getSParam()); | ||
| 570 | + } | ||
| 571 | + if(ObjectUtil.isNotEmpty(v)){ | ||
| 572 | + finalArgs.put(k,v); | ||
| 573 | + } | ||
| 574 | + }); | ||
| 575 | + session.setArgs(finalArgs); | ||
| 576 | + // 2. 获取必填参数规则 | ||
| 577 | +// List<ParamRule> sParamRules = meta.getParamRuleListCheck(); | ||
| 578 | +// List<String> missingParams = getRequiredParams(sParamRules); | ||
| 579 | +// String collectPrompt = buildCollectParamsPrompt(meta, missingParams, args); | ||
| 580 | +// log.info("参数缺失,返回收集提示: {}", collectPrompt); | ||
| 581 | + return String.valueOf(successResult(toolExecutionRequest, JSONUtil.toJsonStr(finalArgs))); | ||
| 582 | + }; | ||
| 583 | + } | ||
| 563 | 584 | ||
| 564 | - // 6. 【最终确认信息】所有检测通过后,需要和客户确认交互 | ||
| 565 | - List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(memoryId.toString()); | ||
| 566 | - ChatMessage userMessage = getLasterUserMssage(chatMessage); | ||
| 567 | - String input = StrUtil.replace(userMessage.text(),"用户输入:",StrUtil.EMPTY); | 585 | + public String doDynamicTool(ToolMeta meta,UserSceneSession session) { |
| 586 | + List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | ||
| 587 | + Map<String, Object> args = session.getArgs(); | ||
| 588 | + Map<String, Object> argsOld = new HashMap<>(args); | ||
| 589 | + // 2 【补全动态参数】动态参数补全 | ||
| 590 | + try{ | ||
| 591 | + args = applyValues(args, meta.getParamRuleListCheck()); | ||
| 592 | + }catch (Exception e){ | ||
| 593 | + log.error("返回信息",e); | ||
| 594 | + String sTsMsg = e.getMessage(); | ||
| 595 | + return sTsMsg; | ||
| 596 | + } | ||
| 597 | + // 2.1 【自动补全】应用参数的默认值 | ||
| 598 | + args = applyDefaultValues(args, paramRuleData); | ||
| 599 | + session.setArgs(args); | ||
| 600 | + // 3. 【自动校验】检查必填项 | ||
| 601 | + List<String> missing = checkRequiredParams(args, paramRuleData); | ||
| 602 | + if (!missing.isEmpty()) { | ||
| 603 | + // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 604 | + String askMsg = buildAskUserMessage(meta, missing,args); | ||
| 605 | + return askMsg; | ||
| 606 | + } | ||
| 568 | 607 | ||
| 608 | + // 6. 【最终确认信息】所有检测通过后,需要和客户确认交互 | ||
| 609 | + List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | ||
| 610 | + ChatMessage userMessage = getLasterUserMssage(chatMessage); | ||
| 611 | + String input = StrUtil.replace(userMessage.text(),"用户输入:",StrUtil.EMPTY); | ||
| 569 | // {"0":"查询","1":"执行"} 查询不需要确认 | 612 | // {"0":"查询","1":"执行"} 查询不需要确认 |
| 570 | - Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); | ||
| 571 | - //判断是否生成数据 | ||
| 572 | - List<Map<String,Object>> sRowData = new ArrayList<>(); | ||
| 573 | - String sHandleType = "merge"; | ||
| 574 | - if(4== meta.getIBizType() && ObjectUtil.isNotEmpty(session.getCurrentRowData())){ | ||
| 575 | - Map<String,Object> sRowDataMap = UserChoseIntentParser.getSelectedRows( input, session.getCurrentRowData()); | ||
| 576 | - sRowData = (List<Map<String, Object>>) sRowDataMap.get("sRowData"); | ||
| 577 | - sHandleType = sRowDataMap.get("sHandleType").toString(); | ||
| 578 | - } | ||
| 579 | - //{"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | ||
| 580 | - | ||
| 581 | - if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) | ||
| 582 | - || 2== meta.getIBizType() | ||
| 583 | - || 3== meta.getIBizType() | ||
| 584 | - || 6== meta.getIBizType() | ||
| 585 | - || 7== meta.getIBizType() | ||
| 586 | - || 8== meta.getIBizType() | ||
| 587 | - ) | ||
| 588 | - { | ||
| 589 | - // 确认后必填项校验 | ||
| 590 | - List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); | ||
| 591 | - if (!missingAfter.isEmpty()) { | ||
| 592 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 593 | - String askMsg = buildAskUserMessage(meta, missingAfter,args); | ||
| 594 | - session.setSFunPrompts(askMsg); | ||
| 595 | - return String.valueOf(askUserResult(toolExecutionRequest, askMsg)); | ||
| 596 | - } | ||
| 597 | - // 7. 【业务校验】执行业务层面的逻辑校验 + 所有校验通过,执行核心业务逻辑 | ||
| 598 | - return executeTool(toolExecutionRequest, meta, args, paramRuleData, memoryId.toString(), session); | ||
| 599 | - } | ||
| 600 | - String askconfirmMsg =StrUtil.EMPTY; | ||
| 601 | -// if(0== meta.getIActionType() && 4!= meta.getIBizType() && 5!= meta.getIBizType()){ | ||
| 602 | -// askconfirmMsg = buildConfirmUserMessage(meta, args); | ||
| 603 | -// }else | ||
| 604 | - if(4== meta.getIBizType() || meta.getIBizType()==5){ | ||
| 605 | - askconfirmMsg = doGetFromData( meta,args,session); | ||
| 606 | -// session.setSFunPrompts(askconfirmMsg); | ||
| 607 | -// operableChatMemoryProvider.get(memoryId).add(UserMessage.from("SYSTEM: 等待用户确认或选择部分数据操作")); | ||
| 608 | - return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text(); | ||
| 609 | - }else{ | ||
| 610 | - askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); | 613 | + Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); |
| 614 | + //判断是否生成数据 | ||
| 615 | + List<Map<String,Object>> sRowData = new ArrayList<>(); | ||
| 616 | + String sHandleType = "merge"; | ||
| 617 | + if(4== meta.getIBizType() && ObjectUtil.isNotEmpty(session.getCurrentRowData())){ | ||
| 618 | + Map<String,Object> sRowDataMap = UserChoseIntentParser.getSelectedRows( input, session.getCurrentRowData()); | ||
| 619 | + sRowData = (List<Map<String, Object>>) sRowDataMap.get("sRowData"); | ||
| 620 | + sHandleType = sRowDataMap.get("sHandleType").toString(); | ||
| 621 | + } | ||
| 622 | + //{"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | ||
| 623 | + if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) | ||
| 624 | + || 2== meta.getIBizType() | ||
| 625 | + || 3== meta.getIBizType() | ||
| 626 | + || 6== meta.getIBizType() | ||
| 627 | + || 7== meta.getIBizType() | ||
| 628 | + || 8== meta.getIBizType() | ||
| 629 | + ) | ||
| 630 | + { | ||
| 631 | + // 确认后必填项校验 | ||
| 632 | + List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); | ||
| 633 | + if (!missingAfter.isEmpty()) { | ||
| 634 | + // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 635 | + String askMsg = buildAskUserMessage(meta, missingAfter,args); | ||
| 636 | + return askMsg; | ||
| 611 | } | 637 | } |
| 612 | - // 返回需要确认的结果 | ||
| 613 | - return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text(); | ||
| 614 | - }; | 638 | + // 7. 【业务校验】执行业务层面的逻辑校验 + 所有校验通过,执行核心业务逻辑 |
| 639 | + return executeTool(meta, args, paramRuleData, session.getUserId(), session); | ||
| 640 | + } | ||
| 641 | + String askconfirmMsg =StrUtil.EMPTY; | ||
| 642 | + if(4== meta.getIBizType() || meta.getIBizType()==5){ | ||
| 643 | + askconfirmMsg = doGetFromData( meta,args,session); | ||
| 644 | + return executeWithConfirmation(askconfirmMsg,operableChatMemoryProvider.get(session.getUserId()), session, meta); | ||
| 645 | + }else{ | ||
| 646 | + askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); | ||
| 647 | + } | ||
| 648 | + // 返回需要确认的结果 | ||
| 649 | + return executeWithConfirmation(askconfirmMsg,operableChatMemoryProvider.get(session.getUserId()), session, meta); | ||
| 615 | } | 650 | } |
| 651 | + | ||
| 616 | /*** | 652 | /*** |
| 617 | * @Author 钱豹 | 653 | * @Author 钱豹 |
| 618 | * @Date 15:16 2026/2/9 | 654 | * @Date 15:16 2026/2/9 |
| @@ -651,7 +687,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -651,7 +687,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 651 | **/ | 687 | **/ |
| 652 | private void appendConfirmAll(StringBuilder markdown,String sName){ | 688 | private void appendConfirmAll(StringBuilder markdown,String sName){ |
| 653 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; | 689 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; |
| 654 | - markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"1,3行确认"\n"); | 690 | + markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"第1行确认"\n"); |
| 655 | //全部确认 ,部分确认,取消 | 691 | //全部确认 ,部分确认,取消 |
| 656 | markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\" >全部确认</a>**").append(" ") | 692 | markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\" >全部确认</a>**").append(" ") |
| 657 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"合并确认\" >合并确认</a>**").append(" ") | 693 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"合并确认\" >合并确认</a>**").append(" ") |
| @@ -666,9 +702,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -666,9 +702,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 666 | **/ | 702 | **/ |
| 667 | private void appendConfirm(StringBuilder markdown,String sName){ | 703 | private void appendConfirm(StringBuilder markdown,String sName){ |
| 668 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; | 704 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; |
| 669 | - markdown.append("请确认是否执行").append(sName).append("操作?请直接回复"确认"或"取消"\n"); | ||
| 670 | - //全部确认 ,部分确认,取消 | ||
| 671 | - markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">确认</a>**").append(" ") | 705 | + markdown.append("请确认是否执行").append(sName).append("操作?请回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">确认</a>**").append(" ") |
| 672 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); | 706 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); |
| 673 | } | 707 | } |
| 674 | 708 | ||
| @@ -836,6 +870,14 @@ public class DynamicToolProvider implements ToolProvider { | @@ -836,6 +870,14 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 836 | } | 870 | } |
| 837 | return result; | 871 | return result; |
| 838 | } | 872 | } |
| 873 | + /** | ||
| 874 | + * 检查必填参数 | ||
| 875 | + */ | ||
| 876 | + private List<String> getRequiredParams(List<ParamRule> paramDefs) { | ||
| 877 | + return paramDefs.stream() | ||
| 878 | + .map(ParamRule::getSParam) | ||
| 879 | + .toList(); | ||
| 880 | + } | ||
| 839 | 881 | ||
| 840 | /** | 882 | /** |
| 841 | * 检查必填参数 | 883 | * 检查必填参数 |
| @@ -845,8 +887,11 @@ public class DynamicToolProvider implements ToolProvider { | @@ -845,8 +887,11 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 845 | return paramDefs.stream() | 887 | return paramDefs.stream() |
| 846 | .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()) | 888 | .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()) |
| 847 | .filter(pd -> | 889 | .filter(pd -> |
| 848 | - (!returnMap.containsKey(pd.getSParam()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam())))) | ||
| 849 | - && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) | 890 | + (!returnMap.containsKey(pd.getSParam()) |
| 891 | + || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam()))) | ||
| 892 | + || (pd.getSParamValue().startsWith("d") && 0==Double.valueOf (returnMap.get(pd.getSParam()).toString())) | ||
| 893 | + ) | ||
| 894 | + && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) | ||
| 850 | ) | 895 | ) |
| 851 | .map(ParamRule::getSParam) | 896 | .map(ParamRule::getSParam) |
| 852 | .toList(); | 897 | .toList(); |
| @@ -867,16 +912,17 @@ public class DynamicToolProvider implements ToolProvider { | @@ -867,16 +912,17 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 867 | .toList(); | 912 | .toList(); |
| 868 | } | 913 | } |
| 869 | 914 | ||
| 915 | + | ||
| 870 | /** | 916 | /** |
| 871 | * 模拟执行工具 | 917 | * 模拟执行工具 |
| 872 | */ | 918 | */ |
| 873 | - public String executeTool(ToolExecutionRequest toolExecutionRequest,ToolMeta meta, Map<String, Object> args, List<ParamRule> paramRuleData,String userId,UserSceneSession session ) { | 919 | + public String executeTool(ToolMeta meta, Map<String, Object> args, List<ParamRule> paramRuleData,String userId,UserSceneSession session ) { |
| 874 | log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); | 920 | log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); |
| 875 | // 2.2 将中文key转换成英文key | 921 | // 2.2 将中文key转换成英文key |
| 876 | args = transformationArgs( args, paramRuleData); | 922 | args = transformationArgs( args, paramRuleData); |
| 877 | String sReturn ="执行成功"; | 923 | String sReturn ="执行成功"; |
| 878 | try{ | 924 | try{ |
| 879 | - sReturn = executeToolAfter(meta, args,toolExecutionRequest,paramRuleData,session); | 925 | + sReturn = executeToolAfter(meta, args,paramRuleData,session); |
| 880 | }catch (BusinessException e) { | 926 | }catch (BusinessException e) { |
| 881 | return e.getMessage(); | 927 | return e.getMessage(); |
| 882 | } | 928 | } |
| @@ -893,7 +939,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -893,7 +939,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 893 | * @return | 939 | * @return |
| 894 | * @Description 返回结果后 执行业务类 | 940 | * @Description 返回结果后 执行业务类 |
| 895 | **/ | 941 | **/ |
| 896 | - private String executeToolAfter(ToolMeta meta, Map<String, Object> args,ToolExecutionRequest toolExecutionRequest,List<ParamRule> paramDefs,UserSceneSession session) { | 942 | + private String executeToolAfter(ToolMeta meta, Map<String, Object> args,List<ParamRule> paramDefs,UserSceneSession session) { |
| 897 | // {"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | 943 | // {"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} |
| 898 | String sBizContent = meta.getSBizContent(); | 944 | String sBizContent = meta.getSBizContent(); |
| 899 | Integer iBizType = meta.getIBizType(); | 945 | Integer iBizType = meta.getIBizType(); |
| @@ -950,7 +996,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -950,7 +996,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 950 | if ("queryTodayTask".equals(meta.getSMethodNo())) { | 996 | if ("queryTodayTask".equals(meta.getSMethodNo())) { |
| 951 | session.setBCleanMemory(true); | 997 | session.setBCleanMemory(true); |
| 952 | } | 998 | } |
| 953 | - return String.valueOf(successResult(toolExecutionRequest, sb.toString())); | 999 | + return sb.toString(); |
| 954 | } else { | 1000 | } else { |
| 955 | String sMsgText = "未找到对应的数据"; | 1001 | String sMsgText = "未找到对应的数据"; |
| 956 | session.setSFunPrompts(sMsgText); | 1002 | session.setSFunPrompts(sMsgText); |
| @@ -961,7 +1007,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -961,7 +1007,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 961 | return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), | 1007 | return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), |
| 962 | new HashMap<>(), "POST", "JSON"); | 1008 | new HashMap<>(), "POST", "JSON"); |
| 963 | } | 1009 | } |
| 964 | - return String.valueOf(successResult(toolExecutionRequest, "操作成功")); | 1010 | + return "操作成功"; |
| 965 | } | 1011 | } |
| 966 | 1012 | ||
| 967 | 1013 | ||
| @@ -1051,8 +1097,37 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1051,8 +1097,37 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1051 | } | 1097 | } |
| 1052 | List<Map<String, Object>> recordData = findFieldNameByChinese(sAIshowfieldShow, rows); | 1098 | List<Map<String, Object>> recordData = findFieldNameByChinese(sAIshowfieldShow, rows); |
| 1053 | int recordCount = dataset != null ? dataset.getTotalCount() : 0; | 1099 | int recordCount = dataset != null ? dataset.getTotalCount() : 0; |
| 1100 | + // 动态生成表头 | ||
| 1101 | + Set<String> headers = new LinkedHashSet<>(); | ||
| 1102 | + for (Map<String, Object> record : sAIshowfieldShow) { | ||
| 1103 | + String chineseName = (String) record.get("label"); | ||
| 1104 | + if (chineseName != null && !"sSlaveId".equals(record.get("sName"))) { | ||
| 1105 | + headers.add(chineseName); | ||
| 1106 | + } | ||
| 1107 | + } | ||
| 1108 | + | ||
| 1054 | StringBuilder markdown = new StringBuilder(); | 1109 | StringBuilder markdown = new StringBuilder(); |
| 1055 | //状态 | 1110 | //状态 |
| 1111 | + if(ObjectUtil.isNotEmpty(session.getArgs())){ | ||
| 1112 | + markdown.append("**查询条件**:"); | ||
| 1113 | + List<ParamRule> pr = session.getCurrentTool().getParamRuleListCheck(); | ||
| 1114 | + Map<String, Object> argsOld = new HashMap<>(session.getArgs()); | ||
| 1115 | + pr.forEach(one->{ | ||
| 1116 | + if(argsOld.containsKey(one.getSParam())){ | ||
| 1117 | + if(ObjectUtil.isNotEmpty(argsOld.get(one.getSParam()))){ | ||
| 1118 | + if(one.getSParamValue().startsWith("d")){ | ||
| 1119 | + if(Double.valueOf(argsOld.get(one.getSParam()).toString())>0){ | ||
| 1120 | + markdown.append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" "); | ||
| 1121 | + } | ||
| 1122 | + }else{ | ||
| 1123 | + markdown.append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" "); | ||
| 1124 | + } | ||
| 1125 | + } | ||
| 1126 | + } | ||
| 1127 | + }); | ||
| 1128 | + markdown.append("\n\n"); | ||
| 1129 | + } | ||
| 1130 | + markdown.append("**结果**:"); | ||
| 1056 | String sStatus = erpResult.getCode()<0?ErrorCode.ERRORMSG.getMessage():ErrorCode.SUCCESSMSG.getMessage(); | 1131 | String sStatus = erpResult.getCode()<0?ErrorCode.ERRORMSG.getMessage():ErrorCode.SUCCESSMSG.getMessage(); |
| 1057 | markdown.append(sStatus).append("\n"); | 1132 | markdown.append(sStatus).append("\n"); |
| 1058 | if(erpResult.getCode()<0){ | 1133 | if(erpResult.getCode()<0){ |
| @@ -1067,14 +1142,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1067,14 +1142,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1067 | } | 1142 | } |
| 1068 | // markdown.append("\n---\n"); | 1143 | // markdown.append("\n---\n"); |
| 1069 | markdown.append("\n\n").append("| 序号 | "); | 1144 | markdown.append("\n\n").append("| 序号 | "); |
| 1070 | - // 动态生成表头 | ||
| 1071 | - Set<String> headers = new LinkedHashSet<>(); | ||
| 1072 | - for (Map<String, Object> record : sAIshowfieldShow) { | ||
| 1073 | - String chineseName = (String) record.get("label"); | ||
| 1074 | - if (chineseName != null && !"sSlaveId".equals(record.get("sName"))) { | ||
| 1075 | - headers.add(chineseName); | ||
| 1076 | - } | ||
| 1077 | - } | ||
| 1078 | headers.forEach(header -> markdown.append(header).append(" | ")); | 1145 | headers.forEach(header -> markdown.append(header).append(" | ")); |
| 1079 | markdown.append("\n|").append("---|".repeat(headers.size() + 1)).append("\n"); | 1146 | markdown.append("\n|").append("---|".repeat(headers.size() + 1)).append("\n"); |
| 1080 | // 填充表格数据 | 1147 | // 填充表格数据 |
| @@ -1256,20 +1323,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1256,20 +1323,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1256 | } | 1323 | } |
| 1257 | 1324 | ||
| 1258 | /** | 1325 | /** |
| 1259 | - * 询问用户工具执行结果 | ||
| 1260 | - * @param request 工具执行请求 | ||
| 1261 | - * @param text 回复文本内容 | ||
| 1262 | - * @return 工具执行结果消息 | ||
| 1263 | - * @author 钱豹 | ||
| 1264 | - */ | ||
| 1265 | - private ToolExecutionResultMessage askUserResult(ToolExecutionRequest request, String text) { | ||
| 1266 | - // 直接返回标准结果 | ||
| 1267 | - return ToolExecutionResultMessage.from(request, text); | ||
| 1268 | - } | ||
| 1269 | - /** | ||
| 1270 | * 执行方法后需要用户确认的扩展版本 | 1326 | * 执行方法后需要用户确认的扩展版本 |
| 1271 | */ | 1327 | */ |
| 1272 | - private ToolExecutionResultMessage executeWithConfirmation(ToolExecutionRequest request, String initialResult,ChatMemory chatMemory, UserSceneSession session,ToolMeta meta) { | 1328 | + private String executeWithConfirmation(String initialResult,ChatMemory chatMemory, UserSceneSession session,ToolMeta meta) { |
| 1273 | 1329 | ||
| 1274 | // 第一步:执行原始操作,返回初步结果 | 1330 | // 第一步:执行原始操作,返回初步结果 |
| 1275 | Map<String, Object> step1Result = new HashMap<>(); | 1331 | Map<String, Object> step1Result = new HashMap<>(); |
| @@ -1278,18 +1334,19 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1278,18 +1334,19 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1278 | step1Result.put("confirmationRequired", true); | 1334 | step1Result.put("confirmationRequired", true); |
| 1279 | step1Result.put("confirmationMessage", initialResult); | 1335 | step1Result.put("confirmationMessage", initialResult); |
| 1280 | // // 将确认状态保存到对话记忆 | 1336 | // // 将确认状态保存到对话记忆 |
| 1281 | - chatMemory.add(UserMessage.from("SYSTEM: 等待用户确认操作")); | 1337 | +// chatMemory.add(UserMessage.from("SYSTEM: 等待用户确认操作")); |
| 1282 | String userMessage = formatConfirmationResult(step1Result); | 1338 | String userMessage = formatConfirmationResult(step1Result); |
| 1283 | session.setCurrentTool(meta); | 1339 | session.setCurrentTool(meta); |
| 1284 | - session.setSFunPrompts(userMessage); | 1340 | +// session.setSFunPrompts(userMessage); |
| 1285 | // 6. 返回确认请求 | 1341 | // 6. 返回确认请求 |
| 1286 | - return ToolExecutionResultMessage.from(request,userMessage); | 1342 | +// return ToolExecutionResultMessage.from(request,userMessage); |
| 1343 | + return userMessage; | ||
| 1287 | } | 1344 | } |
| 1288 | 1345 | ||
| 1289 | private String formatConfirmationResult(Map<String, Object> result) { | 1346 | private String formatConfirmationResult(Map<String, Object> result) { |
| 1290 | return String.format( | 1347 | return String.format( |
| 1291 | """ | 1348 | """ |
| 1292 | - **结果** : %s | 1349 | + %s |
| 1293 | """, | 1350 | """, |
| 1294 | result.get("initialResult"), | 1351 | result.get("initialResult"), |
| 1295 | result.get("confirmationMessage") | 1352 | result.get("confirmationMessage") |
src/main/resources/templates/chat.html
| @@ -468,7 +468,7 @@ | @@ -468,7 +468,7 @@ | ||
| 468 | let subsidiaryid= "1111111111"; | 468 | let subsidiaryid= "1111111111"; |
| 469 | let usertype= "sysadmin"; | 469 | let usertype= "sysadmin"; |
| 470 | // let usertype= "General"; | 470 | // let usertype= "General"; |
| 471 | - let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D59FCE41E63C9FE20948A232F9F67AAE5687D4EF8281542FFC87C4EB776974C6A538155B7ADAEE71E899235DC1122F426"; | 471 | + let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D0771D239F1C61B14219E1D1B3A166D73495FD8E662F2065F9430347C7E4472B5538155B7ADAEE71E899235DC1122F426"; |
| 472 | let hrefLock = window.location.origin+"/xlyAi"; | 472 | let hrefLock = window.location.origin+"/xlyAi"; |
| 473 | // ==================== 配置部分 ==================== | 473 | // ==================== 配置部分 ==================== |
| 474 | const CONFIG = { | 474 | const CONFIG = { |