Commit 38cc822b35c666ea38d7b0c780706318f05c47db
1 parent
e7d66b07
添加未清选择 改成动态引导语
Showing
4 changed files
with
39 additions
and
6 deletions
src/main/java/com/xly/entity/UserSceneSession.java
| @@ -6,6 +6,7 @@ import lombok.Data; | @@ -6,6 +6,7 @@ import lombok.Data; | ||
| 6 | 6 | ||
| 7 | import java.util.List; | 7 | import java.util.List; |
| 8 | import java.util.Map; | 8 | import java.util.Map; |
| 9 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
| 9 | import java.util.concurrent.atomic.AtomicInteger; | 10 | import java.util.concurrent.atomic.AtomicInteger; |
| 10 | import java.util.stream.Collectors; | 11 | import java.util.stream.Collectors; |
| 11 | 12 | ||
| @@ -101,6 +102,15 @@ public class UserSceneSession { | @@ -101,6 +102,15 @@ public class UserSceneSession { | ||
| 101 | **/ | 102 | **/ |
| 102 | private String sCopyToSrcId; | 103 | private String sCopyToSrcId; |
| 103 | 104 | ||
| 105 | + /*** | ||
| 106 | + * @Author 钱豹 | ||
| 107 | + * @Date 10:03 2026/4/24 | ||
| 108 | + * @Param | ||
| 109 | + * @return | ||
| 110 | + * @Description 工具是否已执行 | ||
| 111 | + **/ | ||
| 112 | + private Boolean toolExecuted=false; | ||
| 113 | + | ||
| 104 | /** | 114 | /** |
| 105 | * 构建场景选择提示语:展示权限内场景,引导用户选择 | 115 | * 构建场景选择提示语:展示权限内场景,引导用户选择 |
| 106 | * @return 自然语言提示语 | 116 | * @return 自然语言提示语 |
| @@ -181,5 +191,4 @@ public class UserSceneSession { | @@ -181,5 +191,4 @@ public class UserSceneSession { | ||
| 181 | return false; | 191 | return false; |
| 182 | } | 192 | } |
| 183 | 193 | ||
| 184 | - | ||
| 185 | } | 194 | } |
| 186 | \ No newline at end of file | 195 | \ No newline at end of file |
src/main/java/com/xly/tool/DynamicToolProvider.java
| @@ -198,6 +198,11 @@ public class DynamicToolProvider implements ToolProvider { | @@ -198,6 +198,11 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 198 | Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | 198 | Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); |
| 199 | // 获取Session | 199 | // 获取Session |
| 200 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); | 200 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); |
| 201 | + // 工具已执行,不再提供任何工具 | ||
| 202 | + if (session != null && session.getToolExecuted()) { | ||
| 203 | + log.info("工具已执行完成,清空可用工具列表"); | ||
| 204 | + return ToolProviderResult.builder().build(); | ||
| 205 | + } | ||
| 201 | 206 | ||
| 202 | // 过滤对应的权限方法 | 207 | // 过滤对应的权限方法 |
| 203 | List<ToolSpecificationHolder> datalist = new ArrayList<>(); | 208 | List<ToolSpecificationHolder> datalist = new ArrayList<>(); |
| @@ -255,9 +260,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -255,9 +260,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 255 | // ====================== 【超级强制:必须调用工具】 ====================== | 260 | // ====================== 【超级强制:必须调用工具】 ====================== |
| 256 | String forceToolPrompt = """ | 261 | String forceToolPrompt = """ |
| 257 | 【重要·强制指令】 | 262 | 【重要·强制指令】 |
| 258 | - 1. 这是当前唯一可用工具,必须调用,禁止直接回答 | ||
| 259 | - 2. 用户输入包含:确认、全部确认、合并确认、行号(第1行/第一行等) | ||
| 260 | - 3. 必须调用本工具,必须调用,必须调用! | 263 | + 1. 这是当前唯一可用工具,必须调用,禁止直接回答 |
| 264 | + 2. 用户输入包含:确认、全部确认、合并确认、行号(第1行/第一行等) | ||
| 265 | + 3. 必须调用本工具,必须调用,并且只调用一次,不要重复调用! | ||
| 261 | """; | 266 | """; |
| 262 | stoolDesc.append(forceToolPrompt); | 267 | stoolDesc.append(forceToolPrompt); |
| 263 | // ======================================================================== | 268 | // ======================================================================== |
| @@ -530,7 +535,13 @@ public class DynamicToolProvider implements ToolProvider { | @@ -530,7 +535,13 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 530 | 535 | ||
| 531 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); | 536 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); |
| 532 | session.setCurrentTool(meta); // 标记当前工具 | 537 | session.setCurrentTool(meta); // 标记当前工具 |
| 533 | - | 538 | + // 防止重复执行 |
| 539 | + if (session.getToolExecuted()) { | ||
| 540 | + log.warn("工具已执行过,拒绝重复调用: {}", meta.getSMethodNo()); | ||
| 541 | + return String.valueOf(successResult(toolExecutionRequest, "{\"status\":\"already_executed\"}")); | ||
| 542 | + } | ||
| 543 | + //标记执行了(所有工具方法只执行一次) | ||
| 544 | + session.setToolExecuted(true); | ||
| 534 | // 1. 解析参数 | 545 | // 1. 解析参数 |
| 535 | Map<String, Object> argsNew; | 546 | Map<String, Object> argsNew; |
| 536 | try { | 547 | try { |
| @@ -1096,6 +1107,8 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1096,6 +1107,8 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1096 | sBody.put("pageSize",10000); | 1107 | sBody.put("pageSize",10000); |
| 1097 | log.info("doGetFromData========================"); | 1108 | log.info("doGetFromData========================"); |
| 1098 | List<Map<String,Object>> list = new ArrayList<>(); | 1109 | List<Map<String,Object>> list = new ArrayList<>(); |
| 1110 | + //移除确认标识 | ||
| 1111 | + args.remove("operateType"); | ||
| 1099 | if(ObjectUtil.isNotEmpty(args)){ | 1112 | if(ObjectUtil.isNotEmpty(args)){ |
| 1100 | List<ParamRule> paramDefs = meta.getParamRuleList(); | 1113 | List<ParamRule> paramDefs = meta.getParamRuleList(); |
| 1101 | args.forEach((k,v)->{ | 1114 | args.forEach((k,v)->{ |
src/main/java/com/xly/tts/service/PythonTtsProxyService.java
| @@ -6,6 +6,7 @@ import com.xly.constant.BusinessCode; | @@ -6,6 +6,7 @@ import com.xly.constant.BusinessCode; | ||
| 6 | import com.xly.constant.ReturnTypeCode; | 6 | import com.xly.constant.ReturnTypeCode; |
| 7 | import com.xly.entity.AiResponseAccumulator; | 7 | import com.xly.entity.AiResponseAccumulator; |
| 8 | import com.xly.entity.AiResponseDTO; | 8 | import com.xly.entity.AiResponseDTO; |
| 9 | +import com.xly.entity.UserSceneSession; | ||
| 9 | import com.xly.service.UserSceneSessionService; | 10 | import com.xly.service.UserSceneSessionService; |
| 10 | import com.xly.service.XlyErpService; | 11 | import com.xly.service.XlyErpService; |
| 11 | import com.xly.tts.bean.*; | 12 | import com.xly.tts.bean.*; |
| @@ -117,10 +118,20 @@ public class PythonTtsProxyService { | @@ -117,10 +118,20 @@ public class PythonTtsProxyService { | ||
| 117 | String sSubsidiaryId = request.getSubsidiaryid(); | 118 | String sSubsidiaryId = request.getSubsidiaryid(); |
| 118 | String sUserType = request.getUsertype(); | 119 | String sUserType = request.getUsertype(); |
| 119 | String authorization = request.getAuthorization(); | 120 | String authorization = request.getAuthorization(); |
| 121 | + cleanupAfterExecution(sUserId); | ||
| 120 | AiResponseDTO voiceText = xlyErpService.erpUserInput(userInput, sUserId, sUserName, sBrandsId, sSubsidiaryId, sUserType, authorization); | 122 | AiResponseDTO voiceText = xlyErpService.erpUserInput(userInput, sUserId, sUserName, sBrandsId, sSubsidiaryId, sUserType, authorization); |
| 121 | return synthesizeStreamAi(request, voiceText); | 123 | return synthesizeStreamAi(request, voiceText); |
| 122 | } | 124 | } |
| 123 | 125 | ||
| 126 | + | ||
| 127 | + // 4. 在 AI 回复后清理 session | ||
| 128 | + public void cleanupAfterExecution(String memoryId) { | ||
| 129 | + UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId); | ||
| 130 | + if (session != null) { | ||
| 131 | + session.setToolExecuted(false); // 重置状态 | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | + | ||
| 124 | /** | 135 | /** |
| 125 | * 流式ERP + 流式TTS合成 | 136 | * 流式ERP + 流式TTS合成 |
| 126 | */ | 137 | */ |
src/main/resources/templates/chat.html
| @@ -466,7 +466,7 @@ | @@ -466,7 +466,7 @@ | ||
| 466 | let brandsid= "1111111111"; | 466 | let brandsid= "1111111111"; |
| 467 | let subsidiaryid= "1111111111"; | 467 | let subsidiaryid= "1111111111"; |
| 468 | let usertype= "sysadmin"; | 468 | let usertype= "sysadmin"; |
| 469 | - let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159A8BB22EBE26EF12CD9A1EEDB89DC6FB3386549BD9F3EBBD954D17D31CED5EED2E9C9A98822AD3F0E3100F8DBBB5963377538155B7ADAEE71E899235DC1122F426"; | 469 | + let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159A8BB22EBE26EF12CD9A1EEDB89DC6FB33178153C379FB82F53B4B689DA1BE7060687D4EF8281542FFC87C4EB776974C6A538155B7ADAEE71E899235DC1122F426"; |
| 470 | let hrefLock = window.location.origin+"/xlyAi"; | 470 | let hrefLock = window.location.origin+"/xlyAi"; |
| 471 | 471 | ||
| 472 | const CONFIG = { | 472 | const CONFIG = { |