You need to sign in before continuing.
Commit 148bdd8c0a43e97412156fb5d65e55320c74cfd3
1 parent
0c696213
添加未清选择 改成动态引导语
Showing
5 changed files
with
281 additions
and
609 deletions
src/main/java/com/xly/agent/ErpAiAgent.java
| 1 | package com.xly.agent; | 1 | package com.xly.agent; |
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | -import dev.langchain4j.service.MemoryId; | ||
| 5 | -import dev.langchain4j.service.SystemMessage; | ||
| 6 | -import dev.langchain4j.service.UserMessage; | ||
| 7 | -import dev.langchain4j.service.V; | 4 | +import dev.langchain4j.service.*; |
| 8 | 5 | ||
| 9 | /** | 6 | /** |
| 10 | * 优化后:新增场景专属交互规则,大模型仅处理当前场景业务指令 | 7 | * 优化后:新增场景专属交互规则,大模型仅处理当前场景业务指令 |
| @@ -13,7 +10,7 @@ public interface ErpAiAgent { | @@ -13,7 +10,7 @@ public interface ErpAiAgent { | ||
| 13 | 10 | ||
| 14 | @SystemMessage("{{sSystemPrompt}}") | 11 | @SystemMessage("{{sSystemPrompt}}") |
| 15 | @UserMessage("用户输入:{{userInput}}") | 12 | @UserMessage("用户输入:{{userInput}}") |
| 16 | - String chat( | 13 | + Result<String> chat( |
| 17 | @MemoryId String userId, | 14 | @MemoryId String userId, |
| 18 | @V("userInput") String userInput, | 15 | @V("userInput") String userInput, |
| 19 | @V("sSystemPrompt") String sSystemPrompt | 16 | @V("sSystemPrompt") String sSystemPrompt |
src/main/java/com/xly/service/XlyErpService.java
| @@ -22,13 +22,18 @@ import com.xly.thread.AiSqlErrorHistoryThread; | @@ -22,13 +22,18 @@ import com.xly.thread.AiSqlErrorHistoryThread; | ||
| 22 | import com.xly.thread.AiUserAgentQuestionThread; | 22 | import com.xly.thread.AiUserAgentQuestionThread; |
| 23 | import com.xly.thread.MultiThreadPoolServer; | 23 | import com.xly.thread.MultiThreadPoolServer; |
| 24 | import com.xly.tool.DynamicToolProvider; | 24 | import com.xly.tool.DynamicToolProvider; |
| 25 | +import com.xly.tool.ToolSpecificationHolder; | ||
| 25 | import com.xly.util.*; | 26 | import com.xly.util.*; |
| 27 | +import dev.langchain4j.agent.tool.ReturnBehavior; | ||
| 26 | import dev.langchain4j.agent.tool.ToolExecutionRequest; | 28 | import dev.langchain4j.agent.tool.ToolExecutionRequest; |
| 29 | +import dev.langchain4j.agent.tool.ToolSpecification; | ||
| 27 | import dev.langchain4j.data.message.AiMessage; | 30 | import dev.langchain4j.data.message.AiMessage; |
| 28 | import dev.langchain4j.data.message.ChatMessage; | 31 | import dev.langchain4j.data.message.ChatMessage; |
| 29 | 32 | ||
| 30 | import dev.langchain4j.model.ollama.OllamaChatModel; | 33 | import dev.langchain4j.model.ollama.OllamaChatModel; |
| 31 | import dev.langchain4j.service.AiServices; | 34 | import dev.langchain4j.service.AiServices; |
| 35 | +import dev.langchain4j.service.Result; | ||
| 36 | +import dev.langchain4j.service.tool.ToolExecutor; | ||
| 32 | import lombok.RequiredArgsConstructor; | 37 | import lombok.RequiredArgsConstructor; |
| 33 | import lombok.extern.slf4j.Slf4j; | 38 | import lombok.extern.slf4j.Slf4j; |
| 34 | import org.apache.commons.lang3.time.DateFormatUtils; | 39 | import org.apache.commons.lang3.time.DateFormatUtils; |
| @@ -131,7 +136,8 @@ public class XlyErpService { | @@ -131,7 +136,8 @@ public class XlyErpService { | ||
| 131 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) | 136 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) |
| 132 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) | 137 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) |
| 133 | ){ | 138 | ){ |
| 134 | - sResponMessage = aiAgent.chat(userId, input , AgentSystemPrompt.sSystemPrompt); | 139 | + Result<String> rs = aiAgent.chat(userId, input , AgentSystemPrompt.sSystemPrompt); |
| 140 | + sResponMessage = rs.content(); | ||
| 135 | } | 141 | } |
| 136 | 142 | ||
| 137 | if(ObjectUtil.isNotEmpty(session.getCurrentTool()) | 143 | if(ObjectUtil.isNotEmpty(session.getCurrentTool()) |
| @@ -350,7 +356,8 @@ public class XlyErpService { | @@ -350,7 +356,8 @@ public class XlyErpService { | ||
| 350 | if(ObjectUtil.isNotEmpty(session.getSSystemPrompt()) && isConfirmed){ | 356 | if(ObjectUtil.isNotEmpty(session.getSSystemPrompt()) && isConfirmed){ |
| 351 | sSystemPrompt = session.getSSystemPrompt(); | 357 | sSystemPrompt = session.getSSystemPrompt(); |
| 352 | } | 358 | } |
| 353 | - sResponMessage = aiAgent.chat(userId, input,sSystemPrompt); | 359 | + Result<String> rs = aiAgent.chat(userId, input,sSystemPrompt); |
| 360 | + sResponMessage = rs.content(); | ||
| 354 | } | 361 | } |
| 355 | methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSMethodName():StrUtil.EMPTY; | 362 | methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSMethodName():StrUtil.EMPTY; |
| 356 | if(ObjectUtil.isNotEmpty(session.getCurrentTool()) | 363 | if(ObjectUtil.isNotEmpty(session.getCurrentTool()) |
| @@ -945,19 +952,24 @@ public class XlyErpService { | @@ -945,19 +952,24 @@ public class XlyErpService { | ||
| 945 | // 4. 获取/创建用Agent | 952 | // 4. 获取/创建用Agent |
| 946 | ErpAiAgent aiAgent = UserSceneSessionService.ERP_AGENT_CACHE.get(userId); | 953 | ErpAiAgent aiAgent = UserSceneSessionService.ERP_AGENT_CACHE.get(userId); |
| 947 | if(ObjectUtil.isEmpty(aiAgent)){ | 954 | if(ObjectUtil.isEmpty(aiAgent)){ |
| 955 | + List<ToolSpecificationHolder> dataList = dynamicToolProvider.sceneToolCacheMap.get(session.getCurrentScene().getSId()); | ||
| 956 | + Set<String> immediateReturnToolNames = new HashSet<>(); | ||
| 957 | + Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | ||
| 958 | + if(ObjectUtil.isNotEmpty(dataList)){ | ||
| 959 | + dataList.forEach(one->{ | ||
| 960 | + immediateReturnToolNames.add(one.getsName()); | ||
| 961 | + executors.put(one.getToolSpecification(),one.getToolExecutor()); | ||
| 962 | + }); | ||
| 963 | + } | ||
| 948 | aiAgent = AiServices.builder(ErpAiAgent.class) | 964 | aiAgent = AiServices.builder(ErpAiAgent.class) |
| 949 | .chatModel(chatModel) | 965 | .chatModel(chatModel) |
| 950 | .chatMemoryProvider(operableChatMemoryProvider) | 966 | .chatMemoryProvider(operableChatMemoryProvider) |
| 951 | - .toolProvider(dynamicToolProvider) | ||
| 952 | -// .toolChoice(ChatCompletionToolChoice.ofRequired()) // 👈 必须调用一个工具 | 967 | + .tools(executors,immediateReturnToolNames) |
| 968 | +// .toolProvider(dynamicToolProvider) | ||
| 969 | +// .returnBehavior(ReturnBehavior.IMMEDIATE) | ||
| 970 | +// .toolChoice(ChatCompletionToolChoice.ofRequired()) | ||
| 953 | .build(); | 971 | .build(); |
| 954 | UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); | 972 | UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); |
| 955 | - // 初始化AiService 以防止热加载太慢 找不到相应的方法 | ||
| 956 | -// try{ | ||
| 957 | -// aiAgent.chat(userId, "initAiService",AgentSystemPrompt.sSystemPrompt); | ||
| 958 | -// }catch (Exception e){ | ||
| 959 | -// e.printStackTrace(); | ||
| 960 | -// } | ||
| 961 | log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); | 973 | log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); |
| 962 | } | 974 | } |
| 963 | return aiAgent; | 975 | return aiAgent; |
src/main/java/com/xly/tool/DynamicToolProvider.java
| @@ -14,6 +14,7 @@ import com.xly.config.OperableChatMemoryProvider; | @@ -14,6 +14,7 @@ import com.xly.config.OperableChatMemoryProvider; | ||
| 14 | import com.xly.constant.*; | 14 | import com.xly.constant.*; |
| 15 | import com.xly.entity.*; | 15 | import com.xly.entity.*; |
| 16 | import com.xly.exception.dto.BusinessException; | 16 | import com.xly.exception.dto.BusinessException; |
| 17 | +import com.xly.exception.dto.DataException; | ||
| 17 | import com.xly.mapper.ParamRuleMapper; | 18 | import com.xly.mapper.ParamRuleMapper; |
| 18 | import com.xly.mapper.ToolMetaMapper; | 19 | import com.xly.mapper.ToolMetaMapper; |
| 19 | import com.xly.service.DynamicExeDbService; | 20 | import com.xly.service.DynamicExeDbService; |
| @@ -30,12 +31,7 @@ import dev.langchain4j.memory.ChatMemory; | @@ -30,12 +31,7 @@ import dev.langchain4j.memory.ChatMemory; | ||
| 30 | 31 | ||
| 31 | import dev.langchain4j.model.chat.request.json.JsonObjectSchema; | 32 | import dev.langchain4j.model.chat.request.json.JsonObjectSchema; |
| 32 | import dev.langchain4j.model.chat.request.json.JsonSchema; | 33 | import dev.langchain4j.model.chat.request.json.JsonSchema; |
| 33 | -import dev.langchain4j.service.tool.ToolExecutor; | ||
| 34 | -import dev.langchain4j.service.tool.ToolProvider; | ||
| 35 | - | ||
| 36 | -import dev.langchain4j.service.tool.ToolProviderRequest; | ||
| 37 | - | ||
| 38 | -import dev.langchain4j.service.tool.ToolProviderResult; | 34 | +import dev.langchain4j.service.tool.*; |
| 39 | 35 | ||
| 40 | 36 | ||
| 41 | import lombok.Getter; | 37 | import lombok.Getter; |
| @@ -59,58 +55,42 @@ import java.util.stream.IntStream; | @@ -59,58 +55,42 @@ import java.util.stream.IntStream; | ||
| 59 | @RequiredArgsConstructor | 55 | @RequiredArgsConstructor |
| 60 | public class DynamicToolProvider implements ToolProvider { | 56 | public class DynamicToolProvider implements ToolProvider { |
| 61 | 57 | ||
| 62 | - // private final ToolMetaMapper toolMetaMapper; | ||
| 63 | private final ObjectMapper objectMapper; | 58 | private final ObjectMapper objectMapper; |
| 64 | private final ToolMetaMapper toolMetaMapper; | 59 | private final ToolMetaMapper toolMetaMapper; |
| 65 | private final ParamRuleMapper paramRuleMapper; | 60 | private final ParamRuleMapper paramRuleMapper; |
| 66 | private final DynamicExeDbService dynamicExeDbService; | 61 | private final DynamicExeDbService dynamicExeDbService; |
| 67 | private final OperableChatMemoryProvider operableChatMemoryProvider; | 62 | private final OperableChatMemoryProvider operableChatMemoryProvider; |
| 68 | 63 | ||
| 69 | - | ||
| 70 | - // 内存缓存:toolName -> ToolSpecificationHolder | ||
| 71 | private final Map<String, ToolSpecificationHolder> toolCache = new ConcurrentHashMap<>(); | 64 | private final Map<String, ToolSpecificationHolder> toolCache = new ConcurrentHashMap<>(); |
| 72 | public final Map<String, String> sSceneIdMap = new ConcurrentHashMap<>(); | 65 | public final Map<String, String> sSceneIdMap = new ConcurrentHashMap<>(); |
| 73 | - | ||
| 74 | - private final Map<String, List<ToolSpecificationHolder>> sceneToolCacheMap = new ConcurrentHashMap<>(); | 66 | + public final Map<String, List<ToolSpecificationHolder>> sceneToolCacheMap = new ConcurrentHashMap<>(); |
| 75 | private final List<ParamRule> paramRuleDataAll = new ArrayList<>(); | 67 | private final List<ParamRule> paramRuleDataAll = new ArrayList<>(); |
| 76 | 68 | ||
| 77 | @Value("${erp.baseurl}") | 69 | @Value("${erp.baseurl}") |
| 78 | private String baseUrl; | 70 | private String baseUrl; |
| 79 | 71 | ||
| 80 | - /*** | ||
| 81 | - * @Author 钱豹 | ||
| 82 | - * @Date 14:05 2026/2/10 | ||
| 83 | - * @Param [] | ||
| 84 | - * @return void | ||
| 85 | - * @Description 移除所有动态方法缓存 | ||
| 86 | - **/ | ||
| 87 | public void cleanAllToolProvider() { | 72 | public void cleanAllToolProvider() { |
| 88 | toolCache.clear(); | 73 | toolCache.clear(); |
| 89 | sceneToolCacheMap.clear(); | 74 | sceneToolCacheMap.clear(); |
| 90 | paramRuleDataAll.clear(); | 75 | paramRuleDataAll.clear(); |
| 91 | } | 76 | } |
| 92 | 77 | ||
| 93 | - /** | ||
| 94 | - * 初始化时加载所有启用的工具到缓存 | ||
| 95 | - */ | ||
| 96 | @jakarta.annotation.PostConstruct | 78 | @jakarta.annotation.PostConstruct |
| 97 | public void init() { | 79 | public void init() { |
| 98 | - // | ||
| 99 | List<ToolMeta> metas = toolMetaMapper.findAll(); | 80 | List<ToolMeta> metas = toolMetaMapper.findAll(); |
| 100 | for (ToolMeta meta : metas) { | 81 | for (ToolMeta meta : metas) { |
| 101 | try { | 82 | try { |
| 102 | - //补全业务类型查询类显示的字段 | ||
| 103 | doSetToolAIshowfieldShow(meta); | 83 | doSetToolAIshowfieldShow(meta); |
| 104 | ToolSpecification spec = buildToolSpecification(meta); | 84 | ToolSpecification spec = buildToolSpecification(meta); |
| 105 | ToolExecutor executor = createToolExecutor(meta); | 85 | ToolExecutor executor = createToolExecutor(meta); |
| 106 | - toolCache.put(meta.getSMethodNo(), new ToolSpecificationHolder(spec, executor)); | 86 | + toolCache.put(meta.getSMethodNo(), new ToolSpecificationHolder(spec, executor,meta.getSMethodNo())); |
| 107 | log.info("已加载动态工具:{}", meta.getSMethodNo()); | 87 | log.info("已加载动态工具:{}", meta.getSMethodNo()); |
| 108 | String sceneId = meta.getSSceneId(); | 88 | String sceneId = meta.getSSceneId(); |
| 109 | List<ToolSpecificationHolder> dataList = new ArrayList<>(); | 89 | List<ToolSpecificationHolder> dataList = new ArrayList<>(); |
| 110 | if(ObjectUtil.isNotEmpty(sceneToolCacheMap.get(sceneId))) { | 90 | if(ObjectUtil.isNotEmpty(sceneToolCacheMap.get(sceneId))) { |
| 111 | dataList = sceneToolCacheMap.get(sceneId); | 91 | dataList = sceneToolCacheMap.get(sceneId); |
| 112 | } | 92 | } |
| 113 | - dataList.add(new ToolSpecificationHolder(spec, executor)); | 93 | + dataList.add(new ToolSpecificationHolder(spec, executor,meta.getSMethodNo())); |
| 114 | sceneToolCacheMap.put(sceneId, dataList); | 94 | sceneToolCacheMap.put(sceneId, dataList); |
| 115 | } catch (Exception e) { | 95 | } catch (Exception e) { |
| 116 | e.printStackTrace(); | 96 | e.printStackTrace(); |
| @@ -119,8 +99,136 @@ public class DynamicToolProvider implements ToolProvider { | @@ -119,8 +99,136 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 119 | } | 99 | } |
| 120 | } | 100 | } |
| 121 | 101 | ||
| 122 | - //补全业务类型查询类显示的字段 | ||
| 123 | - //{"1":"存储过程","2":"SQL查询","3":"第三方API","4":"窗体查询","5":"按钮执行","6":"其它"} | 102 | + @Override |
| 103 | + public ToolProviderResult provideTools(ToolProviderRequest request) { | ||
| 104 | + String sUserId = request.chatMemoryId().toString(); | ||
| 105 | + Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | ||
| 106 | + UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); | ||
| 107 | + | ||
| 108 | + // ====================== 防重复调用核心拦截 ====================== | ||
| 109 | + if (session != null && (session.getToolExecuted() || StrUtil.isNotBlank(session.getSFunPrompts()))) { | ||
| 110 | + log.info("工具已执行/等待用户回复,禁止提供工具"); | ||
| 111 | + return ToolProviderResult.builder().build(); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + List<ToolSpecificationHolder> datalist = new ArrayList<>(); | ||
| 115 | + List<ToolMeta> toolMetaAll = new ArrayList<>(); | ||
| 116 | + | ||
| 117 | + if(session.getCurrentTool() != null){ | ||
| 118 | + toolMetaAll.add(session.getCurrentTool()); | ||
| 119 | + log.info("使用 currentTool: {}", session.getCurrentTool().getSMethodNo()); | ||
| 120 | + } else { | ||
| 121 | + toolMetaAll = session.getAuthTool(); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + if(ObjectUtil.isNotEmpty(toolMetaAll)){ | ||
| 125 | + toolMetaAll = toolMetaAll.stream() | ||
| 126 | + .filter(to -> to.getSSceneId().equals(sSceneIdMap.get(sUserId))) | ||
| 127 | + .collect(Collectors.toUnmodifiableList()); | ||
| 128 | + | ||
| 129 | + if(ObjectUtil.isNotEmpty(toolMetaAll)){ | ||
| 130 | + toolMetaAll.forEach(to -> { | ||
| 131 | + ToolSpecificationHolder holder = toolCache.get(to.getSMethodNo()); | ||
| 132 | + if (holder != null) { | ||
| 133 | + datalist.add(holder); | ||
| 134 | + log.debug("添加工具到提供器: {}", to.getSMethodNo()); | ||
| 135 | + } else { | ||
| 136 | + log.warn("工具缓存缺失: {}", to.getSMethodNo()); | ||
| 137 | + } | ||
| 138 | + }); | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + datalist.forEach(holder -> { | ||
| 143 | + executors.put(holder.getToolSpecification(), holder.getToolExecutor()); | ||
| 144 | + }); | ||
| 145 | + log.info("provideTools 返回工具数量: {}", executors.size()); | ||
| 146 | + return ToolProviderResult.builder().addAll(executors).build(); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + | ||
| 150 | + /*** | ||
| 151 | + * @Author 钱豹 | ||
| 152 | + * @Date 23:59 2026/5/17 | ||
| 153 | + * @Param [meta] | ||
| 154 | + * @return dev.langchain4j.service.tool.ToolExecutor | ||
| 155 | + * @Description AI 自动调用工具执行方法 | ||
| 156 | + **/ | ||
| 157 | + private ToolExecutor createToolExecutor(ToolMeta meta) { | ||
| 158 | + log.info("创建工具执行器: {}", meta.getSMethodNo()); | ||
| 159 | + | ||
| 160 | + return (toolExecutionRequest, memoryId) -> { | ||
| 161 | + log.info("===== 工具执行器开始执行 ====="); | ||
| 162 | + log.info("工具编号: {}", meta.getSMethodNo()); | ||
| 163 | + log.info("工具名称: {}", meta.getSMethodName()); | ||
| 164 | + log.info("memoryId: {}", memoryId); | ||
| 165 | + log.info("请求参数: {}", toolExecutionRequest.arguments()); | ||
| 166 | + UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); | ||
| 167 | + session.setCurrentTool(meta); | ||
| 168 | + | ||
| 169 | + // ====================== 防重复调用:立即上锁 ====================== | ||
| 170 | + session.setToolExecuted(true); | ||
| 171 | + if (StrUtil.isNotBlank(session.getSFunPrompts())) { | ||
| 172 | + // 关键:返回 工具执行失败 = 框架强制停止循环 | ||
| 173 | + throw new IllegalStateException("STOP_INVOCATION: 任务已完成,停止调用"); | ||
| 174 | +// return "【任务已完成】请勿重复调用工具,请直接总结结果回复用户:"+session.getSFunPrompts(); | ||
| 175 | + } | ||
| 176 | + //解析参数失败 | ||
| 177 | + Map<String, Object> argsNew; | ||
| 178 | + try { | ||
| 179 | + argsNew = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); | ||
| 180 | + log.info("解析后的参数: {}", argsNew); | ||
| 181 | + } catch (Exception e) { | ||
| 182 | + log.error("参数解析失败", e); | ||
| 183 | + // 抛异常 | ||
| 184 | + throw new RuntimeException("参数解析失败,请重新输入"); | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + //获取之前获取的参数 | ||
| 188 | + Map<String, Object> args = session.getArgs(); | ||
| 189 | + if(ObjectUtil.isEmpty(args)) args = new HashMap<>(); | ||
| 190 | + Map<String, Object> finalArgs = args; | ||
| 191 | + argsNew.forEach((k, v)->{ | ||
| 192 | + //获取对应的英文参数 | ||
| 193 | + List<ParamRule> data = meta.getParamRuleList().stream().filter(one->one.getSParam().equals(k)).collect(Collectors.toUnmodifiableList()); | ||
| 194 | + if(ObjectUtil.isNotEmpty(data) && data.size()>0){ | ||
| 195 | + finalArgs.remove(data.get(0).getSParamValue()); | ||
| 196 | + finalArgs.remove(data.get(0).getSParam()); | ||
| 197 | + } | ||
| 198 | + if(ObjectUtil.isNotEmpty(v)){ | ||
| 199 | + finalArgs.put(k,v); | ||
| 200 | + } | ||
| 201 | + }); | ||
| 202 | + | ||
| 203 | + // 2 【补全动态参数】动态参数补全 | ||
| 204 | + try{ | ||
| 205 | + args = applyValues(args, meta.getParamRuleListCheck()); | ||
| 206 | + }catch (Exception e){ | ||
| 207 | + log.error("返回信息",e); | ||
| 208 | + String askMsg = e.getMessage(); | ||
| 209 | + session.setSFunPrompts(askMsg); | ||
| 210 | + // 需要提问用户 → 抛异常停止循环 | ||
| 211 | + throw new RuntimeException(askMsg); | ||
| 212 | + } | ||
| 213 | + // 2.1 【自动补全】应用参数的默认值 | ||
| 214 | + List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | ||
| 215 | + args = applyDefaultValues(args, paramRuleData); | ||
| 216 | + session.setArgs(args); | ||
| 217 | + // 3. 【自动校验】检查必填项 | ||
| 218 | + List<String> missing = checkRequiredParams(args, paramRuleData); | ||
| 219 | + if (!missing.isEmpty()) { | ||
| 220 | + // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 221 | + String askMsg = buildAskUserMessage(meta, missing,args); | ||
| 222 | + session.setSFunPrompts(askMsg); | ||
| 223 | + return String.valueOf(successResult(toolExecutionRequest, askMsg)); | ||
| 224 | + } | ||
| 225 | + // ====================== 返回时带终止指令 ====================== | ||
| 226 | +// String resp = JSONUtil.toJsonStr(finalArgs) ; | ||
| 227 | + String resp = doDynamicTool( meta, session); | ||
| 228 | + return String.valueOf(successResult(toolExecutionRequest, resp)); | ||
| 229 | + }; | ||
| 230 | + } | ||
| 231 | + | ||
| 124 | private void doSetToolAIshowfieldShow(ToolMeta meta){ | 232 | private void doSetToolAIshowfieldShow(ToolMeta meta){ |
| 125 | String sToolId = meta.getSId(); | 233 | String sToolId = meta.getSId(); |
| 126 | List<ParamRule> paramRuleData = getParamRuleDataAll(); | 234 | List<ParamRule> paramRuleData = getParamRuleDataAll(); |
| @@ -137,7 +245,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -137,7 +245,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 137 | List<String> sAIshowfieldArry = new ArrayList<>(mutableList); | 245 | List<String> sAIshowfieldArry = new ArrayList<>(mutableList); |
| 138 | sAIshowfieldArry.add("sSlaveId"); | 246 | sAIshowfieldArry.add("sSlaveId"); |
| 139 | String sSrcFormId = meta.getSSrcFormId(); | 247 | String sSrcFormId = meta.getSSrcFormId(); |
| 140 | - //获取对应的窗体配置 | ||
| 141 | StringBuffer sSql =new StringBuffer().append("SELECT 10000 AS iOrderShow,A.sChinese AS label,A.sName,A.sControlName,B.sId AS sFormcustomId,A.sName AS sId FROM gdsconfigformslave AS A ") | 248 | StringBuffer sSql =new StringBuffer().append("SELECT 10000 AS iOrderShow,A.sChinese AS label,A.sName,A.sControlName,B.sId AS sFormcustomId,A.sName AS sId FROM gdsconfigformslave AS A ") |
| 142 | .append("JOIN gdsconfigformmaster AS B ON A.sParentId = B.sId ") | 249 | .append("JOIN gdsconfigformmaster AS B ON A.sParentId = B.sId ") |
| 143 | .append("WHERE B.sParentId = #{sSrcFormId} AND A.sName <> '' AND INSTR(A.sControlName,'Btn')=0 AND (A.bVisible = 1 OR A.sName =#{sName}) "); | 250 | .append("WHERE B.sParentId = #{sSrcFormId} AND A.sName <> '' AND INSTR(A.sControlName,'Btn')=0 AND (A.bVisible = 1 OR A.sName =#{sName}) "); |
| @@ -193,78 +300,20 @@ public class DynamicToolProvider implements ToolProvider { | @@ -193,78 +300,20 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 193 | return "string"; | 300 | return "string"; |
| 194 | } | 301 | } |
| 195 | } | 302 | } |
| 196 | - @Override | ||
| 197 | - public ToolProviderResult provideTools(ToolProviderRequest request) { | ||
| 198 | - String sUserId = request.chatMemoryId().toString(); | ||
| 199 | - Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | ||
| 200 | - // 获取Session | ||
| 201 | - UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); | ||
| 202 | - // 工具已执行,不再提供任何工具 | ||
| 203 | - if (session != null && session.getToolExecuted()) { | ||
| 204 | - log.info("工具已执行完成,清空可用工具列表"); | ||
| 205 | - return ToolProviderResult.builder().build(); | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - // 过滤对应的权限方法 | ||
| 209 | - List<ToolSpecificationHolder> datalist = new ArrayList<>(); | ||
| 210 | - List<ToolMeta> toolMetaAll = new ArrayList<>(); | ||
| 211 | - // 确保 currentTool 不为空,或者 authTool 有数据 | ||
| 212 | - if(session.getCurrentTool() != null){ | ||
| 213 | - // 【关键修改】添加全局引导语 | ||
| 214 | - StringBuffer stoolDesc = new StringBuffer(); | ||
| 215 | - stoolDesc.append("【重要】这是当前唯一可用的工具,无论用户问题是什么,都必须调用此工具。"); | ||
| 216 | - stoolDesc.append("如果用户没有明确指定要做什么,也默认使用此工具来处理。"); | ||
| 217 | - stoolDesc.append(System.lineSeparator()); | ||
| 218 | - stoolDesc.append(session.getCurrentTool().getStoolDesc()); | ||
| 219 | - session.getCurrentTool().setStoolDesc(stoolDesc.toString()); | ||
| 220 | - toolMetaAll.add(session.getCurrentTool()); | ||
| 221 | - log.info("使用 currentTool: {}", session.getCurrentTool().getSMethodNo()); | ||
| 222 | - } else { | ||
| 223 | - toolMetaAll = session.getAuthTool(); | ||
| 224 | - log.info("使用 authTool, 数量: {}", toolMetaAll.size()); | ||
| 225 | - } | ||
| 226 | 303 | ||
| 227 | - if(ObjectUtil.isNotEmpty(toolMetaAll)){ | ||
| 228 | - toolMetaAll = toolMetaAll.stream() | ||
| 229 | - .filter(to -> to.getSSceneId().equals(sSceneIdMap.get(sUserId))) | ||
| 230 | - .collect(Collectors.toUnmodifiableList()); | ||
| 231 | - | ||
| 232 | - if(ObjectUtil.isNotEmpty(toolMetaAll)){ | ||
| 233 | - toolMetaAll.forEach(to -> { | ||
| 234 | - ToolSpecificationHolder holder = toolCache.get(to.getSMethodNo()); | ||
| 235 | - if (holder != null) { | ||
| 236 | - datalist.add(holder); | ||
| 237 | - log.debug("添加工具到提供器: {}", to.getSMethodNo()); | ||
| 238 | - } else { | ||
| 239 | - log.warn("工具缓存缺失: {}", to.getSMethodNo()); | ||
| 240 | - } | ||
| 241 | - }); | ||
| 242 | - } | ||
| 243 | - } | ||
| 244 | - // 将工具添加到返回结果中 | ||
| 245 | - datalist.forEach(holder -> { | ||
| 246 | - executors.put(holder.getToolSpecification(), holder.getToolExecutor()); | ||
| 247 | - }); | ||
| 248 | - log.info("provideTools 返回工具数量: {}", executors.size()); | ||
| 249 | - return ToolProviderResult.builder().addAll(executors).build(); | ||
| 250 | - } | ||
| 251 | 304 | ||
| 252 | private ToolSpecification buildToolSpecification(ToolMeta meta) { | 305 | private ToolSpecification buildToolSpecification(ToolMeta meta) { |
| 253 | ToolSpecification.Builder builder = ToolSpecification.builder() | 306 | ToolSpecification.Builder builder = ToolSpecification.builder() |
| 254 | .name(meta.getSMethodNo()); | 307 | .name(meta.getSMethodNo()); |
| 255 | 308 | ||
| 256 | StringBuffer stoolDesc = new StringBuffer(); | 309 | StringBuffer stoolDesc = new StringBuffer(); |
| 257 | - StringBuffer sbt = new StringBuffer(); | ||
| 258 | - StringBuffer xt = new StringBuffer(); | ||
| 259 | - | ||
| 260 | - // 强制指令【完全保留】 | ||
| 261 | - String forceToolPrompt = StrUtil.EMPTY; | ||
| 262 | -// """ | ||
| 263 | -// 【重要·强制指令】 | ||
| 264 | -// 1. 这是当前唯一可用工具,必须调用,禁止直接回答 | ||
| 265 | -// 2. 用户输入包含:确认、全部确认、合并确认、行号(第1行/第一行等) | ||
| 266 | -// 3. 必须调用本工具,只调用一次! | ||
| 267 | -// """; | 310 | + String forceToolPrompt = """ |
| 311 | + 【工具调用规则】 | ||
| 312 | + 1. 每个自定义方法最多只能调用 1 次 | ||
| 313 | + 2. 只要方法返回结果,必须停止调用 | ||
| 314 | + 3. 禁止重复调用同一个方法 | ||
| 315 | + 4. 禁止无意义循环调用 | ||
| 316 | + """; | ||
| 268 | stoolDesc.append(forceToolPrompt); | 317 | stoolDesc.append(forceToolPrompt); |
| 269 | if (ObjectUtil.isNotEmpty(meta.getStoolDesc())) { | 318 | if (ObjectUtil.isNotEmpty(meta.getStoolDesc())) { |
| 270 | stoolDesc.append("MethodNo:").append(meta.getSMethodNo()) | 319 | stoolDesc.append("MethodNo:").append(meta.getSMethodNo()) |
| @@ -287,97 +336,51 @@ public class DynamicToolProvider implements ToolProvider { | @@ -287,97 +336,51 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 287 | String sRuleCost = getConstMeg(paramRule); | 336 | String sRuleCost = getConstMeg(paramRule); |
| 288 | switch (paramType.toLowerCase()) { | 337 | switch (paramType.toLowerCase()) { |
| 289 | case "string": | 338 | case "string": |
| 290 | - if (bEmpty) sbt.append(paramDesc).append("(字符串)、"); | ||
| 291 | - else xt.append(paramDesc).append("(字符串)、"); | ||
| 292 | schemaBuilder.addStringProperty(paramDesc, paramDesc); | 339 | schemaBuilder.addStringProperty(paramDesc, paramDesc); |
| 293 | break; | 340 | break; |
| 294 | - | ||
| 295 | case "integer": | 341 | case "integer": |
| 296 | case "int": | 342 | case "int": |
| 297 | - if (bEmpty) sbt.append(paramDesc).append("(数字)、"); | ||
| 298 | - else xt.append(paramDesc).append("(数字)、"); | ||
| 299 | schemaBuilder.addIntegerProperty(paramDesc, paramDesc); | 343 | schemaBuilder.addIntegerProperty(paramDesc, paramDesc); |
| 300 | break; | 344 | break; |
| 301 | - | ||
| 302 | case "number": | 345 | case "number": |
| 303 | case "double": | 346 | case "double": |
| 304 | case "float": | 347 | case "float": |
| 305 | - if (bEmpty) sbt.append(paramDesc).append("(浮点)、"); | ||
| 306 | - else xt.append(paramDesc).append("(浮点)、"); | ||
| 307 | schemaBuilder.addNumberProperty(paramDesc, paramDesc); | 348 | schemaBuilder.addNumberProperty(paramDesc, paramDesc); |
| 308 | break; | 349 | break; |
| 309 | - | ||
| 310 | case "boolean": | 350 | case "boolean": |
| 311 | case "bool": | 351 | case "bool": |
| 312 | - if (bEmpty) sbt.append(paramDesc).append("(布尔)、"); | ||
| 313 | - else xt.append(paramDesc).append("(布尔)、"); | ||
| 314 | schemaBuilder.addBooleanProperty(paramDesc, paramDesc); | 352 | schemaBuilder.addBooleanProperty(paramDesc, paramDesc); |
| 315 | break; | 353 | break; |
| 316 | - | ||
| 317 | case "array": | 354 | case "array": |
| 318 | - // 印后工艺:从SQL获取可选工艺列表 | ||
| 319 | - String postProcessArray = getArrrayBySql(paramRule); | ||
| 320 | - List<String> postProcessEnums = new ArrayList<>(); | ||
| 321 | - if (StrUtil.isNotBlank(postProcessArray)) { | ||
| 322 | - postProcessEnums = Arrays.asList(postProcessArray.split("/")); | ||
| 323 | - } | ||
| 324 | - StringBuffer paramDescTs = new StringBuffer(); | ||
| 325 | - paramDescTs.append(paramDesc).append("(数组类型,可多选印后工艺 [").append(postProcessArray).append("]"); | ||
| 326 | - // 处理默认值 | ||
| 327 | - if (ObjectUtil.isNotEmpty(paramRule.getSDefaultValue()) || | ||
| 328 | - (ObjectUtil.isNotEmpty(postProcessArray) && postProcessArray.split("/").length == 1)) { | ||
| 329 | - String defaultVal = (ObjectUtil.isNotEmpty(postProcessArray) && postProcessArray.split("/").length == 1) | ||
| 330 | - ? postProcessArray | ||
| 331 | - : paramRule.getSDefaultValue(); | ||
| 332 | - paramDescTs.append(",默认值[").append(defaultVal).append("]"); | ||
| 333 | - } else { | ||
| 334 | - paramDescTs.append(",无默认值"); | ||
| 335 | - } | ||
| 336 | - paramDescTs.append(")、"); | ||
| 337 | - // 有枚举值走枚举,没有走普通字符串 | ||
| 338 | - if (postProcessEnums.isEmpty()) { | ||
| 339 | - sbt.append(paramDescTs); | ||
| 340 | - schemaBuilder.addStringProperty(paramDesc, paramDescTs.toString()); | 355 | + String enumStr = getArrrayBySql(paramRule); |
| 356 | + List<String> enums = StrUtil.isNotBlank(enumStr) ? Arrays.asList(enumStr.split("/")) : new ArrayList<>(); | ||
| 357 | + if (enums.isEmpty()) { | ||
| 358 | + schemaBuilder.addStringProperty(paramDesc, paramDesc + "(数组)"); | ||
| 341 | } else { | 359 | } else { |
| 342 | - xt.append(paramDescTs); | ||
| 343 | - schemaBuilder.addEnumProperty(paramDesc, postProcessEnums, paramDescTs.toString()); | 360 | + schemaBuilder.addEnumProperty(paramDesc, enums, paramDesc + "(数组)"); |
| 344 | } | 361 | } |
| 345 | break; | 362 | break; |
| 346 | - | ||
| 347 | case "enum": | 363 | case "enum": |
| 348 | - // 印后工艺单选枚举 | ||
| 349 | - List<String> postProcessList = new ArrayList<>(); | ||
| 350 | - if (StrUtil.isNotBlank(sRuleCost)) { | ||
| 351 | - postProcessList = Arrays.asList(sRuleCost.split("/")); | ||
| 352 | - } | ||
| 353 | - if (postProcessList.isEmpty()) { | ||
| 354 | - schemaBuilder.addStringProperty(paramDesc, sRuleCost); | 364 | + String constStr = getConstMeg(paramRule); |
| 365 | + List<String> constList = StrUtil.isNotBlank(constStr) ? Arrays.asList(constStr.split("/")) : new ArrayList<>(); | ||
| 366 | + if (constList.isEmpty()) { | ||
| 367 | + schemaBuilder.addStringProperty(paramDesc, paramDesc); | ||
| 355 | } else { | 368 | } else { |
| 356 | - schemaBuilder.addEnumProperty(paramDesc, postProcessList, sRuleCost); | 369 | + schemaBuilder.addEnumProperty(paramDesc, constList, paramDesc); |
| 357 | } | 370 | } |
| 358 | break; | 371 | break; |
| 359 | default: | 372 | default: |
| 360 | schemaBuilder.addStringProperty(paramDesc, paramDesc); | 373 | schemaBuilder.addStringProperty(paramDesc, paramDesc); |
| 361 | break; | 374 | break; |
| 362 | } | 375 | } |
| 363 | - | ||
| 364 | if (bEmpty) { | 376 | if (bEmpty) { |
| 365 | requiredParams.add(paramDesc); | 377 | requiredParams.add(paramDesc); |
| 366 | } | 378 | } |
| 367 | } | 379 | } |
| 368 | - | ||
| 369 | -// if (ObjectUtil.isNotEmpty(sbt)) { | ||
| 370 | -// stoolDesc.append(System.lineSeparator()).append("1.必填参数:").append(sbt); | ||
| 371 | -// } | ||
| 372 | -// if (ObjectUtil.isNotEmpty(xt)) { | ||
| 373 | -// stoolDesc.append(System.lineSeparator()).append("2.选填参数:").append(xt); | ||
| 374 | -// } | ||
| 375 | - | ||
| 376 | } catch (Exception e) { | 380 | } catch (Exception e) { |
| 377 | e.printStackTrace(); | 381 | e.printStackTrace(); |
| 378 | } | 382 | } |
| 379 | 383 | ||
| 380 | - // 固定添加 operateType | ||
| 381 | if (meta.getIBizType() == 4 || meta.getIBizType() == 5) { | 384 | if (meta.getIBizType() == 4 || meta.getIBizType() == 5) { |
| 382 | schemaBuilder.addStringProperty("operateType", "操作类型:全部确认/合并确认/单行确认"); | 385 | schemaBuilder.addStringProperty("operateType", "操作类型:全部确认/合并确认/单行确认"); |
| 383 | requiredParams.add("operateType"); | 386 | requiredParams.add("operateType"); |
| @@ -392,13 +395,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -392,13 +395,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 392 | .build(); | 395 | .build(); |
| 393 | } | 396 | } |
| 394 | 397 | ||
| 395 | - /*** | ||
| 396 | - * @Author 钱豹 | ||
| 397 | - * @Date 23:42 2026/2/3 | ||
| 398 | - * @Param [sConstConfig, sRule] | ||
| 399 | - * @return java.lang.String | ||
| 400 | - * @Description 常量类型枚举 | ||
| 401 | - **/ | ||
| 402 | private String getConstMeg(ParamRule paramRule){ | 398 | private String getConstMeg(ParamRule paramRule){ |
| 403 | if(!RuleCode.CONST.getCode().equals(paramRule.getSRule())){ | 399 | if(!RuleCode.CONST.getCode().equals(paramRule.getSRule())){ |
| 404 | return StrUtil.EMPTY; | 400 | return StrUtil.EMPTY; |
| @@ -414,13 +410,11 @@ public class DynamicToolProvider implements ToolProvider { | @@ -414,13 +410,11 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 414 | paramRule.setSRuleTs(sb.toString()); | 410 | paramRule.setSRuleTs(sb.toString()); |
| 415 | return sb.toString(); | 411 | return sb.toString(); |
| 416 | } | 412 | } |
| 417 | - | ||
| 418 | return StrUtil.EMPTY; | 413 | return StrUtil.EMPTY; |
| 419 | } | 414 | } |
| 420 | - //数组类型枚举 | 415 | + |
| 421 | private String getArrrayBySql(ParamRule paramRule){ | 416 | private String getArrrayBySql(ParamRule paramRule){ |
| 422 | Boolean bCheckArray = !(RuleCode.SQL.getCode().equals(paramRule.getSRule())); | 417 | Boolean bCheckArray = !(RuleCode.SQL.getCode().equals(paramRule.getSRule())); |
| 423 | -// {"string":"字符","integer":"数字","double":"浮点","boolean":"布尔型","array":"数组","enum":"枚举"} | ||
| 424 | Boolean bCheckArray2= !("array".equals(paramRule.getSType()) || "enum".equals(paramRule.getSType())); | 418 | Boolean bCheckArray2= !("array".equals(paramRule.getSType()) || "enum".equals(paramRule.getSType())); |
| 425 | Boolean bCheckArray3= ObjectUtil.isEmpty(paramRule.getSParamConfig()); | 419 | Boolean bCheckArray3= ObjectUtil.isEmpty(paramRule.getSParamConfig()); |
| 426 | if(bCheckArray || bCheckArray2 || bCheckArray3){ | 420 | if(bCheckArray || bCheckArray2 || bCheckArray3){ |
| @@ -434,10 +428,8 @@ public class DynamicToolProvider implements ToolProvider { | @@ -434,10 +428,8 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 434 | if(data.get(0).containsKey("sGroupName")){ | 428 | if(data.get(0).containsKey("sGroupName")){ |
| 435 | Map<Object, List<Map<String, Object>>> groupData = data.stream() | 429 | Map<Object, List<Map<String, Object>>> groupData = data.stream() |
| 436 | .collect(Collectors.groupingBy(map -> map.get("sGroupName"))); | 430 | .collect(Collectors.groupingBy(map -> map.get("sGroupName"))); |
| 437 | - // 打印结果 | ||
| 438 | Integer sUpKeySize =groupData.size(); | 431 | Integer sUpKeySize =groupData.size(); |
| 439 | groupData.forEach((key, value) -> { | 432 | groupData.forEach((key, value) -> { |
| 440 | -// System.out.println("key: " + key); | ||
| 441 | value.forEach(one->{ | 433 | value.forEach(one->{ |
| 442 | sb.append(one.get(paramRule.getSParamValue())).append("/"); | 434 | sb.append(one.get(paramRule.getSParamValue())).append("/"); |
| 443 | }); | 435 | }); |
| @@ -446,8 +438,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -446,8 +438,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 446 | sb.append(","); | 438 | sb.append(","); |
| 447 | } | 439 | } |
| 448 | }); | 440 | }); |
| 449 | - | ||
| 450 | - | ||
| 451 | }else{ | 441 | }else{ |
| 452 | data.forEach(one->{ | 442 | data.forEach(one->{ |
| 453 | if(ObjectUtil.isNotEmpty(one.get(paramRule.getSParamValue()))){ | 443 | if(ObjectUtil.isNotEmpty(one.get(paramRule.getSParamValue()))){ |
| @@ -462,135 +452,34 @@ public class DynamicToolProvider implements ToolProvider { | @@ -462,135 +452,34 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 462 | return sb.toString(); | 452 | return sb.toString(); |
| 463 | } | 453 | } |
| 464 | 454 | ||
| 465 | - | ||
| 466 | - /*** | ||
| 467 | - * @Author 钱豹 | ||
| 468 | - * @Date 15:08 2026/1/30 | ||
| 469 | - * @Param [] | ||
| 470 | - * @return java.util.List<com.xly.entity.ParamRule> | ||
| 471 | - * @Description 获取所有参数 | ||
| 472 | - **/ | ||
| 473 | private List<ParamRule> getParamRuleDataAll(){ | 455 | private List<ParamRule> getParamRuleDataAll(){ |
| 474 | if(paramRuleDataAll==null || paramRuleDataAll.size()==0){ | 456 | if(paramRuleDataAll==null || paramRuleDataAll.size()==0){ |
| 475 | paramRuleDataAll.addAll(paramRuleMapper.findAll()); | 457 | paramRuleDataAll.addAll(paramRuleMapper.findAll()); |
| 476 | } | 458 | } |
| 477 | return paramRuleDataAll; | 459 | return paramRuleDataAll; |
| 478 | } | 460 | } |
| 479 | - /*** | ||
| 480 | - * @Author 钱豹 | ||
| 481 | - * @Date 12:37 2026/3/16 | ||
| 482 | - * @Param [meta] | ||
| 483 | - * @return dev.langchain4j.service.tool.ToolExecutor | ||
| 484 | - * @Description 参数采集执行器 | ||
| 485 | - **/ | ||
| 486 | - private ToolExecutor createToolExecutor(ToolMeta meta) { | ||
| 487 | - log.info("创建工具执行器: {}", meta.getSMethodNo()); | ||
| 488 | - | ||
| 489 | - return (toolExecutionRequest, memoryId) -> { | ||
| 490 | - log.info("===== 工具执行器开始执行 ====="); | ||
| 491 | - log.info("工具编号: {}", meta.getSMethodNo()); | ||
| 492 | - log.info("工具名称: {}", meta.getSMethodName()); | ||
| 493 | - log.info("memoryId: {}", memoryId); | ||
| 494 | - log.info("请求参数: {}", toolExecutionRequest.arguments()); | ||
| 495 | 461 | ||
| 496 | - UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); | ||
| 497 | - session.setCurrentTool(meta); // 标记当前工具 | ||
| 498 | - // 防止重复执行 | ||
| 499 | - if (session.getToolExecuted()) { | ||
| 500 | - log.warn("工具已执行过,拒绝重复调用: {}", meta.getSMethodNo()); | ||
| 501 | - return String.valueOf(successResult(toolExecutionRequest, "{\"status\":\"already_executed\"}")); | ||
| 502 | - } | ||
| 503 | - //标记执行了(所有工具方法只执行一次) | ||
| 504 | - session.setToolExecuted(true); | ||
| 505 | - // 1. 解析参数 | ||
| 506 | - Map<String, Object> argsNew; | ||
| 507 | - try { | ||
| 508 | - argsNew = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); | ||
| 509 | - log.info("解析后的参数: {}", argsNew); | ||
| 510 | - } catch (Exception e) { | ||
| 511 | - log.error("参数解析失败", e); | ||
| 512 | - String errorMsg = "参数解析失败,请重新输入"; | ||
| 513 | - return String.valueOf(errorResult(toolExecutionRequest, errorMsg)); | ||
| 514 | - } | ||
| 515 | - Map<String, Object> args = session.getArgs(); | ||
| 516 | - if(ObjectUtil.isEmpty(args)){ | ||
| 517 | - args = new HashMap<>(); | ||
| 518 | - } | ||
| 519 | - Map<String, Object> finalArgs = args; | ||
| 520 | - argsNew.forEach((k, v)->{ | ||
| 521 | - //获取对应的英文参数 | ||
| 522 | - List<ParamRule> data = meta.getParamRuleList().stream().filter(one->one.getSParam().equals(k)).collect(Collectors.toUnmodifiableList()); | ||
| 523 | - if(ObjectUtil.isNotEmpty(data) && data.size()>0){ | ||
| 524 | - finalArgs.remove(data.get(0).getSParamValue()); | ||
| 525 | - finalArgs.remove(data.get(0).getSParam()); | ||
| 526 | - } | ||
| 527 | - if(ObjectUtil.isNotEmpty(v)){ | ||
| 528 | - finalArgs.put(k,v); | ||
| 529 | - } | ||
| 530 | - }); | ||
| 531 | - // 2 【补全动态参数】动态参数补全 | ||
| 532 | - try{ | ||
| 533 | - args = applyValues(args, meta.getParamRuleListCheck()); | ||
| 534 | - }catch (Exception e){ | ||
| 535 | - log.error("返回信息",e); | ||
| 536 | - String askMsg = e.getMessage(); | ||
| 537 | - session.setSFunPrompts(askMsg); | ||
| 538 | - return String.valueOf(successResult(toolExecutionRequest, askMsg)); | ||
| 539 | - } | ||
| 540 | - List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | ||
| 541 | - // 2.1 【自动补全】应用参数的默认值 | ||
| 542 | - args = applyDefaultValues(args, paramRuleData); | ||
| 543 | - session.setArgs(args); | ||
| 544 | - // 3. 【自动校验】检查必填项 | ||
| 545 | - List<String> missing = checkRequiredParams(args, paramRuleData); | ||
| 546 | - if (!missing.isEmpty()) { | ||
| 547 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 548 | - String askMsg = buildAskUserMessage(meta, missing,args); | ||
| 549 | - session.setSFunPrompts(askMsg); | ||
| 550 | - return String.valueOf(successResult(toolExecutionRequest, askMsg)); | ||
| 551 | - } | ||
| 552 | - // 2. 获取必填参数规则 | ||
| 553 | -// List<ParamRule> sParamRules = meta.getParamRuleListCheck(); | ||
| 554 | -// List<String> missingParams = getRequiredParams(sParamRules); | ||
| 555 | -// String collectPrompt = buildCollectParamsPrompt(meta, missingParams, args); | ||
| 556 | -// log.info("参数缺失,返回收集提示: {}", collectPrompt); | ||
| 557 | - return String.valueOf(successResult(toolExecutionRequest, JSONUtil.toJsonStr(finalArgs))); | ||
| 558 | - }; | ||
| 559 | - } | ||
| 560 | 462 | ||
| 561 | public String doDynamicTool(ToolMeta meta,UserSceneSession session) { | 463 | public String doDynamicTool(ToolMeta meta,UserSceneSession session) { |
| 562 | List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | 464 | List<ParamRule> paramRuleData = meta.getParamRuleListAll(); |
| 563 | List<ParamRule> paramRuleDataCheck = meta.getParamRuleListCheck(); | 465 | List<ParamRule> paramRuleDataCheck = meta.getParamRuleListCheck(); |
| 564 | Map<String, Object> args = session.getArgs(); | 466 | Map<String, Object> args = session.getArgs(); |
| 565 | 467 | ||
| 566 | - // 3. 【自动校验】检查必填项 | ||
| 567 | List<String> missing = checkRequiredParams(args, paramRuleDataCheck); | 468 | List<String> missing = checkRequiredParams(args, paramRuleDataCheck); |
| 568 | if (!missing.isEmpty()) { | 469 | if (!missing.isEmpty()) { |
| 569 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 570 | String askMsg = buildAskUserMessage(meta, missing,args); | 470 | String askMsg = buildAskUserMessage(meta, missing,args); |
| 571 | - //告知AI 缺失参数 | ||
| 572 | -// operableChatMemoryProvider.get(session.getUserId()).add(UserMessage.from(askMsg)); | ||
| 573 | return askMsg; | 471 | return askMsg; |
| 574 | } | 472 | } |
| 575 | 473 | ||
| 576 | - // 6. 【最终确认信息】所有检测通过后,需要和客户确认交互 | ||
| 577 | List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | 474 | List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); |
| 578 | ChatMessage userMessage = getLastUserMessage(chatMessage); | 475 | ChatMessage userMessage = getLastUserMessage(chatMessage); |
| 579 | String input = ""; | 476 | String input = ""; |
| 580 | if (userMessage != null) { | 477 | if (userMessage != null) { |
| 581 | input = StrUtil.replace(getChatMessageContent(userMessage), "用户输入:", StrUtil.EMPTY); | 478 | input = StrUtil.replace(getChatMessageContent(userMessage), "用户输入:", StrUtil.EMPTY); |
| 582 | } | 479 | } |
| 583 | -// {"0":"查询","1":"执行"} 查询不需要确认 | 480 | + |
| 584 | Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); | 481 | Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); |
| 585 | -// //判断是否生成数据 | ||
| 586 | -// List<Map<String,Object>> sRowData = new ArrayList<>(); | ||
| 587 | -// String sHandleType = "merge"; | ||
| 588 | -// if(4== meta.getIBizType() && ObjectUtil.isNotEmpty(session.getCurrentRowData())){ | ||
| 589 | -// Map<String,Object> sRowDataMap = UserChoseIntentParser.getSelectedRows( input, session.getCurrentRowData()); | ||
| 590 | -// sRowData = (List<Map<String, Object>>) sRowDataMap.get("sRowData"); | ||
| 591 | -// sHandleType = sRowDataMap.get("sHandleType").toString(); | ||
| 592 | -// } | ||
| 593 | - //{"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | 482 | + |
| 594 | if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) | 483 | if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) |
| 595 | || 2== meta.getIBizType() | 484 | || 2== meta.getIBizType() |
| 596 | || 3== meta.getIBizType() | 485 | || 3== meta.getIBizType() |
| @@ -599,40 +488,29 @@ public class DynamicToolProvider implements ToolProvider { | @@ -599,40 +488,29 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 599 | || 8== meta.getIBizType() | 488 | || 8== meta.getIBizType() |
| 600 | ) | 489 | ) |
| 601 | { | 490 | { |
| 602 | - // 确认后必填项校验 | ||
| 603 | List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); | 491 | List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); |
| 604 | if (!missingAfter.isEmpty()) { | 492 | if (!missingAfter.isEmpty()) { |
| 605 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | ||
| 606 | String askMsg = buildAskUserMessage(meta, missingAfter,args); | 493 | String askMsg = buildAskUserMessage(meta, missingAfter,args); |
| 607 | - return askMsg; | 494 | + throw new DataException(askMsg); |
| 608 | } | 495 | } |
| 609 | - // 7. 【业务校验】执行业务层面的逻辑校验 + 所有校验通过,执行核心业务逻辑 | ||
| 610 | return executeTool(meta, args, paramRuleData, session.getUserId(), session); | 496 | return executeTool(meta, args, paramRuleData, session.getUserId(), session); |
| 611 | } | 497 | } |
| 498 | + | ||
| 612 | String askconfirmMsg =StrUtil.EMPTY; | 499 | String askconfirmMsg =StrUtil.EMPTY; |
| 613 | if(4== meta.getIBizType() || meta.getIBizType()==5){ | 500 | if(4== meta.getIBizType() || meta.getIBizType()==5){ |
| 614 | askconfirmMsg = doGetFromData( meta,args,session); | 501 | askconfirmMsg = doGetFromData( meta,args,session); |
| 615 | - // ===================== 加入这一行 ===================== | ||
| 616 | String sSystemPrompt = buildDynamicSystemPrompt(session); | 502 | String sSystemPrompt = buildDynamicSystemPrompt(session); |
| 617 | session.setSSystemPrompt(sSystemPrompt); | 503 | session.setSSystemPrompt(sSystemPrompt); |
| 618 | - //===================== AI 返回需要确认 ===================== | ||
| 619 | return executeWithConfirmation(askconfirmMsg, session, meta); | 504 | return executeWithConfirmation(askconfirmMsg, session, meta); |
| 620 | }else{ | 505 | }else{ |
| 621 | askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); | 506 | askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); |
| 622 | } | 507 | } |
| 623 | - // 返回需要确认的结果 | ||
| 624 | return executeWithConfirmation(askconfirmMsg, session, meta); | 508 | return executeWithConfirmation(askconfirmMsg, session, meta); |
| 625 | } | 509 | } |
| 626 | 510 | ||
| 627 | - /** | ||
| 628 | - * 安全获取 ChatMessage 内容,适配你当前所有版本 | ||
| 629 | - * 不依赖 UserMessage / .text() | ||
| 630 | - */ | ||
| 631 | private String getChatMessageContent(ChatMessage message) { | 511 | private String getChatMessageContent(ChatMessage message) { |
| 632 | if (message == null) return ""; | 512 | if (message == null) return ""; |
| 633 | - | ||
| 634 | try { | 513 | try { |
| 635 | - // 通用反射获取内容(兼容所有版本) | ||
| 636 | return message.toString() | 514 | return message.toString() |
| 637 | .replace("ChatMessage{", "") | 515 | .replace("ChatMessage{", "") |
| 638 | .replace("}", "") | 516 | .replace("}", "") |
| @@ -642,9 +520,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -642,9 +520,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 642 | return ""; | 520 | return ""; |
| 643 | } | 521 | } |
| 644 | } | 522 | } |
| 523 | + | ||
| 645 | private ChatMessage getLastUserMessage(List<ChatMessage> messages) { | 524 | private ChatMessage getLastUserMessage(List<ChatMessage> messages) { |
| 646 | if (messages == null || messages.isEmpty()) return null; | 525 | if (messages == null || messages.isEmpty()) return null; |
| 647 | - | ||
| 648 | for (int i = messages.size() - 1; i >= 0; i--) { | 526 | for (int i = messages.size() - 1; i >= 0; i--) { |
| 649 | ChatMessage msg = messages.get(i); | 527 | ChatMessage msg = messages.get(i); |
| 650 | if (msg.type() == ChatMessageType.USER) { | 528 | if (msg.type() == ChatMessageType.USER) { |
| @@ -654,14 +532,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -654,14 +532,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 654 | return null; | 532 | return null; |
| 655 | } | 533 | } |
| 656 | 534 | ||
| 657 | - | ||
| 658 | - /*** | ||
| 659 | - * @Author 钱豹 | ||
| 660 | - * @Date 15:16 2026/2/9 | ||
| 661 | - * @Param [argMap] | ||
| 662 | - * @return java.lang.String | ||
| 663 | - * @Description MAP转提示 | ||
| 664 | - **/ | ||
| 665 | private String getDefMessage(Map<String,Object> argMap,String sName,ToolMeta meta){ | 535 | private String getDefMessage(Map<String,Object> argMap,String sName,ToolMeta meta){ |
| 666 | List<ParamRule> showList = meta.getParamRuleListAll(); | 536 | List<ParamRule> showList = meta.getParamRuleListAll(); |
| 667 | List<ParamRule> showListData = new ArrayList<>(); | 537 | List<ParamRule> showListData = new ArrayList<>(); |
| @@ -684,67 +554,31 @@ public class DynamicToolProvider implements ToolProvider { | @@ -684,67 +554,31 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 684 | appendConfirm(markdown,sName); | 554 | appendConfirm(markdown,sName); |
| 685 | return markdown.toString(); | 555 | return markdown.toString(); |
| 686 | } | 556 | } |
| 687 | - /*** | ||
| 688 | - * @Author 钱豹 | ||
| 689 | - * @Date 14:56 2026/2/9 | ||
| 690 | - * @Param [markdown] | ||
| 691 | - * @return void | ||
| 692 | - * @Description 全部确认 | ||
| 693 | - **/ | 557 | + |
| 694 | private void appendConfirmAll(StringBuilder markdown,String sName){ | 558 | private void appendConfirmAll(StringBuilder markdown,String sName){ |
| 695 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; | 559 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; |
| 696 | markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"第1行确认"\n"); | 560 | markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"第1行确认"\n"); |
| 697 | - //全部确认 ,部分确认,取消 | ||
| 698 | markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\" >全部确认</a>**").append(" ") | 561 | markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\" >全部确认</a>**").append(" ") |
| 699 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"合并确认\" >合并确认</a>**").append(" ") | 562 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"合并确认\" >合并确认</a>**").append(" ") |
| 700 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\" >取消</a>**"); | 563 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\" >取消</a>**"); |
| 701 | } | 564 | } |
| 702 | - /*** | ||
| 703 | - * @Author 钱豹 | ||
| 704 | - * @Date 14:56 2026/2/9 | ||
| 705 | - * @Param [markdown] | ||
| 706 | - * @return void | ||
| 707 | - * @Description 单条确认 | ||
| 708 | - **/ | 565 | + |
| 709 | private void appendConfirm(StringBuilder markdown,String sName){ | 566 | private void appendConfirm(StringBuilder markdown,String sName){ |
| 710 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; | 567 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; |
| 711 | markdown.append("请确认是否执行").append(sName).append("操作?请回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">确认</a>**").append(" ") | 568 | markdown.append("请确认是否执行").append(sName).append("操作?请回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">确认</a>**").append(" ") |
| 712 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); | 569 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); |
| 713 | } | 570 | } |
| 714 | 571 | ||
| 715 | - private ChatMessage getLasterUserMssage(List<ChatMessage> chatMessage){ | ||
| 716 | - if(chatMessage!=null){ | ||
| 717 | - for(int i=chatMessage.size()-1;i>0;i--){ | ||
| 718 | - ChatMessage data = chatMessage.get(i); | ||
| 719 | - ChatMessageType sType = data.type(); | ||
| 720 | - if(ChatMessageType.USER.equals(sType)){ | ||
| 721 | - return chatMessage.get(i); | ||
| 722 | - } | ||
| 723 | - } | ||
| 724 | - } | ||
| 725 | - return null; | ||
| 726 | - } | ||
| 727 | - | ||
| 728 | - /*** | ||
| 729 | - * @Author 钱豹 | ||
| 730 | - * @Date 13:35 2026/1/31 | ||
| 731 | - * @Param [args, paramDefs] | ||
| 732 | - * @return java.util.Map<java.lang.String,java.lang.Object> | ||
| 733 | - * @Description Map 值转换 | ||
| 734 | - **/ | ||
| 735 | private Map<String, Object> transformationArgs(Map<String, Object> args, List<ParamRule> paramDefs) { | 572 | private Map<String, Object> transformationArgs(Map<String, Object> args, List<ParamRule> paramDefs) { |
| 736 | Map<String, Object> result = new HashMap<>(args); | 573 | Map<String, Object> result = new HashMap<>(args); |
| 737 | paramDefs.forEach(pd->{ | 574 | paramDefs.forEach(pd->{ |
| 738 | String name = pd.getSParam(); | 575 | String name = pd.getSParam(); |
| 739 | String sValue = pd.getSParamValue(); | 576 | String sValue = pd.getSParamValue(); |
| 740 | - //中文 | ||
| 741 | Boolean bCheck = result.containsKey(name) && ObjectUtil.isNotEmpty(result.get(name)); | 577 | Boolean bCheck = result.containsKey(name) && ObjectUtil.isNotEmpty(result.get(name)); |
| 742 | - //英文字段 | ||
| 743 | Boolean bCheck2 = result.containsKey(sValue) && ObjectUtil.isNotEmpty(result.get(sValue)); | 578 | Boolean bCheck2 = result.containsKey(sValue) && ObjectUtil.isNotEmpty(result.get(sValue)); |
| 744 | if (!bCheck2 && bCheck ) { | 579 | if (!bCheck2 && bCheck ) { |
| 745 | result.put(sValue,args.get(name)); | 580 | result.put(sValue,args.get(name)); |
| 746 | } | 581 | } |
| 747 | - //常量value -> key 转换 用于后面入库 | ||
| 748 | if(RuleCode.CONST.getCode().equals(pd.getSRule()) && ObjectUtil.isNotEmpty(result.get(sValue))){ | 582 | if(RuleCode.CONST.getCode().equals(pd.getSRule()) && ObjectUtil.isNotEmpty(result.get(sValue))){ |
| 749 | String sData = result.get(sValue).toString(); | 583 | String sData = result.get(sValue).toString(); |
| 750 | Map<String,Object> configData = JSONUtil.parseObj(pd.getSParamConfig()); | 584 | Map<String,Object> configData = JSONUtil.parseObj(pd.getSParamConfig()); |
| @@ -758,13 +592,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -758,13 +592,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 758 | return result; | 592 | return result; |
| 759 | } | 593 | } |
| 760 | 594 | ||
| 761 | - /** | ||
| 762 | - * 动态参数补全SQL | ||
| 763 | - */ | ||
| 764 | private Map<String, Object> applyValues(Map<String, Object> args, List<ParamRule> paramDefsCheck) { | 595 | private Map<String, Object> applyValues(Map<String, Object> args, List<ParamRule> paramDefsCheck) { |
| 765 | Map<String, Object> result = new HashMap<>(args); | 596 | Map<String, Object> result = new HashMap<>(args); |
| 766 | result = transformationArgs( result, paramDefsCheck); | 597 | result = transformationArgs( result, paramDefsCheck); |
| 767 | - //根据iOrder 排序 | ||
| 768 | List<ParamRule> paramDefs = new ArrayList<>(paramDefsCheck); | 598 | List<ParamRule> paramDefs = new ArrayList<>(paramDefsCheck); |
| 769 | paramDefs.sort(Comparator.comparing(ParamRule::getIOrder)); | 599 | paramDefs.sort(Comparator.comparing(ParamRule::getIOrder)); |
| 770 | for (ParamRule pd : paramDefs) { | 600 | for (ParamRule pd : paramDefs) { |
| @@ -777,38 +607,30 @@ public class DynamicToolProvider implements ToolProvider { | @@ -777,38 +607,30 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 777 | bCheck = bCheck && ObjectUtil.isNotEmpty(result.get(name)); | 607 | bCheck = bCheck && ObjectUtil.isNotEmpty(result.get(name)); |
| 778 | bCheck = bCheck && RuleCode.SQL.getCode().equals(sRule); | 608 | bCheck = bCheck && RuleCode.SQL.getCode().equals(sRule); |
| 779 | bCheck = bCheck && ObjectUtil.isNotEmpty(pd.getSParamConfig()); | 609 | bCheck = bCheck && ObjectUtil.isNotEmpty(pd.getSParamConfig()); |
| 780 | -// bCheck = bCheck && !"array".equals(sType); | ||
| 781 | 610 | ||
| 782 | Boolean bCheck2 = result.containsKey(sValue); | 611 | Boolean bCheck2 = result.containsKey(sValue); |
| 783 | bCheck2 = bCheck2 && ObjectUtil.isNotEmpty(result.get(sValue)); | 612 | bCheck2 = bCheck2 && ObjectUtil.isNotEmpty(result.get(sValue)); |
| 784 | bCheck2 = bCheck2 && RuleCode.SQL.getCode().equals(sRule); | 613 | bCheck2 = bCheck2 && RuleCode.SQL.getCode().equals(sRule); |
| 785 | bCheck2 = bCheck2 && ObjectUtil.isNotEmpty(pd.getSParamConfig()); | 614 | bCheck2 = bCheck2 && ObjectUtil.isNotEmpty(pd.getSParamConfig()); |
| 786 | -// bCheck2 = bCheck2 && !"array".equals(sType); | ||
| 787 | - //存在动态SQL 并且是枚举的需要 | 615 | + |
| 788 | if ((bCheck || bCheck2) &&("enum".equals(sType) || "string".equals(sType))){ | 616 | if ((bCheck || bCheck2) &&("enum".equals(sType) || "string".equals(sType))){ |
| 789 | String sSql = pd.getSParamConfig(); | 617 | String sSql = pd.getSParamConfig(); |
| 790 | String sKey = bCheck?name:sValue; | 618 | String sKey = bCheck?name:sValue; |
| 791 | String nameValue = result.get(sKey).toString(); | 619 | String nameValue = result.get(sKey).toString(); |
| 792 | List<Map<String,Object>> dataList = dynamicExeDbService.findSql(result,sSql); | 620 | List<Map<String,Object>> dataList = dynamicExeDbService.findSql(result,sSql); |
| 793 | - //传入的参数无效返回继续盘问消息 | ||
| 794 | if(ObjectUtil.isEmpty(dataList)){ | 621 | if(ObjectUtil.isEmpty(dataList)){ |
| 795 | throw new BusinessException(ErrorCode.PARAM_REQUIRED,String.format("%s 您描述的%s 不存在,请重新告诉我",name,nameValue)); | 622 | throw new BusinessException(ErrorCode.PARAM_REQUIRED,String.format("%s 您描述的%s 不存在,请重新告诉我",name,nameValue)); |
| 796 | } | 623 | } |
| 797 | - //如果SQL没有条件 多个数据集中进行匹配 如果只匹配一个也算成功 | ||
| 798 | if(ObjectUtil.isNotEmpty(args.get(name)) || ObjectUtil.isNotEmpty(args.get(sValue))){ | 624 | if(ObjectUtil.isNotEmpty(args.get(name)) || ObjectUtil.isNotEmpty(args.get(sValue))){ |
| 799 | if(("enum".equals(sType) ||"string".equals(sType)) && (args.get(name) instanceof List || args.get(sValue) instanceof List)){ | 625 | if(("enum".equals(sType) ||"string".equals(sType)) && (args.get(name) instanceof List || args.get(sValue) instanceof List)){ |
| 800 | - //枚举返回了数组 纠正成字符串 | ||
| 801 | if(args.get(name) instanceof List){ | 626 | if(args.get(name) instanceof List){ |
| 802 | args.put(name,((List<?>) args.get(name)).get(0)); | 627 | args.put(name,((List<?>) args.get(name)).get(0)); |
| 803 | -// args.put(sValue,((List<?>) args.get(name)).get(0)); | ||
| 804 | } | 628 | } |
| 805 | if(args.get(sValue) instanceof List){ | 629 | if(args.get(sValue) instanceof List){ |
| 806 | args.put(sValue,((List<?>) args.get(sValue)).get(0)); | 630 | args.put(sValue,((List<?>) args.get(sValue)).get(0)); |
| 807 | -// args.put(name,((List<?>) args.get(sValue)).get(0)); | ||
| 808 | } | 631 | } |
| 809 | } | 632 | } |
| 810 | List<Map<String,Object>> dataListNew = dataList.stream().filter(one-> one.get(sValue).equals(args.get(name)) || one.get(sValue).equals(args.get(sValue))).collect(Collectors.toUnmodifiableList()); | 633 | List<Map<String,Object>> dataListNew = dataList.stream().filter(one-> one.get(sValue).equals(args.get(name)) || one.get(sValue).equals(args.get(sValue))).collect(Collectors.toUnmodifiableList()); |
| 811 | - //如果枚举类型枚举值中又不存在AI 返回的数据 | ||
| 812 | if("enum".equals(sType) && ObjectUtil.isEmpty(dataListNew)){ | 634 | if("enum".equals(sType) && ObjectUtil.isEmpty(dataListNew)){ |
| 813 | args.remove(name); | 635 | args.remove(name); |
| 814 | args.remove(sValue); | 636 | args.remove(sValue); |
| @@ -827,7 +649,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -827,7 +649,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 827 | result.put(sValue, dataList.get(0).get(sValue)); | 649 | result.put(sValue, dataList.get(0).get(sValue)); |
| 828 | result.put(name, dataList.get(0).get(sValue)); | 650 | result.put(name, dataList.get(0).get(sValue)); |
| 829 | }else{ | 651 | }else{ |
| 830 | - //赋值到 | ||
| 831 | String[] sCopyToA = sCopyTo.split(","); | 652 | String[] sCopyToA = sCopyTo.split(","); |
| 832 | for(String sCopyToOne:sCopyToA){ | 653 | for(String sCopyToOne:sCopyToA){ |
| 833 | String[] sCopyToOneA = sCopyToOne.split(":"); | 654 | String[] sCopyToOneA = sCopyToOne.split(":"); |
| @@ -836,7 +657,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -836,7 +657,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 836 | } | 657 | } |
| 837 | } | 658 | } |
| 838 | StringBuffer sData=new StringBuffer(); | 659 | StringBuffer sData=new StringBuffer(); |
| 839 | - //存在多个形成提示语 | ||
| 840 | if(dataList.size()>1){ | 660 | if(dataList.size()>1){ |
| 841 | List<Map<String, Object>> finalDataList = dataList; | 661 | List<Map<String, Object>> finalDataList = dataList; |
| 842 | IntStream.range(0, dataList.size()) | 662 | IntStream.range(0, dataList.size()) |
| @@ -858,17 +678,12 @@ public class DynamicToolProvider implements ToolProvider { | @@ -858,17 +678,12 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 858 | return result; | 678 | return result; |
| 859 | } | 679 | } |
| 860 | 680 | ||
| 861 | - /** | ||
| 862 | - * 应用参数的默认值 | ||
| 863 | - */ | ||
| 864 | private Map<String, Object> applyDefaultValues(Map<String, Object> args, List<ParamRule> paramDefs) { | 681 | private Map<String, Object> applyDefaultValues(Map<String, Object> args, List<ParamRule> paramDefs) { |
| 865 | Map<String, Object> result = new HashMap<>(args); | 682 | Map<String, Object> result = new HashMap<>(args); |
| 866 | for (ParamRule pd : paramDefs) { | 683 | for (ParamRule pd : paramDefs) { |
| 867 | String name = pd.getSParam(); | 684 | String name = pd.getSParam(); |
| 868 | if ((!result.containsKey(name)|| ObjectUtil.isEmpty(result.get(name))) | 685 | if ((!result.containsKey(name)|| ObjectUtil.isEmpty(result.get(name))) |
| 869 | && ObjectUtil.isNotEmpty(pd.getSDefaultValue()) | 686 | && ObjectUtil.isNotEmpty(pd.getSDefaultValue()) |
| 870 | -// && !"enum".equals(pd.getSType()) | ||
| 871 | -// && !"array".equals(pd.getSType()) | ||
| 872 | ) { | 687 | ) { |
| 873 | Object defaultValue = pd.getSDefaultValue(); | 688 | Object defaultValue = pd.getSDefaultValue(); |
| 874 | result.put(name, defaultValue); | 689 | result.put(name, defaultValue); |
| @@ -876,18 +691,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -876,18 +691,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 876 | } | 691 | } |
| 877 | return result; | 692 | return result; |
| 878 | } | 693 | } |
| 879 | - /** | ||
| 880 | - * 检查必填参数 | ||
| 881 | - */ | ||
| 882 | - private List<String> getRequiredParams(List<ParamRule> paramDefs) { | ||
| 883 | - return paramDefs.stream() | ||
| 884 | - .map(ParamRule::getSParam) | ||
| 885 | - .toList(); | ||
| 886 | - } | ||
| 887 | 694 | ||
| 888 | - /** | ||
| 889 | - * 检查必填参数 | ||
| 890 | - */ | ||
| 891 | private List<String> checkRequiredParams(Map<String, Object> args, List<ParamRule> paramDefs) { | 695 | private List<String> checkRequiredParams(Map<String, Object> args, List<ParamRule> paramDefs) { |
| 892 | Map<String,Object> returnMap = transformationArgs( args, paramDefs); | 696 | Map<String,Object> returnMap = transformationArgs( args, paramDefs); |
| 893 | return paramDefs.stream() | 697 | return paramDefs.stream() |
| @@ -915,10 +719,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -915,10 +719,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 915 | return bDbZero || bBhcs || (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))); | 719 | return bDbZero || bBhcs || (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))); |
| 916 | } | 720 | } |
| 917 | 721 | ||
| 918 | - | ||
| 919 | - /** | ||
| 920 | - * 确认后必填参数 | ||
| 921 | - */ | ||
| 922 | private List<String> checkConfirmAfterParam(Map<String, Object> args, List<ParamRule> paramDefs) { | 722 | private List<String> checkConfirmAfterParam(Map<String, Object> args, List<ParamRule> paramDefs) { |
| 923 | Map<String,Object> returnMap = transformationArgs( args, paramDefs); | 723 | Map<String,Object> returnMap = transformationArgs( args, paramDefs); |
| 924 | return paramDefs.stream() | 724 | return paramDefs.stream() |
| @@ -931,13 +731,8 @@ public class DynamicToolProvider implements ToolProvider { | @@ -931,13 +731,8 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 931 | .toList(); | 731 | .toList(); |
| 932 | } | 732 | } |
| 933 | 733 | ||
| 934 | - | ||
| 935 | - /** | ||
| 936 | - * 模拟执行工具 | ||
| 937 | - */ | ||
| 938 | public String executeTool(ToolMeta meta, Map<String, Object> args, List<ParamRule> paramRuleData,String userId,UserSceneSession session ) { | 734 | public String executeTool(ToolMeta meta, Map<String, Object> args, List<ParamRule> paramRuleData,String userId,UserSceneSession session ) { |
| 939 | log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); | 735 | log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); |
| 940 | - // 2.2 将中文key转换成英文key | ||
| 941 | args = transformationArgs( args, paramRuleData); | 736 | args = transformationArgs( args, paramRuleData); |
| 942 | String sReturn ="执行成功"; | 737 | String sReturn ="执行成功"; |
| 943 | try{ | 738 | try{ |
| @@ -951,100 +746,86 @@ public class DynamicToolProvider implements ToolProvider { | @@ -951,100 +746,86 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 951 | session.setBCleanMemory(true); | 746 | session.setBCleanMemory(true); |
| 952 | } | 747 | } |
| 953 | return sReturn; | 748 | return sReturn; |
| 954 | - | ||
| 955 | } | 749 | } |
| 956 | - /**** | ||
| 957 | - * @Author 钱豹 | ||
| 958 | - * @Date 10:26 2026/2/1 | ||
| 959 | - * @Param | ||
| 960 | - * @return | ||
| 961 | - * @Description 返回结果后 执行业务类 | ||
| 962 | - **/ | 750 | + |
| 963 | private String executeToolAfter(ToolMeta meta, Map<String, Object> args,List<ParamRule> paramDefs,UserSceneSession session) { | 751 | private String executeToolAfter(ToolMeta meta, Map<String, Object> args,List<ParamRule> paramDefs,UserSceneSession session) { |
| 964 | -// {"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | ||
| 965 | - String sBizContent = meta.getSBizContent(); | ||
| 966 | - Integer iBizType = meta.getIBizType(); | ||
| 967 | - args.put("sUserId", session.getUserId()); | ||
| 968 | - args.put("sLoginId", session.getUserName()); | ||
| 969 | - args.put("sMakePerson", session.getUserName()); | ||
| 970 | - args.put("sBrId", session.getSBrandsId()); | ||
| 971 | - args.put("sBrandsId", session.getSBrandsId()); | ||
| 972 | - args.put("sSuId", session.getSSubsidiaryId()); | ||
| 973 | - args.put("sSrcFormId", meta.getSSrcFormId()); | ||
| 974 | - args.put("sControlName", meta.getSControlName()); | ||
| 975 | - args.put("iBizType", iBizType); | ||
| 976 | - args.put("sSubsidiaryId", session.getSSubsidiaryId()); | ||
| 977 | - args.put("sToolId", meta.getSId()); | ||
| 978 | - if (iBizType == 1 || iBizType == 4) { | ||
| 979 | - Map<String, Object> data = new HashMap<>(args); | ||
| 980 | - data.put("sData", JSONObject.toJSONString((data))); | ||
| 981 | - if(ObjectUtil.isEmpty(sBizContent) && iBizType == 4){ | ||
| 982 | - sBizContent ="Sp_Ai_AddCommonAfterNew"; | ||
| 983 | - //获取未清数据 | ||
| 984 | - if(ObjectUtil.isEmpty(args.get("sSlaveId"))){ | ||
| 985 | - throw new BusinessException(-1,"请选择操作数据"); | ||
| 986 | - } | ||
| 987 | - List<Map<String,Object>> sRowData = doGetFromDataWq( meta, args, session); | ||
| 988 | - data.put("sRowData", JSONObject.toJSONString(sRowData)); | ||
| 989 | - } | ||
| 990 | - Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data); | ||
| 991 | - Map<String, Object> sReturn = this.dynamicExeDbService.getCallPro(searMap, sBizContent); | ||
| 992 | - Integer sCode = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SCODE)) ? Integer.valueOf(sReturn.get(ProcedureConstant.SCODE).toString()) : 0; | ||
| 993 | - String sMsgText = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SRETURN)) ? sReturn.get(ProcedureConstant.SRETURN).toString() : "操作成功"; | ||
| 994 | - if (sCode < 0) { | ||
| 995 | - sMsgText = ObjectUtil.isEmpty(sMsgText) ? "调用过程sCode:" + Integer.valueOf(searMap.get(ProcedureConstant.SCODE).toString()) : sMsgText; | ||
| 996 | - session.setSFunPrompts(sMsgText); | ||
| 997 | - throw new BusinessException(sCode,sMsgText); | ||
| 998 | - } | ||
| 999 | - Map<String,Object> outMap = (Map<String, Object>) sReturn.get("outMap"); | ||
| 1000 | - String sId = ObjectUtil.isNotEmpty(outMap.get("sBillId")) ? outMap.get("sBillId").toString() : ""; | ||
| 1001 | - session.setSCopyTo(meta.getSControlName()); | ||
| 1002 | - session.setSCopyToSrcId(sId); | ||
| 1003 | - session.setSFunPrompts(sMsgText); | ||
| 1004 | - return sMsgText; | ||
| 1005 | - } else if (iBizType == 2 && ObjectUtil.isNotEmpty(sBizContent)) { | ||
| 1006 | - //SQL查询 | ||
| 1007 | - if (sBizContent.toLowerCase().startsWith("update")) { | ||
| 1008 | - this.dynamicExeDbService.updateSql(args, sBizContent); | ||
| 1009 | - } else if (sBizContent.toLowerCase().startsWith("delete")) { | ||
| 1010 | - this.dynamicExeDbService.delSql(args, sBizContent); | ||
| 1011 | - } else if (sBizContent.toLowerCase().startsWith("insert")) { | ||
| 1012 | - this.dynamicExeDbService.addSql(args, sBizContent); | ||
| 1013 | - } else { | ||
| 1014 | - List<Map<String, Object>> retData = this.dynamicExeDbService.findSql(args, sBizContent); | ||
| 1015 | - if (ObjectUtil.isNotEmpty(retData)) { | ||
| 1016 | - StringBuffer sb = new StringBuffer(); | ||
| 1017 | - retData.forEach(one -> { | ||
| 1018 | - one.forEach((k, v) -> { | ||
| 1019 | - sb.append(v).append(" "); | ||
| 1020 | - }); | ||
| 1021 | - sb.append("<br/>"); | ||
| 1022 | - }); | ||
| 1023 | - if (ObjectUtil.isNotEmpty(retData)) { | ||
| 1024 | - sb.append("请根据这些信息安排今天的工作吧!如果有具体任务需要进一步处理,请告诉我"); | ||
| 1025 | - } | ||
| 1026 | - session.setSFunPrompts(sb.toString()); | ||
| 1027 | - if ("queryTodayTask".equals(meta.getSMethodNo())) { | ||
| 1028 | - session.setBCleanMemory(true); | ||
| 1029 | - } | ||
| 1030 | - return sb.toString(); | ||
| 1031 | - } else { | ||
| 1032 | - String sMsgText = "未找到对应的数据"; | ||
| 1033 | - session.setSFunPrompts(sMsgText); | ||
| 1034 | - throw new BusinessException(-1,sMsgText); | ||
| 1035 | - } | ||
| 1036 | - } | ||
| 1037 | - } else if (iBizType == 3) { | ||
| 1038 | - return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), | ||
| 1039 | - new HashMap<>(), "POST", "JSON"); | ||
| 1040 | - } | ||
| 1041 | - return "操作成功"; | 752 | + String sBizContent = meta.getSBizContent(); |
| 753 | + Integer iBizType = meta.getIBizType(); | ||
| 754 | + args.put("sUserId", session.getUserId()); | ||
| 755 | + args.put("sLoginId", session.getUserName()); | ||
| 756 | + args.put("sMakePerson", session.getUserName()); | ||
| 757 | + args.put("sBrId", session.getSBrandsId()); | ||
| 758 | + args.put("sBrandsId", session.getSBrandsId()); | ||
| 759 | + args.put("sSuId", session.getSSubsidiaryId()); | ||
| 760 | + args.put("sSrcFormId", meta.getSSrcFormId()); | ||
| 761 | + args.put("sControlName", meta.getSControlName()); | ||
| 762 | + args.put("iBizType", iBizType); | ||
| 763 | + args.put("sSubsidiaryId", session.getSSubsidiaryId()); | ||
| 764 | + args.put("sToolId", meta.getSId()); | ||
| 765 | + if (iBizType == 1 || iBizType == 4) { | ||
| 766 | + Map<String, Object> data = new HashMap<>(args); | ||
| 767 | + data.put("sData", JSONObject.toJSONString((data))); | ||
| 768 | + if(ObjectUtil.isEmpty(sBizContent) && iBizType == 4){ | ||
| 769 | + sBizContent ="Sp_Ai_AddCommonAfterNew"; | ||
| 770 | + if(ObjectUtil.isEmpty(args.get("sSlaveId"))){ | ||
| 771 | + throw new BusinessException(-1,"请选择操作数据"); | ||
| 772 | + } | ||
| 773 | + List<Map<String,Object>> sRowData = doGetFromDataWq( meta, args, session); | ||
| 774 | + data.put("sRowData", JSONObject.toJSONString(sRowData)); | ||
| 775 | + } | ||
| 776 | + Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data); | ||
| 777 | + Map<String, Object> sReturn = this.dynamicExeDbService.getCallPro(searMap, sBizContent); | ||
| 778 | + Integer sCode = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SCODE)) ? Integer.valueOf(sReturn.get(ProcedureConstant.SCODE).toString()) : 0; | ||
| 779 | + String sMsgText = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SRETURN)) ? sReturn.get(ProcedureConstant.SRETURN).toString() : "操作成功"; | ||
| 780 | + if (sCode < 0) { | ||
| 781 | + sMsgText = ObjectUtil.isEmpty(sMsgText) ? "调用过程sCode:" + Integer.valueOf(searMap.get(ProcedureConstant.SCODE).toString()) : sMsgText; | ||
| 782 | + session.setSFunPrompts(sMsgText); | ||
| 783 | + throw new BusinessException(sCode,sMsgText); | ||
| 784 | + } | ||
| 785 | + Map<String,Object> outMap = (Map<String, Object>) sReturn.get("outMap"); | ||
| 786 | + String sId = ObjectUtil.isNotEmpty(outMap.get("sBillId")) ? outMap.get("sBillId").toString() : ""; | ||
| 787 | + session.setSCopyTo(meta.getSControlName()); | ||
| 788 | + session.setSCopyToSrcId(sId); | ||
| 789 | + session.setSFunPrompts(sMsgText); | ||
| 790 | + return sMsgText; | ||
| 791 | + } else if (iBizType == 2 && ObjectUtil.isNotEmpty(sBizContent)) { | ||
| 792 | + if (sBizContent.toLowerCase().startsWith("update")) { | ||
| 793 | + this.dynamicExeDbService.updateSql(args, sBizContent); | ||
| 794 | + } else if (sBizContent.toLowerCase().startsWith("delete")) { | ||
| 795 | + this.dynamicExeDbService.delSql(args, sBizContent); | ||
| 796 | + } else if (sBizContent.toLowerCase().startsWith("insert")) { | ||
| 797 | + this.dynamicExeDbService.addSql(args, sBizContent); | ||
| 798 | + } else { | ||
| 799 | + List<Map<String, Object>> retData = this.dynamicExeDbService.findSql(args, sBizContent); | ||
| 800 | + if (ObjectUtil.isNotEmpty(retData)) { | ||
| 801 | + StringBuffer sb = new StringBuffer(); | ||
| 802 | + retData.forEach(one -> { | ||
| 803 | + one.forEach((k, v) -> { | ||
| 804 | + sb.append(v).append(" "); | ||
| 805 | + }); | ||
| 806 | + sb.append("<br/>"); | ||
| 807 | + }); | ||
| 808 | + if (ObjectUtil.isNotEmpty(retData)) { | ||
| 809 | + sb.append("请根据这些信息安排今天的工作吧!如果有具体任务需要进一步处理,请告诉我"); | ||
| 810 | + } | ||
| 811 | + session.setSFunPrompts(sb.toString()); | ||
| 812 | + if ("queryTodayTask".equals(meta.getSMethodNo())) { | ||
| 813 | + session.setBCleanMemory(true); | ||
| 814 | + } | ||
| 815 | + return sb.toString(); | ||
| 816 | + } else { | ||
| 817 | + String sMsgText = "未找到对应的数据"; | ||
| 818 | + session.setSFunPrompts(sMsgText); | ||
| 819 | + throw new BusinessException(-1,sMsgText); | ||
| 820 | + } | ||
| 821 | + } | ||
| 822 | + } else if (iBizType == 3) { | ||
| 823 | + return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), | ||
| 824 | + new HashMap<>(), "POST", "JSON"); | ||
| 825 | + } | ||
| 826 | + return "操作成功"; | ||
| 1042 | } | 827 | } |
| 1043 | 828 | ||
| 1044 | - /*** | ||
| 1045 | - * @Author | ||
| 1046 | - * 确认获取未清数据 | ||
| 1047 | - **/ | ||
| 1048 | private List<Map<String,Object>> doGetFromDataWq(ToolMeta meta, Map<String, Object> args,UserSceneSession session){ | 829 | private List<Map<String,Object>> doGetFromDataWq(ToolMeta meta, Map<String, Object> args,UserSceneSession session){ |
| 1049 | String sUrl = meta.getSendUrl(); | 830 | String sUrl = meta.getSendUrl(); |
| 1050 | Map<String,Object> sBody = new HashMap<>(); | 831 | Map<String,Object> sBody = new HashMap<>(); |
| @@ -1064,13 +845,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1064,13 +845,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1064 | headers.put("Authorization",session.getAuthorization()); | 845 | headers.put("Authorization",session.getAuthorization()); |
| 1065 | String result; | 846 | String result; |
| 1066 | try{ | 847 | try{ |
| 1067 | - // 1. 获取实例 | ||
| 1068 | result = HttpsRequestUtil.me().doRequestHttp(sUrl,JSONObject.toJSONString(sBody),headers,"POST","JSON"); | 848 | result = HttpsRequestUtil.me().doRequestHttp(sUrl,JSONObject.toJSONString(sBody),headers,"POST","JSON"); |
| 1069 | log.info("请求URL========================{}", sUrl); | 849 | log.info("请求URL========================{}", sUrl); |
| 1070 | log.info("请求URLresult========================{}", result); | 850 | log.info("请求URLresult========================{}", result); |
| 1071 | - log.info("JSON==========================={}", JSONObject.toJSONString(sBody)); | ||
| 1072 | - log.info("headers=============================={}", JSONObject.toJSONString(headers)); | ||
| 1073 | - log.info("请求URL,JSON,headers=={},{},{}",sUrl,JSONObject.toJSONString(sBody),JSONObject.toJSONString(headers)); | ||
| 1074 | ErpResult erpResult = JsonUtils.toObject(result,ErpResult.class); | 851 | ErpResult erpResult = JsonUtils.toObject(result,ErpResult.class); |
| 1075 | if(ObjectUtil.isNotEmpty(erpResult) | 852 | if(ObjectUtil.isNotEmpty(erpResult) |
| 1076 | && ObjectUtil.isNotEmpty(erpResult.getDataset()) | 853 | && ObjectUtil.isNotEmpty(erpResult.getDataset()) |
| @@ -1081,19 +858,10 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1081,19 +858,10 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1081 | return erpResult.getDataset().getRows().get(0).getDataSet(); | 858 | return erpResult.getDataset().getRows().get(0).getDataSet(); |
| 1082 | } | 859 | } |
| 1083 | }catch (Exception e){ | 860 | }catch (Exception e){ |
| 1084 | -// result ="执行异常:"+e.getMessage(); | ||
| 1085 | } | 861 | } |
| 1086 | return new ArrayList<>(); | 862 | return new ArrayList<>(); |
| 1087 | } | 863 | } |
| 1088 | 864 | ||
| 1089 | - | ||
| 1090 | - /*** | ||
| 1091 | - * @Author 钱豹 | ||
| 1092 | - * @Date 23:38 2026/2/5 | ||
| 1093 | - * @Param [] | ||
| 1094 | - * @return void | ||
| 1095 | - * @Description 窗体获取数据方法 未清或者明细 | ||
| 1096 | - **/ | ||
| 1097 | private String doGetFromData(ToolMeta meta, Map<String, Object> args,UserSceneSession session){ | 865 | private String doGetFromData(ToolMeta meta, Map<String, Object> args,UserSceneSession session){ |
| 1098 | String sUrl = meta.getSendUrl(); | 866 | String sUrl = meta.getSendUrl(); |
| 1099 | Map<String,Object> sBody = new HashMap<>(); | 867 | Map<String,Object> sBody = new HashMap<>(); |
| @@ -1101,7 +869,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1101,7 +869,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1101 | sBody.put("pageSize",10000); | 869 | sBody.put("pageSize",10000); |
| 1102 | log.info("doGetFromData========================"); | 870 | log.info("doGetFromData========================"); |
| 1103 | List<Map<String,Object>> list = new ArrayList<>(); | 871 | List<Map<String,Object>> list = new ArrayList<>(); |
| 1104 | - //移除确认标识 | ||
| 1105 | args.remove("operateType"); | 872 | args.remove("operateType"); |
| 1106 | if(ObjectUtil.isNotEmpty(args)){ | 873 | if(ObjectUtil.isNotEmpty(args)){ |
| 1107 | List<ParamRule> paramDefs = meta.getParamRuleList(); | 874 | List<ParamRule> paramDefs = meta.getParamRuleList(); |
| @@ -1140,13 +907,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1140,13 +907,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1140 | headers.put("Authorization",session.getAuthorization()); | 907 | headers.put("Authorization",session.getAuthorization()); |
| 1141 | String result; | 908 | String result; |
| 1142 | try{ | 909 | try{ |
| 1143 | - // 1. 获取实例 | ||
| 1144 | result = HttpsRequestUtil.me().doRequestHttp(sUrl,JSONObject.toJSONString(sBody),headers,"POST","JSON"); | 910 | result = HttpsRequestUtil.me().doRequestHttp(sUrl,JSONObject.toJSONString(sBody),headers,"POST","JSON"); |
| 1145 | log.info("请求URL========================{}", sUrl); | 911 | log.info("请求URL========================{}", sUrl); |
| 1146 | log.info("请求URLresult========================{}", result); | 912 | log.info("请求URLresult========================{}", result); |
| 1147 | - log.info("JSON==========================={}", JSONObject.toJSONString(sBody)); | ||
| 1148 | - log.info("headers=============================={}", JSONObject.toJSONString(headers)); | ||
| 1149 | - log.info("请求URL,JSON,headers=={},{},{}",sUrl,JSONObject.toJSONString(sBody),JSONObject.toJSONString(headers)); | ||
| 1150 | ErpResult erpResult = JsonUtils.toObject(result,ErpResult.class); | 913 | ErpResult erpResult = JsonUtils.toObject(result,ErpResult.class); |
| 1151 | result = buildResultMessageWithTable( meta, erpResult, session); | 914 | result = buildResultMessageWithTable( meta, erpResult, session); |
| 1152 | }catch (Exception e){ | 915 | }catch (Exception e){ |
| @@ -1155,13 +918,9 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1155,13 +918,9 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1155 | return result; | 918 | return result; |
| 1156 | } | 919 | } |
| 1157 | 920 | ||
| 1158 | - /** | ||
| 1159 | - * 构建 窗体获取数据方法 未清或者明细 | ||
| 1160 | - */ | ||
| 1161 | public String buildResultMessageWithTable(ToolMeta meta,ErpResult erpResult,UserSceneSession session){ | 921 | public String buildResultMessageWithTable(ToolMeta meta,ErpResult erpResult,UserSceneSession session){ |
| 1162 | Map<Integer,Map<String,Object>> currentRowData = new HashMap<>(); | 922 | Map<Integer,Map<String,Object>> currentRowData = new HashMap<>(); |
| 1163 | ErpDataset dataset = erpResult.getDataset(); | 923 | ErpDataset dataset = erpResult.getDataset(); |
| 1164 | - //返回错误信息 | ||
| 1165 | if(erpResult.getCode()<0 && ObjectUtil.isNotEmpty(erpResult.getMsg())){ | 924 | if(erpResult.getCode()<0 && ObjectUtil.isNotEmpty(erpResult.getMsg())){ |
| 1166 | return erpResult.getMsg(); | 925 | return erpResult.getMsg(); |
| 1167 | } | 926 | } |
| @@ -1175,7 +934,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1175,7 +934,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1175 | } | 934 | } |
| 1176 | List<Map<String, Object>> recordData = findFieldNameByChinese(sAIshowfieldShow, rows); | 935 | List<Map<String, Object>> recordData = findFieldNameByChinese(sAIshowfieldShow, rows); |
| 1177 | int recordCount = dataset != null ? dataset.getTotalCount() : 0; | 936 | int recordCount = dataset != null ? dataset.getTotalCount() : 0; |
| 1178 | - // 动态生成表头 | ||
| 1179 | Set<String> headers = new LinkedHashSet<>(); | 937 | Set<String> headers = new LinkedHashSet<>(); |
| 1180 | for (Map<String, Object> record : sAIshowfieldShow) { | 938 | for (Map<String, Object> record : sAIshowfieldShow) { |
| 1181 | String chineseName = (String) record.get("label"); | 939 | String chineseName = (String) record.get("label"); |
| @@ -1185,7 +943,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1185,7 +943,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1185 | } | 943 | } |
| 1186 | 944 | ||
| 1187 | StringBuilder markdown = new StringBuilder(); | 945 | StringBuilder markdown = new StringBuilder(); |
| 1188 | - //状态 | ||
| 1189 | if(ObjectUtil.isNotEmpty(session.getArgs())){ | 946 | if(ObjectUtil.isNotEmpty(session.getArgs())){ |
| 1190 | markdown.append("**查询条件**:"); | 947 | markdown.append("**查询条件**:"); |
| 1191 | List<ParamRule> pr = session.getCurrentTool().getParamRuleListCheck(); | 948 | List<ParamRule> pr = session.getCurrentTool().getParamRuleListCheck(); |
| @@ -1205,7 +962,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1205,7 +962,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1205 | .append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" ") | 962 | .append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" ") |
| 1206 | .append(" <span style=\"font-weight: bold;font-size: 22px;position: absolute;right: -5px;top: -12px;color: #ff4d4f;display: inline-block;\" data-action=\"clearSql\" data-text=\""+one.getSParam()+","+one.getSParamValue()+"\" onclick=\"clearSql('"+one.getSParam()+","+one.getSParamValue()+"')\"> × </span>") | 963 | .append(" <span style=\"font-weight: bold;font-size: 22px;position: absolute;right: -5px;top: -12px;color: #ff4d4f;display: inline-block;\" data-action=\"clearSql\" data-text=\""+one.getSParam()+","+one.getSParamValue()+"\" onclick=\"clearSql('"+one.getSParam()+","+one.getSParamValue()+"')\"> × </span>") |
| 1207 | .append("</span>"); | 964 | .append("</span>"); |
| 1208 | -// markdown.append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" "); | ||
| 1209 | } | 965 | } |
| 1210 | } | 966 | } |
| 1211 | } | 967 | } |
| @@ -1225,39 +981,29 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1225,39 +981,29 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1225 | markdown.append(",显示前").append(rows.size()).append("条。如需查看全部,请指定筛选条件。"); | 981 | markdown.append(",显示前").append(rows.size()).append("条。如需查看全部,请指定筛选条件。"); |
| 1226 | } | 982 | } |
| 1227 | } | 983 | } |
| 1228 | -// markdown.append("\n---\n"); | ||
| 1229 | markdown.append("\n\n").append("| 序号 | "); | 984 | markdown.append("\n\n").append("| 序号 | "); |
| 1230 | headers.forEach(header -> markdown.append(header).append(" | ")); | 985 | headers.forEach(header -> markdown.append(header).append(" | ")); |
| 1231 | markdown.append("\n|").append("---|".repeat(headers.size() + 1)).append("\n"); | 986 | markdown.append("\n|").append("---|".repeat(headers.size() + 1)).append("\n"); |
| 1232 | - // 填充表格数据 | ||
| 1233 | List<Map<String,Object>> machineData = new LinkedList<>(); | 987 | List<Map<String,Object>> machineData = new LinkedList<>(); |
| 1234 | for (int i = 0; i < recordData.size(); i++) { | 988 | for (int i = 0; i < recordData.size(); i++) { |
| 1235 | - // 保存隐藏列的值(如"唯一"字段) | ||
| 1236 | String uniqueValue = recordData.get(i).get("sSlaveId") != null ? recordData.get(i).get("sSlaveId").toString() : ""; | 989 | String uniqueValue = recordData.get(i).get("sSlaveId") != null ? recordData.get(i).get("sSlaveId").toString() : ""; |
| 1237 | markdown.append("| ").append(i + 1).append(" | "); | 990 | markdown.append("| ").append(i + 1).append(" | "); |
| 1238 | Map<String,Object> rMap = new HashMap<>(); | 991 | Map<String,Object> rMap = new HashMap<>(); |
| 1239 | for (String header : headers) { | 992 | for (String header : headers) { |
| 1240 | - // 这里需要根据你的数据结构来获取对应的值 | ||
| 1241 | Object value = recordData.get(i)!= null ? recordData.get(i).get(header) : null; | 993 | Object value = recordData.get(i)!= null ? recordData.get(i).get(header) : null; |
| 1242 | markdown.append(value != null ? value : "—").append(" | "); | 994 | markdown.append(value != null ? value : "—").append(" | "); |
| 1243 | rMap.put(header,value); | 995 | rMap.put(header,value); |
| 1244 | } | 996 | } |
| 1245 | rMap.put("sSlaveId",uniqueValue); | 997 | rMap.put("sSlaveId",uniqueValue); |
| 1246 | rMap.put("唯一",uniqueValue); | 998 | rMap.put("唯一",uniqueValue); |
| 1247 | - // 在行末添加隐藏数据的特殊标记(AI可以解析) | ||
| 1248 | markdown.append(" <span style=\"display:none;\">HIDDEN_DATA:") | 999 | markdown.append(" <span style=\"display:none;\">HIDDEN_DATA:") |
| 1249 | .append(JSONUtil.toJsonStr(rMap)) | 1000 | .append(JSONUtil.toJsonStr(rMap)) |
| 1250 | .append("</span>"); | 1001 | .append("</span>"); |
| 1251 | -// markdown.append(" <!-- HIDDEN_DATA:").append(JSONUtil.toJsonStr(rMap)).append("-->"); | ||
| 1252 | markdown.append("\n"); | 1002 | markdown.append("\n"); |
| 1253 | machineData.add(rMap); | 1003 | machineData.add(rMap); |
| 1254 | currentRowData.put(i + 1,recordData.get(i)); | 1004 | currentRowData.put(i + 1,recordData.get(i)); |
| 1255 | } | 1005 | } |
| 1256 | markdown.append(">"); | 1006 | markdown.append(">"); |
| 1257 | -// // 4. 机器可读的结构化数据(只出现一次!) | ||
| 1258 | -// markdown.append("<!-- MACHINE_DATA_START -->\n"); | ||
| 1259 | -// markdown.append(JSONUtil.toJsonStr(machineData)); | ||
| 1260 | -// markdown.append("\n<!-- MACHINE_DATA_END -->\n\n"); | ||
| 1261 | if(meta.getIBizType()==4){ | 1007 | if(meta.getIBizType()==4){ |
| 1262 | markdown.append("\n---\n"); | 1008 | markdown.append("\n---\n"); |
| 1263 | appendConfirmAll(markdown,meta.getSControlName()); | 1009 | appendConfirmAll(markdown,meta.getSControlName()); |
| @@ -1295,40 +1041,8 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1295,40 +1041,8 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1295 | } | 1041 | } |
| 1296 | """.formatted(rowJson, methodNo); | 1042 | """.formatted(rowJson, methodNo); |
| 1297 | } | 1043 | } |
| 1298 | -// public String buildDynamicSystemPrompt(UserSceneSession session) { | ||
| 1299 | -// // 动态获取当前工具方法号 | ||
| 1300 | -// String methodNo = session.getCurrentTool().getSMethodNo(); | ||
| 1301 | -// String promptHead = """ | ||
| 1302 | -// 【极强约束·必须执行】 | ||
| 1303 | -// 1. 禁止说话!禁止解释! | ||
| 1304 | -// 2. 必须调用工具,固定方法编号:MethodNo = %s | ||
| 1305 | -// 3. 只输出JSON,无任何其他内容 | ||
| 1306 | -// 以下是【行号 → sSlaveId】对应数据: | ||
| 1307 | -// """.formatted(methodNo); | ||
| 1308 | -// | ||
| 1309 | -// Map<Integer, Map<String, Object>> rowDataMap = session.getCurrentRowData(); | ||
| 1310 | -// StringBuilder rowDataSb = new StringBuilder(); | ||
| 1311 | -// if (ObjectUtil.isNotEmpty(rowDataMap)) { | ||
| 1312 | -// for (Map.Entry<Integer, Map<String, Object>> entry : rowDataMap.entrySet()) { | ||
| 1313 | -// int rowNum = entry.getKey(); | ||
| 1314 | -// String sSlaveId = StrUtil.toString(entry.getValue().get("sSlaveId")); | ||
| 1315 | -// rowDataSb.append("第").append(rowNum).append("行 → ").append(sSlaveId).append("\n"); | ||
| 1316 | -// } | ||
| 1317 | -// } | ||
| 1318 | -// String promptFoot = """ | ||
| 1319 | -// 【输出JSON格式·严格遵守】 | ||
| 1320 | -// 根据用户选择的行,自动填写 sSlaveId,多行用英文逗号拼接 | ||
| 1321 | -// { | ||
| 1322 | -// "operateType": "全部确认/合并确认/单行确认", | ||
| 1323 | -// "sSlaveId": "填写对应的ID,多个用逗号分隔" | ||
| 1324 | -// } | ||
| 1325 | -// """; | ||
| 1326 | -// return promptHead + rowDataSb + promptFoot; | ||
| 1327 | -// } | ||
| 1328 | - | ||
| 1329 | - // 辅助方法:根据中文名查找字段名(通过映射关系转换) | 1044 | + |
| 1330 | private List<Map<String, Object>> findFieldNameByChinese(List<Map<String, Object>> sAIshowfieldShow,List<Map<String, Object>> rows){ | 1045 | private List<Map<String, Object>> findFieldNameByChinese(List<Map<String, Object>> sAIshowfieldShow,List<Map<String, Object>> rows){ |
| 1331 | - //获取映射关系 | ||
| 1332 | Map<String,String> keyMappings = new HashMap<>(); | 1046 | Map<String,String> keyMappings = new HashMap<>(); |
| 1333 | List<String> selectedKeys = new ArrayList<>(); | 1047 | List<String> selectedKeys = new ArrayList<>(); |
| 1334 | sAIshowfieldShow.forEach(one->{ | 1048 | sAIshowfieldShow.forEach(one->{ |
| @@ -1342,13 +1056,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1342,13 +1056,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1342 | return sRowData; | 1056 | return sRowData; |
| 1343 | } | 1057 | } |
| 1344 | 1058 | ||
| 1345 | - /*** | ||
| 1346 | - * @Author 钱豹 | ||
| 1347 | - * @Date 2:04 2026/2/6 | ||
| 1348 | - * @Param [rows, limit, selectedKeys] | ||
| 1349 | - * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>> | ||
| 1350 | - * @Description 返回指定数量并筛选指定key | ||
| 1351 | - **/ | ||
| 1352 | public List<Map<String, Object>> getFilteredDataStream(List<Map<String, Object>> rows, | 1059 | public List<Map<String, Object>> getFilteredDataStream(List<Map<String, Object>> rows, |
| 1353 | int limit, | 1060 | int limit, |
| 1354 | List<String> selectedKeys, | 1061 | List<String> selectedKeys, |
| @@ -1357,13 +1064,11 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1357,13 +1064,11 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1357 | return Collections.emptyList(); | 1064 | return Collections.emptyList(); |
| 1358 | } | 1065 | } |
| 1359 | return rows.stream() | 1066 | return rows.stream() |
| 1360 | - .limit(limit) // 限制数量 | 1067 | + .limit(limit) |
| 1361 | .map(original -> { | 1068 | .map(original -> { |
| 1362 | - // 创建新的Map,只包含指定key | ||
| 1363 | Map<String, Object> filtered = new HashMap<>(); | 1069 | Map<String, Object> filtered = new HashMap<>(); |
| 1364 | selectedKeys.forEach(key -> { | 1070 | selectedKeys.forEach(key -> { |
| 1365 | if (original.containsKey(key)) { | 1071 | if (original.containsKey(key)) { |
| 1366 | - //指定映射的key 放中文 | ||
| 1367 | filtered.put(keyMappings.get(key), original.get(key)); | 1072 | filtered.put(keyMappings.get(key), original.get(key)); |
| 1368 | } | 1073 | } |
| 1369 | }); | 1074 | }); |
| @@ -1373,9 +1078,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1373,9 +1078,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1373 | .collect(Collectors.toList()); | 1078 | .collect(Collectors.toList()); |
| 1374 | } | 1079 | } |
| 1375 | 1080 | ||
| 1376 | - /** | ||
| 1377 | - * 构建确认操作消息 | ||
| 1378 | - */ | ||
| 1379 | private String buildConfirmUserMessage(ToolMeta meta, Map<String, Object> args) { | 1081 | private String buildConfirmUserMessage(ToolMeta meta, Map<String, Object> args) { |
| 1380 | StringBuilder markdown = new StringBuilder(); | 1082 | StringBuilder markdown = new StringBuilder(); |
| 1381 | markdown.append("参数提取如下:\n\n"); | 1083 | markdown.append("参数提取如下:\n\n"); |
| @@ -1390,11 +1092,6 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1390,11 +1092,6 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1390 | return markdown.toString(); | 1092 | return markdown.toString(); |
| 1391 | } | 1093 | } |
| 1392 | 1094 | ||
| 1393 | - | ||
| 1394 | - | ||
| 1395 | - /** | ||
| 1396 | - * 构建提问消息 | ||
| 1397 | - */ | ||
| 1398 | private String buildAskUserMessage(ToolMeta meta, List<String> missing,Map<String,Object> arg) { | 1095 | private String buildAskUserMessage(ToolMeta meta, List<String> missing,Map<String,Object> arg) { |
| 1399 | StringBuilder sb = new StringBuilder(); | 1096 | StringBuilder sb = new StringBuilder(); |
| 1400 | sb.append("缺少参数请补全:\n"); | 1097 | sb.append("缺少参数请补全:\n"); |
| @@ -1429,18 +1126,15 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1429,18 +1126,15 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1429 | return sb.toString(); | 1126 | return sb.toString(); |
| 1430 | } | 1127 | } |
| 1431 | 1128 | ||
| 1432 | - // 创建提前成功的结果 | ||
| 1433 | private String createEarlySuccessResult(ToolExecutionRequest request, String message) { | 1129 | private String createEarlySuccessResult(ToolExecutionRequest request, String message) { |
| 1434 | - // 设置一个标志,告诉执行器不要继续执行 | ||
| 1435 | return JSONUtil.toJsonStr(Map.of( | 1130 | return JSONUtil.toJsonStr(Map.of( |
| 1436 | "status", "success", | 1131 | "status", "success", |
| 1437 | "message", message, | 1132 | "message", message, |
| 1438 | - // 关键标志 | ||
| 1439 | "executionCompleted", true, | 1133 | "executionCompleted", true, |
| 1440 | "data", successResult(request, message) | 1134 | "data", successResult(request, message) |
| 1441 | )); | 1135 | )); |
| 1442 | } | 1136 | } |
| 1443 | - // 创建终止执行的结果 | 1137 | + |
| 1444 | private String createTerminationResult(String message) { | 1138 | private String createTerminationResult(String message) { |
| 1445 | return JSONUtil.toJsonStr(Map.of( | 1139 | return JSONUtil.toJsonStr(Map.of( |
| 1446 | "status", "terminated", | 1140 | "status", "terminated", |
| @@ -1449,70 +1143,30 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1449,70 +1143,30 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1449 | )); | 1143 | )); |
| 1450 | } | 1144 | } |
| 1451 | 1145 | ||
| 1452 | - /*** | ||
| 1453 | - * @Author 钱豹 | ||
| 1454 | - * @Date 10:15 2026/1/31 | ||
| 1455 | - * @Param [request, errorMsg] | ||
| 1456 | - * @return dev.langchain4j.data.message.ToolExecutionResultMessage | ||
| 1457 | - * @Description 错误返回 | ||
| 1458 | - **/ | ||
| 1459 | private ToolExecutionResultMessage errorResult(ToolExecutionRequest request, String errorMsg) { | 1146 | private ToolExecutionResultMessage errorResult(ToolExecutionRequest request, String errorMsg) { |
| 1460 | return ToolExecutionResultMessage.from(request, errorMsg); | 1147 | return ToolExecutionResultMessage.from(request, errorMsg); |
| 1461 | } | 1148 | } |
| 1462 | - /*** | ||
| 1463 | - * @Author 钱豹 | ||
| 1464 | - * @Date 10:15 2026/1/31 | ||
| 1465 | - * @Param [request, text] | ||
| 1466 | - * @return dev.langchain4j.data.message.ToolExecutionResultMessage | ||
| 1467 | - * @Description 构建正确返回 | ||
| 1468 | - **/ | 1149 | + |
| 1469 | private ToolExecutionResultMessage successResult(ToolExecutionRequest request, String text) { | 1150 | private ToolExecutionResultMessage successResult(ToolExecutionRequest request, String text) { |
| 1470 | return ToolExecutionResultMessage.from(request, text); | 1151 | return ToolExecutionResultMessage.from(request, text); |
| 1471 | } | 1152 | } |
| 1472 | 1153 | ||
| 1473 | - /** | ||
| 1474 | - * 执行方法后需要用户确认的扩展版本 | ||
| 1475 | - */ | ||
| 1476 | private String executeWithConfirmation(String initialResult, UserSceneSession session,ToolMeta meta) { | 1154 | private String executeWithConfirmation(String initialResult, UserSceneSession session,ToolMeta meta) { |
| 1477 | - | ||
| 1478 | - // 第一步:执行原始操作,返回初步结果 | ||
| 1479 | Map<String, Object> step1Result = new HashMap<>(); | 1155 | Map<String, Object> step1Result = new HashMap<>(); |
| 1480 | step1Result.put("initialResult", initialResult); | 1156 | step1Result.put("initialResult", initialResult); |
| 1481 | step1Result.put("status", "PENDING_CONFIRMATION"); | 1157 | step1Result.put("status", "PENDING_CONFIRMATION"); |
| 1482 | step1Result.put("confirmationRequired", true); | 1158 | step1Result.put("confirmationRequired", true); |
| 1483 | step1Result.put("confirmationMessage", initialResult); | 1159 | step1Result.put("confirmationMessage", initialResult); |
| 1484 | -// // 将确认状态保存到对话记忆 | ||
| 1485 | -// chatMemory.add(UserMessage.from("SYSTEM: 等待用户确认操作")); | ||
| 1486 | String userMessage = formatConfirmationResult(step1Result); | 1160 | String userMessage = formatConfirmationResult(step1Result); |
| 1487 | session.setCurrentTool(meta); | 1161 | session.setCurrentTool(meta); |
| 1488 | -// session.setSFunPrompts(userMessage); | ||
| 1489 | - // 6. 返回确认请求 | ||
| 1490 | -// return ToolExecutionResultMessage.from(request,userMessage); | ||
| 1491 | -// ToolExecutionResultMessage.from(request, text); | ||
| 1492 | return userMessage; | 1162 | return userMessage; |
| 1493 | } | 1163 | } |
| 1494 | 1164 | ||
| 1495 | private String formatConfirmationResult(Map<String, Object> result) { | 1165 | private String formatConfirmationResult(Map<String, Object> result) { |
| 1496 | - return String.format( | ||
| 1497 | - """ | ||
| 1498 | - %s | ||
| 1499 | - """, | ||
| 1500 | - result.get("initialResult"), | ||
| 1501 | - result.get("confirmationMessage") | ||
| 1502 | - ); | 1166 | + return String.format("%s", result.get("initialResult")); |
| 1503 | } | 1167 | } |
| 1504 | 1168 | ||
| 1505 | - /*** | ||
| 1506 | - * @Author 钱豹 | ||
| 1507 | - * @Date 0:54 2026/2/4 | ||
| 1508 | - * @Param [userResponse] | ||
| 1509 | - * @return boolean | ||
| 1510 | - * @Description 检查是确认 | ||
| 1511 | - **/ | ||
| 1512 | public boolean isConfirmed(String userResponse) { | 1169 | public boolean isConfirmed(String userResponse) { |
| 1513 | return userResponse.matches("(?i)(确认|全部确认|部分确认|是|yes|confirm|true|是的|可以|没问题|确定|好的|生成|)"); | 1170 | return userResponse.matches("(?i)(确认|全部确认|部分确认|是|yes|confirm|true|是的|可以|没问题|确定|好的|生成|)"); |
| 1514 | } | 1171 | } |
| 1515 | - | ||
| 1516 | - | ||
| 1517 | - | ||
| 1518 | -} | 1172 | +} |
| 1519 | \ No newline at end of file | 1173 | \ No newline at end of file |
src/main/java/com/xly/tool/ToolSpecificationHolder.java
| @@ -7,9 +7,11 @@ import dev.langchain4j.agent.tool.ToolSpecification; | @@ -7,9 +7,11 @@ import dev.langchain4j.agent.tool.ToolSpecification; | ||
| 7 | public class ToolSpecificationHolder { | 7 | public class ToolSpecificationHolder { |
| 8 | private final ToolSpecification toolSpecification; | 8 | private final ToolSpecification toolSpecification; |
| 9 | private final ToolExecutor toolExecutor; | 9 | private final ToolExecutor toolExecutor; |
| 10 | - public ToolSpecificationHolder(ToolSpecification toolSpecification, ToolExecutor toolExecutor) { | 10 | + private final String sName; |
| 11 | + public ToolSpecificationHolder(ToolSpecification toolSpecification, ToolExecutor toolExecutor,String sName) { | ||
| 11 | this.toolSpecification = toolSpecification; | 12 | this.toolSpecification = toolSpecification; |
| 12 | this.toolExecutor = toolExecutor; | 13 | this.toolExecutor = toolExecutor; |
| 14 | + this.sName = sName; | ||
| 13 | } | 15 | } |
| 14 | 16 | ||
| 15 | public ToolSpecification getToolSpecification() { | 17 | public ToolSpecification getToolSpecification() { |
| @@ -18,4 +20,11 @@ public class ToolSpecificationHolder { | @@ -18,4 +20,11 @@ public class ToolSpecificationHolder { | ||
| 18 | 20 | ||
| 19 | public ToolExecutor getToolExecutor() { | 21 | public ToolExecutor getToolExecutor() { |
| 20 | return toolExecutor; | 22 | return toolExecutor; |
| 21 | - }} | 23 | + } |
| 24 | + | ||
| 25 | + public String getsName() { | ||
| 26 | + return sName; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} | ||
| 30 | + |
src/main/resources/application.yml
| @@ -135,8 +135,8 @@ langchain4j: | @@ -135,8 +135,8 @@ langchain4j: | ||
| 135 | ollama: | 135 | ollama: |
| 136 | # 聊天模型配置(用于一般对话) | 136 | # 聊天模型配置(用于一般对话) |
| 137 | base-url: http://112.82.245.194:11434 | 137 | base-url: http://112.82.245.194:11434 |
| 138 | -# chat-model-name: qwen2.5:7b-instruct | ||
| 139 | - chat-model-name: qwen3:14b | 138 | + chat-model-name: qwen2.5:7b-instruct |
| 139 | +# chat-model-name: qwen3:14b | ||
| 140 | # chat-model-name: qwen3.5:9b | 140 | # chat-model-name: qwen3.5:9b |
| 141 | # SQL/代码模型配置(专门用于代码和SQL生成) | 141 | # SQL/代码模型配置(专门用于代码和SQL生成) |
| 142 | sql-model-name: qwen2.5-coder:7b | 142 | sql-model-name: qwen2.5-coder:7b |
| @@ -171,4 +171,4 @@ tts: | @@ -171,4 +171,4 @@ tts: | ||
| 171 | timeout: 30000 | 171 | timeout: 30000 |
| 172 | max-connections: 10 | 172 | max-connections: 10 |
| 173 | erp: | 173 | erp: |
| 174 | - baseurl: http://8.130.144.93:8080/xlyEntry_saas | ||
| 175 | \ No newline at end of file | 174 | \ No newline at end of file |
| 175 | + baseurl: http://118.178.19.35:8080/xlyEntry_saas | ||
| 176 | \ No newline at end of file | 176 | \ No newline at end of file |