package com.xly.tool; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.xly.agent.AgentSystemPrompt; import com.xly.config.OperableChatMemoryProvider; import com.xly.constant.*; import com.xly.entity.*; import com.xly.exception.dto.BusinessException; import com.xly.exception.dto.DataException; import com.xly.mapper.ParamRuleMapper; import com.xly.mapper.ToolMetaMapper; import com.xly.service.DynamicExeDbService; import com.xly.service.UserSceneSessionService; import com.xly.util.*; import dev.langchain4j.agent.tool.*; import dev.langchain4j.data.message.ChatMessage; import dev.langchain4j.data.message.ChatMessageType; import dev.langchain4j.data.message.ToolExecutionResultMessage; import dev.langchain4j.data.message.UserMessage; import dev.langchain4j.memory.ChatMemory; import dev.langchain4j.model.chat.request.json.JsonObjectSchema; import dev.langchain4j.model.chat.request.json.JsonSchema; import dev.langchain4j.service.tool.*; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.javassist.expr.NewArray; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.IntStream; @Slf4j @Service @RequiredArgsConstructor public class DynamicToolProvider implements ToolProvider { private final ObjectMapper objectMapper; private final ToolMetaMapper toolMetaMapper; private final ParamRuleMapper paramRuleMapper; private final DynamicExeDbService dynamicExeDbService; private final OperableChatMemoryProvider operableChatMemoryProvider; private final Map toolCache = new ConcurrentHashMap<>(); public final Map sSceneIdMap = new ConcurrentHashMap<>(); public final Map> sceneToolCacheMap = new ConcurrentHashMap<>(); private final List paramRuleDataAll = new ArrayList<>(); @Value("${erp.baseurl}") private String baseUrl; public void cleanAllToolProvider() { toolCache.clear(); sceneToolCacheMap.clear(); paramRuleDataAll.clear(); } @jakarta.annotation.PostConstruct public void init() { List metas = toolMetaMapper.findAll(); for (ToolMeta meta : metas) { try { doSetToolAIshowfieldShow(meta); ToolSpecification spec = buildToolSpecification(meta); ToolExecutor executor = createToolExecutor(meta); toolCache.put(meta.getSMethodNo(), new ToolSpecificationHolder(spec, executor,meta.getSMethodNo())); log.info("已加载动态工具:{}", meta.getSMethodNo()); String sceneId = meta.getSSceneId(); List dataList = new ArrayList<>(); if(ObjectUtil.isNotEmpty(sceneToolCacheMap.get(sceneId))) { dataList = sceneToolCacheMap.get(sceneId); } dataList.add(new ToolSpecificationHolder(spec, executor,meta.getSMethodNo())); sceneToolCacheMap.put(sceneId, dataList); } catch (Exception e) { e.printStackTrace(); log.error("构建工具失败,sMethodNo={}", meta.getSMethodNo(), e); } } } @Override public ToolProviderResult provideTools(ToolProviderRequest request) { String sUserId = request.chatMemoryId().toString(); Map executors = new HashMap<>(); UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); // ====================== 防重复调用核心拦截 ====================== if (session != null && (session.getToolExecuted() || StrUtil.isNotBlank(session.getSFunPrompts()))) { log.info("工具已执行/等待用户回复,禁止提供工具"); return ToolProviderResult.builder().build(); } List datalist = new ArrayList<>(); List toolMetaAll = new ArrayList<>(); if(session.getCurrentTool() != null){ toolMetaAll.add(session.getCurrentTool()); log.info("使用 currentTool: {}", session.getCurrentTool().getSMethodNo()); } else { toolMetaAll = session.getAuthTool(); } if(ObjectUtil.isNotEmpty(toolMetaAll)){ toolMetaAll = toolMetaAll.stream() .filter(to -> to.getSSceneId().equals(sSceneIdMap.get(sUserId))) .collect(Collectors.toUnmodifiableList()); if(ObjectUtil.isNotEmpty(toolMetaAll)){ toolMetaAll.forEach(to -> { ToolSpecificationHolder holder = toolCache.get(to.getSMethodNo()); if (holder != null) { datalist.add(holder); log.debug("添加工具到提供器: {}", to.getSMethodNo()); } else { log.warn("工具缓存缺失: {}", to.getSMethodNo()); } }); } } datalist.forEach(holder -> { executors.put(holder.getToolSpecification(), holder.getToolExecutor()); }); log.info("provideTools 返回工具数量: {}", executors.size()); return ToolProviderResult.builder().addAll(executors).build(); } /*** * @Author 钱豹 * @Date 23:59 2026/5/17 * @Param [meta] * @return dev.langchain4j.service.tool.ToolExecutor * @Description AI 自动调用工具执行方法 **/ private ToolExecutor createToolExecutor(ToolMeta meta) { log.info("创建工具执行器: {}", meta.getSMethodNo()); return (toolExecutionRequest, memoryId) -> { log.info("===== 工具执行器开始执行 ====="); log.info("工具编号: {}", meta.getSMethodNo()); log.info("工具名称: {}", meta.getSMethodName()); log.info("memoryId: {}", memoryId); log.info("请求参数: {}", toolExecutionRequest.arguments()); UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); session.setCurrentTool(meta); // ====================== 防重复调用:立即上锁 ====================== session.setToolExecuted(true); if (StrUtil.isNotBlank(session.getSFunPrompts())) { // 关键:返回 工具执行失败 = 框架强制停止循环 // throw new IllegalStateException("STOP_INVOCATION: 任务已完成,停止调用"); return "【任务已完成】请勿重复调用工具,请直接总结结果回复用户:"+session.getSFunPrompts(); } //解析参数失败 Map argsNew; try { argsNew = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); log.info("解析后的参数: {}", argsNew); } catch (Exception e) { log.error("参数解析失败", e); // 抛异常 throw new RuntimeException("参数解析失败,请重新输入"); } //获取之前获取的参数 Map args = session.getArgs(); if(ObjectUtil.isEmpty(args)) args = new HashMap<>(); Map finalArgs = args; argsNew.forEach((k, v)->{ //获取对应的英文参数 List data = meta.getParamRuleList().stream().filter(one->one.getSParam().equals(k)).collect(Collectors.toUnmodifiableList()); if(ObjectUtil.isNotEmpty(data) && data.size()>0){ finalArgs.remove(data.get(0).getSParamValue()); finalArgs.remove(data.get(0).getSParam()); } if(ObjectUtil.isNotEmpty(v)){ finalArgs.put(k,v); } }); // 2 【补全动态参数】动态参数补全 try{ args = applyValues(args, meta.getParamRuleListCheck()); }catch (Exception e){ log.error("返回信息",e); String askMsg = e.getMessage(); session.setSFunPrompts(askMsg); // 需要提问用户 → 抛异常停止循环 throw new RuntimeException(askMsg); } // 2.1 【自动补全】应用参数的默认值 List paramRuleData = meta.getParamRuleListAll(); args = applyDefaultValues(args, paramRuleData); session.setArgs(args); // 3. 【自动校验】检查必填项 List missing = checkRequiredParams(args, paramRuleData); if (!missing.isEmpty()) { // 4.1 参数缺失,生成“提问”消息,直接返给客户 String askMsg = buildAskUserMessage(meta, missing,args); session.setSFunPrompts(askMsg); return String.valueOf(successResult(toolExecutionRequest, askMsg)); } // ====================== 返回时带终止指令 ====================== String resp = JSONUtil.toJsonStr(finalArgs) ; // String resp = doDynamicTool( meta, session); return String.valueOf(successResult(toolExecutionRequest, resp)); }; } private void doSetToolAIshowfieldShow(ToolMeta meta){ String sToolId = meta.getSId(); List paramRuleData = getParamRuleDataAll(); List paramRuleListAll = paramRuleData.stream().filter(one-> sToolId.equals(one.getSParentId())).collect(Collectors.toUnmodifiableList()); List paramRuleList = paramRuleListAll.stream().filter(one-> one.getBTipModel()).collect(Collectors.toUnmodifiableList()); List paramRuleListCheck = paramRuleListAll.stream().filter(one->one.getBEmpty()).collect(Collectors.toUnmodifiableList()); paramRuleList = ObjectUtil.isNotEmpty(paramRuleList)?paramRuleList:new ArrayList<>(); if((meta.getIBizType()==4 || meta.getIBizType()==5) && ObjectUtil.isNotEmpty(meta.getSAIshowfield()) && ObjectUtil.isNotEmpty(meta.getSSrcFormId()) ){ String[] sAIshowfield = meta.getSAIshowfield().split(","); List mutableList = Arrays.asList(sAIshowfield); List sAIshowfieldArry = new ArrayList<>(mutableList); sAIshowfieldArry.add("sSlaveId"); String sSrcFormId = meta.getSSrcFormId(); 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 ") .append("JOIN gdsconfigformmaster AS B ON A.sParentId = B.sId ") .append("WHERE B.sParentId = #{sSrcFormId} AND A.sName <> '' AND INSTR(A.sControlName,'Btn')=0 AND (A.bVisible = 1 OR A.sName =#{sName}) "); Map searMap = new HashMap<>(); searMap.put("sSrcFormId",sSrcFormId); searMap.put("sName","sSlaveId"); List> sAIshowfieldShowAll = dynamicExeDbService.findSql(searMap,sSql.toString()); if(ObjectUtil.isNotEmpty(sAIshowfieldShowAll)){ sAIshowfieldShowAll = sAIshowfieldShowAll.stream().filter(m-> sAIshowfieldArry.contains(m.get("sName").toString())).collect(Collectors.toUnmodifiableList()); sAIshowfieldShowAll.forEach(one->{ one.put("iOrderShow",sAIshowfieldArry.indexOf(one.get("sName").toString())+1); }); List> sAIshowfieldShowData = new ArrayList<>(); sAIshowfieldShowData.addAll(sAIshowfieldShowAll); sAIshowfieldShowData.sort(Comparator.comparing(h -> Integer.valueOf(h.get("iOrderShow").toString()))); meta.setSAIshowfieldShow(sAIshowfieldShowData); } List paramRuleListNew = new ArrayList<>(paramRuleList); for(int i=0;i sAIshowfieldShow = sAIshowfieldShowAll.get(i); List one = paramRuleList.stream().filter(m->m.getSParamValue().equals(sAIshowfieldShow.get("sName"))).collect(Collectors.toUnmodifiableList()); if(ObjectUtil.isEmpty(one)){ ParamRule pr = new ParamRule(); pr.setIOrder(i+1); pr.setSParamValue(sAIshowfieldShowAll.get(i).get("sName").toString()); pr.setSParam(sAIshowfieldShowAll.get(i).get("label").toString()); pr.setBEmpty(false); pr.setSType(getDefType(sAIshowfieldShowAll.get(i).get("sName").toString())); if("sSlaveId".equals(sAIshowfieldShowAll.get(i).get("sName"))){ pr.setSParam("sSlaveId"); } pr.setBTipModel(true); paramRuleListNew.add(pr); } } String sendUrl = baseUrl + UrlErpConstant.getBusinessDataByFormcustomId; sendUrl = StrUtil.format(sendUrl,sAIshowfieldShowAll.get(0).get("sFormcustomId"),sSrcFormId); meta.setSendUrl(sendUrl); paramRuleList = paramRuleListNew; paramRuleListCheck = paramRuleListNew; paramRuleListAll = paramRuleListNew; } List paramRuleListNew = new ArrayList<>(paramRuleList); meta.setParamRuleList(paramRuleListNew); meta.setParamRuleListCheck(paramRuleListCheck); meta.setParamRuleListAll(paramRuleListAll); } private String getDefType(String sColumn){ if(sColumn.startsWith("d")){ return "double"; }else{ return "string"; } } private ToolSpecification buildToolSpecification(ToolMeta meta) { ToolSpecification.Builder builder = ToolSpecification.builder() .name(meta.getSMethodNo()); StringBuffer stoolDesc = new StringBuffer(); String forceToolPrompt = """ 【工具调用规则】 1. 每个自定义方法最多只能调用 1 次 2. 只要方法返回结果,必须停止调用 3. 禁止重复调用同一个方法 4. 禁止无意义循环调用 """; stoolDesc.append(forceToolPrompt); if (ObjectUtil.isNotEmpty(meta.getStoolDesc())) { stoolDesc.append("MethodNo:").append(meta.getSMethodNo()) .append(",当用户").append(meta.getSMethodName()) .append("时,必须调用本工具").append(meta.getSMethodNo()) .append(",").append(meta.getStoolDesc()); } JsonObjectSchema.Builder schemaBuilder = JsonObjectSchema.builder(); List requiredParams = new ArrayList<>(); try { List paramRuleData = meta.getParamRuleList(); for (ParamRule paramRule : paramRuleData) { String paramDesc = paramRule.getSParam(); String paramType = paramRule.getSType(); Boolean bEmpty = paramRule.getBEmpty(); if (paramDesc == null || paramDesc.isEmpty()) { continue; } String sRuleCost = getConstMeg(paramRule); switch (paramType.toLowerCase()) { case "string": schemaBuilder.addStringProperty(paramDesc, paramDesc); break; case "integer": case "int": schemaBuilder.addIntegerProperty(paramDesc, paramDesc); break; case "number": case "double": case "float": schemaBuilder.addNumberProperty(paramDesc, paramDesc); break; case "boolean": case "bool": schemaBuilder.addBooleanProperty(paramDesc, paramDesc); break; case "array": String enumStr = getArrrayBySql(paramRule); List enums = StrUtil.isNotBlank(enumStr) ? Arrays.asList(enumStr.split("/")) : new ArrayList<>(); if (enums.isEmpty()) { schemaBuilder.addStringProperty(paramDesc, paramDesc + "(数组)"); } else { schemaBuilder.addEnumProperty(paramDesc, enums, paramDesc + "(数组)"); } break; case "enum": String constStr = getConstMeg(paramRule); List constList = StrUtil.isNotBlank(constStr) ? Arrays.asList(constStr.split("/")) : new ArrayList<>(); if (constList.isEmpty()) { schemaBuilder.addStringProperty(paramDesc, paramDesc); } else { schemaBuilder.addEnumProperty(paramDesc, constList, paramDesc); } break; default: schemaBuilder.addStringProperty(paramDesc, paramDesc); break; } if (bEmpty) { requiredParams.add(paramDesc); } } } catch (Exception e) { e.printStackTrace(); } if (meta.getIBizType() == 4 || meta.getIBizType() == 5) { schemaBuilder.addStringProperty("operateType", "操作类型:全部确认/合并确认/单行确认"); requiredParams.add("operateType"); } if (!requiredParams.isEmpty()) { schemaBuilder.required(requiredParams); } JsonObjectSchema parameters = schemaBuilder.build(); return builder .description(stoolDesc.toString()) .parameters(parameters) .build(); } private String getConstMeg(ParamRule paramRule){ if(!RuleCode.CONST.getCode().equals(paramRule.getSRule())){ return StrUtil.EMPTY; } String sConstConfig = paramRule.getSParamConfig(); if(StrUtil.isNotEmpty(sConstConfig)){ Map constMap = JSONUtil.parseObj(sConstConfig); StringBuffer sb = new StringBuffer(); constMap.forEach((k,v)->{ sb.append(v).append("/"); }); sb.delete(sb.length()-1,sb.length()); paramRule.setSRuleTs(sb.toString()); return sb.toString(); } return StrUtil.EMPTY; } private String getArrrayBySql(ParamRule paramRule){ Boolean bCheckArray = !(RuleCode.SQL.getCode().equals(paramRule.getSRule())); Boolean bCheckArray2= !("array".equals(paramRule.getSType()) || "enum".equals(paramRule.getSType())); Boolean bCheckArray3= ObjectUtil.isEmpty(paramRule.getSParamConfig()); if(bCheckArray || bCheckArray2 || bCheckArray3){ return StrUtil.EMPTY; } List> data = dynamicExeDbService.findSql(new HashMap<>(),paramRule.getSParamConfig()); StringBuffer sb = new StringBuffer(); if(ObjectUtil.isEmpty(data)){ return StrUtil.EMPTY; } if(data.get(0).containsKey("sGroupName")){ Map>> groupData = data.stream() .collect(Collectors.groupingBy(map -> map.get("sGroupName"))); Integer sUpKeySize =groupData.size(); groupData.forEach((key, value) -> { value.forEach(one->{ sb.append(one.get(paramRule.getSParamValue())).append("/"); }); if(sUpKeySize>1 && ObjectUtil.isNotEmpty(sb)){ sb.delete(sb.length()-1,sb.length()); sb.append(","); } }); }else{ data.forEach(one->{ if(ObjectUtil.isNotEmpty(one.get(paramRule.getSParamValue()))){ sb.append(one.get(paramRule.getSParamValue())).append("/"); } }); } if(ObjectUtil.isNotEmpty(sb)){ sb.delete(sb.length()-1,sb.length()); paramRule.setSRuleTs(sb.toString()); } return sb.toString(); } private List getParamRuleDataAll(){ if(paramRuleDataAll==null || paramRuleDataAll.size()==0){ paramRuleDataAll.addAll(paramRuleMapper.findAll()); } return paramRuleDataAll; } public String doDynamicTool(ToolMeta meta,UserSceneSession session) { List paramRuleData = meta.getParamRuleListAll(); List paramRuleDataCheck = meta.getParamRuleListCheck(); Map args = session.getArgs(); List missing = checkRequiredParams(args, paramRuleDataCheck); if (!missing.isEmpty()) { String askMsg = buildAskUserMessage(meta, missing,args); return askMsg; } List chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); ChatMessage userMessage = getLastUserMessage(chatMessage); String input = ""; if (userMessage != null) { input = StrUtil.replace(getChatMessageContent(userMessage), "用户输入:", StrUtil.EMPTY); } Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) || 2== meta.getIBizType() || 3== meta.getIBizType() || 6== meta.getIBizType() || 7== meta.getIBizType() || 8== meta.getIBizType() ) { List missingAfter = checkConfirmAfterParam(args, paramRuleData); if (!missingAfter.isEmpty()) { String askMsg = buildAskUserMessage(meta, missingAfter,args); throw new DataException(askMsg); } return executeTool(meta, args, paramRuleData, session.getUserId(), session); } String askconfirmMsg =StrUtil.EMPTY; if(4== meta.getIBizType() || meta.getIBizType()==5){ askconfirmMsg = doGetFromData( meta,args,session); String sSystemPrompt = buildDynamicSystemPrompt(session); session.setSSystemPrompt(sSystemPrompt); return executeWithConfirmation(askconfirmMsg, session, meta); }else{ askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); } return executeWithConfirmation(askconfirmMsg, session, meta); } private String getChatMessageContent(ChatMessage message) { if (message == null) return ""; try { return message.toString() .replace("ChatMessage{", "") .replace("}", "") .replace("text=", "") .trim(); } catch (Exception e) { return ""; } } private ChatMessage getLastUserMessage(List messages) { if (messages == null || messages.isEmpty()) return null; for (int i = messages.size() - 1; i >= 0; i--) { ChatMessage msg = messages.get(i); if (msg.type() == ChatMessageType.USER) { return msg; } } return null; } private String getDefMessage(Map argMap,String sName,ToolMeta meta){ List showList = meta.getParamRuleListAll(); List showListData = new ArrayList<>(); showList = showList.stream().filter(one->one.getBTipModel()).collect(Collectors.toUnmodifiableList()); showListData.addAll(showList); showListData.sort(Comparator.comparing(h -> h.getIOrder())); StringBuilder markdown = new StringBuilder().append("\n"); markdown.append("\n---\n"); showListData.forEach(one->{ if(argMap.containsKey(one.getSParam())){ String valueStr = argMap.get(one.getSParam()) != null ? argMap.get(one.getSParam()).toString() : ""; markdown.append("- ") .append(one.getSParam()) .append(": `") .append(valueStr) .append("`\n"); } }); markdown.append("\n---\n"); appendConfirm(markdown,sName); return markdown.toString(); } private void appendConfirmAll(StringBuilder markdown,String sName){ sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"第1行确认"\n"); markdown.append("回复:  ").append("**全部确认**").append(" ") .append("**合并确认**").append(" ") .append("**取消**"); } private void appendConfirm(StringBuilder markdown,String sName){ sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; markdown.append("请确认是否执行").append(sName).append("操作?请回复:  ").append("**确认**").append(" ") .append("**取消**"); } private Map transformationArgs(Map args, List paramDefs) { Map result = new HashMap<>(args); paramDefs.forEach(pd->{ String name = pd.getSParam(); String sValue = pd.getSParamValue(); Boolean bCheck = result.containsKey(name) && ObjectUtil.isNotEmpty(result.get(name)); Boolean bCheck2 = result.containsKey(sValue) && ObjectUtil.isNotEmpty(result.get(sValue)); if (!bCheck2 && bCheck ) { result.put(sValue,args.get(name)); } if(RuleCode.CONST.getCode().equals(pd.getSRule()) && ObjectUtil.isNotEmpty(result.get(sValue))){ String sData = result.get(sValue).toString(); Map configData = JSONUtil.parseObj(pd.getSParamConfig()); configData.forEach((k,v)->{ if(sData.equals(v)){ result.put(sValue,k); } }); } }); return result; } private Map applyValues(Map args, List paramDefsCheck) { Map result = new HashMap<>(args); result = transformationArgs( result, paramDefsCheck); List paramDefs = new ArrayList<>(paramDefsCheck); paramDefs.sort(Comparator.comparing(ParamRule::getIOrder)); for (ParamRule pd : paramDefs) { String name = pd.getSParam(); String sValue = pd.getSParamValue(); String sRule = pd.getSRule(); String sType = pd.getSType(); Boolean bCheck = result.containsKey(name); bCheck = bCheck && ObjectUtil.isNotEmpty(result.get(name)); bCheck = bCheck && RuleCode.SQL.getCode().equals(sRule); bCheck = bCheck && ObjectUtil.isNotEmpty(pd.getSParamConfig()); Boolean bCheck2 = result.containsKey(sValue); bCheck2 = bCheck2 && ObjectUtil.isNotEmpty(result.get(sValue)); bCheck2 = bCheck2 && RuleCode.SQL.getCode().equals(sRule); bCheck2 = bCheck2 && ObjectUtil.isNotEmpty(pd.getSParamConfig()); if ((bCheck || bCheck2) &&("enum".equals(sType) || "string".equals(sType))){ String sSql = pd.getSParamConfig(); String sKey = bCheck?name:sValue; String nameValue = result.get(sKey).toString(); List> dataList = dynamicExeDbService.findSql(result,sSql); if(ObjectUtil.isEmpty(dataList)){ throw new BusinessException(ErrorCode.PARAM_REQUIRED,String.format("%s 您描述的%s 不存在,请重新告诉我",name,nameValue)); } if(ObjectUtil.isNotEmpty(args.get(name)) || ObjectUtil.isNotEmpty(args.get(sValue))){ if(("enum".equals(sType) ||"string".equals(sType)) && (args.get(name) instanceof List || args.get(sValue) instanceof List)){ if(args.get(name) instanceof List){ args.put(name,((List) args.get(name)).get(0)); } if(args.get(sValue) instanceof List){ args.put(sValue,((List) args.get(sValue)).get(0)); } } List> dataListNew = dataList.stream().filter(one-> one.get(sValue).equals(args.get(name)) || one.get(sValue).equals(args.get(sValue))).collect(Collectors.toUnmodifiableList()); if("enum".equals(sType) && ObjectUtil.isEmpty(dataListNew)){ args.remove(name); args.remove(sValue); result.remove(name); result.remove(sValue); continue; } if(ObjectUtil.isNotEmpty(dataListNew)){ dataList = new ArrayList<>(); dataList.add(dataListNew.get(0)); } } if(ObjectUtil.isNotEmpty(dataList) && dataList.size()==1){ String sCopyTo = pd.getSCopyTo(); if(ObjectUtil.isEmpty(sCopyTo)){ result.put(sValue, dataList.get(0).get(sValue)); result.put(name, dataList.get(0).get(sValue)); }else{ String[] sCopyToA = sCopyTo.split(","); for(String sCopyToOne:sCopyToA){ String[] sCopyToOneA = sCopyToOne.split(":"); result.put(sCopyToOneA[0], dataList.get(0).get(sCopyToOneA[1])); } } } StringBuffer sData=new StringBuffer(); if(dataList.size()>1){ List> finalDataList = dataList; IntStream.range(0, dataList.size()) .forEach(iRowNum ->{ sData.append((iRowNum + 1)).append(".").append(finalDataList.get(iRowNum).get(pd.getSParamValue())) .append("\n\n"); }); String sParamMissMemo = StrUtil.EMPTY; if(ObjectUtil.isEmpty(pd.getSParamMissMemo())){ sParamMissMemo = pd.getSParam()+"存在多个,请选择:
"+sData; }else{ sParamMissMemo = StrUtil.format(pd.getSParamMissMemo(),sData.toString()); } throw new BusinessException(ErrorCode.PARAM_REQUIRED,sParamMissMemo); } } } return result; } private Map applyDefaultValues(Map args, List paramDefs) { Map result = new HashMap<>(args); for (ParamRule pd : paramDefs) { String name = pd.getSParam(); if ((!result.containsKey(name)|| ObjectUtil.isEmpty(result.get(name))) && ObjectUtil.isNotEmpty(pd.getSDefaultValue()) ) { Object defaultValue = pd.getSDefaultValue(); result.put(name, defaultValue); } } return result; } private List checkRequiredParams(Map args, List paramDefs) { Map returnMap = transformationArgs( args, paramDefs); return paramDefs.stream() .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()) .filter(pd -> checkMiss( returnMap, pd)) .map(ParamRule::getSParam) .toList(); } private Boolean checkMiss(Map returnMap,ParamRule pd) { if(ObjectUtil.isEmpty(returnMap)){ returnMap = new HashMap<>(); } Boolean bBhcs = (ObjectUtil.isEmpty(returnMap.get(pd.getSParam()))); Boolean bDbZero = false; if(pd.getSParamValue().startsWith("d")){ try{ String sParam = pd.getSParam().toString(); Object sParamV = returnMap.get(sParam); bDbZero = (ObjectUtil.isEmpty(sParamV) || 0 ==Double.valueOf(sParamV.toString())); }catch (Exception e){ bDbZero = true; } } return bDbZero || bBhcs || (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))); } private List checkConfirmAfterParam(Map args, List paramDefs) { Map returnMap = transformationArgs( args, paramDefs); return paramDefs.stream() .filter(pd -> Boolean.TRUE.equals(pd.getBConfirmAfter()) && pd.getBTipModel()) .filter(pd -> (!returnMap.containsKey(pd.getSParam()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam())))) && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) ) .map(ParamRule::getSParam) .toList(); } public String executeTool(ToolMeta meta, Map args, List paramRuleData,String userId,UserSceneSession session ) { log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); args = transformationArgs( args, paramRuleData); String sReturn ="执行成功"; try{ sReturn = executeToolAfter(meta, args,paramRuleData,session); }catch (BusinessException e) { return e.getMessage(); }finally { session.setSSystemPrompt(StrUtil.EMPTY); } if(meta.getIActionType()==1){ session.setBCleanMemory(true); } return sReturn; } private String executeToolAfter(ToolMeta meta, Map args,List paramDefs,UserSceneSession session) { String sBizContent = meta.getSBizContent(); Integer iBizType = meta.getIBizType(); args.put("sUserId", session.getUserId()); args.put("sLoginId", session.getUserName()); args.put("sMakePerson", session.getUserName()); args.put("sBrId", session.getSBrandsId()); args.put("sBrandsId", session.getSBrandsId()); args.put("sSuId", session.getSSubsidiaryId()); args.put("sSrcFormId", meta.getSSrcFormId()); args.put("sControlName", meta.getSControlName()); args.put("iBizType", iBizType); args.put("sSubsidiaryId", session.getSSubsidiaryId()); args.put("sToolId", meta.getSId()); if (iBizType == 1 || iBizType == 4) { Map data = new HashMap<>(args); data.put("sData", JSONObject.toJSONString((data))); if(ObjectUtil.isEmpty(sBizContent) && iBizType == 4){ sBizContent ="Sp_Ai_AddCommonAfterNew"; if(ObjectUtil.isEmpty(args.get("sSlaveId"))){ throw new BusinessException(-1,"请选择操作数据"); } List> sRowData = doGetFromDataWq( meta, args, session); data.put("sRowData", JSONObject.toJSONString(sRowData)); } Map searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data); Map sReturn = this.dynamicExeDbService.getCallPro(searMap, sBizContent); Integer sCode = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SCODE)) ? Integer.valueOf(sReturn.get(ProcedureConstant.SCODE).toString()) : 0; String sMsgText = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SRETURN)) ? sReturn.get(ProcedureConstant.SRETURN).toString() : "操作成功"; if (sCode < 0) { sMsgText = ObjectUtil.isEmpty(sMsgText) ? "调用过程sCode:" + Integer.valueOf(searMap.get(ProcedureConstant.SCODE).toString()) : sMsgText; session.setSFunPrompts(sMsgText); throw new BusinessException(sCode,sMsgText); } Map outMap = (Map) sReturn.get("outMap"); String sId = ObjectUtil.isNotEmpty(outMap.get("sBillId")) ? outMap.get("sBillId").toString() : ""; session.setSCopyTo(meta.getSControlName()); session.setSCopyToSrcId(sId); session.setSFunPrompts(sMsgText); return sMsgText; } else if (iBizType == 2 && ObjectUtil.isNotEmpty(sBizContent)) { if (sBizContent.toLowerCase().startsWith("update")) { this.dynamicExeDbService.updateSql(args, sBizContent); } else if (sBizContent.toLowerCase().startsWith("delete")) { this.dynamicExeDbService.delSql(args, sBizContent); } else if (sBizContent.toLowerCase().startsWith("insert")) { this.dynamicExeDbService.addSql(args, sBizContent); } else { List> retData = this.dynamicExeDbService.findSql(args, sBizContent); if (ObjectUtil.isNotEmpty(retData)) { StringBuffer sb = new StringBuffer(); retData.forEach(one -> { one.forEach((k, v) -> { sb.append(v).append(" "); }); sb.append("
"); }); if (ObjectUtil.isNotEmpty(retData)) { sb.append("请根据这些信息安排今天的工作吧!如果有具体任务需要进一步处理,请告诉我"); } session.setSFunPrompts(sb.toString()); if ("queryTodayTask".equals(meta.getSMethodNo())) { session.setBCleanMemory(true); } return sb.toString(); } else { String sMsgText = "未找到对应的数据"; session.setSFunPrompts(sMsgText); throw new BusinessException(-1,sMsgText); } } } else if (iBizType == 3) { return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), new HashMap<>(), "POST", "JSON"); } return "操作成功"; } private List> doGetFromDataWq(ToolMeta meta, Map args,UserSceneSession session){ String sUrl = meta.getSendUrl(); Map sBody = new HashMap<>(); sBody.put("pageNum",1); sBody.put("pageSize",10000); log.info("doGetFromData========================"); List> list = new ArrayList<>(); Map serOne = new HashMap<>(4); serOne.put("bFilterCondition","IN"); serOne.put("bFilterValue",args.get("sSlaveId")); serOne.put("bFilterName","sSlaveId"); list.add(serOne); log.info("开始请请求========================{}", sUrl); sBody.put("bFilter",list); Map headers = new HashMap<>(); headers.put("Authorization",session.getAuthorization()); String result; try{ result = HttpsRequestUtil.me().doRequestHttp(sUrl,JSONObject.toJSONString(sBody),headers,"POST","JSON"); log.info("请求URL========================{}", sUrl); log.info("请求URLresult========================{}", result); ErpResult erpResult = JsonUtils.toObject(result,ErpResult.class); if(ObjectUtil.isNotEmpty(erpResult) && ObjectUtil.isNotEmpty(erpResult.getDataset()) && ObjectUtil.isNotEmpty(erpResult.getDataset().getRows()) && ObjectUtil.isNotEmpty(erpResult.getDataset().getRows().get(0)) && ObjectUtil.isNotEmpty(erpResult.getDataset().getRows().get(0).getDataSet()) ){ return erpResult.getDataset().getRows().get(0).getDataSet(); } }catch (Exception e){ } return new ArrayList<>(); } private String doGetFromData(ToolMeta meta, Map args,UserSceneSession session){ String sUrl = meta.getSendUrl(); Map sBody = new HashMap<>(); sBody.put("pageNum",1); sBody.put("pageSize",10000); log.info("doGetFromData========================"); List> list = new ArrayList<>(); args.remove("operateType"); if(ObjectUtil.isNotEmpty(args)){ List paramDefs = meta.getParamRuleList(); args.forEach((k,v)->{ if(ObjectUtil.isNotEmpty(v)){ List pdList = paramDefs.stream().filter(m-> m.getSParam().equals(k) || m.getSParamValue().equals(k)).collect(Collectors.toUnmodifiableList()); List data = new ArrayList<>(); if(v instanceof List){ data.addAll((List) v); }else{ data.add(v); } data = data.stream().filter(m-> !(m.toString().contains("全部") || m.toString().contains("所有"))).collect(Collectors.toUnmodifiableList()); if(ObjectUtil.isNotEmpty(data)){ StringBuffer bFilterValue = new StringBuffer(); for(int i=0;i serOne = new HashMap<>(4); serOne.put("bFilterCondition","like"); serOne.put("bFilterValue",bFilterValue.toString()); serOne.put("bFilterName",pdList.get(0).getSParamValue()); list.add(serOne); } } } }); } log.info("开始请请求========================{}", sUrl); sBody.put("bFilter",list); Map headers = new HashMap<>(); headers.put("Authorization",session.getAuthorization()); String result; try{ result = HttpsRequestUtil.me().doRequestHttp(sUrl,JSONObject.toJSONString(sBody),headers,"POST","JSON"); log.info("请求URL========================{}", sUrl); log.info("请求URLresult========================{}", result); ErpResult erpResult = JsonUtils.toObject(result,ErpResult.class); result = buildResultMessageWithTable( meta, erpResult, session); }catch (Exception e){ result ="执行异常:"+e.getMessage(); } return result; } public String buildResultMessageWithTable(ToolMeta meta,ErpResult erpResult,UserSceneSession session){ Map> currentRowData = new HashMap<>(); ErpDataset dataset = erpResult.getDataset(); if(erpResult.getCode()<0 && ObjectUtil.isNotEmpty(erpResult.getMsg())){ return erpResult.getMsg(); } if(dataset==null){ return ErrorCode.DATA_NOT_FOUND.getMessage(); } List> sAIshowfieldShow = meta.getSAIshowfieldShow(); List> rows = new ArrayList<>(); if(ObjectUtil.isNotEmpty(dataset.getRows().get(0))){ rows = dataset.getRows().get(0).getDataSet(); } List> recordData = findFieldNameByChinese(sAIshowfieldShow, rows); int recordCount = dataset != null ? dataset.getTotalCount() : 0; Set headers = new LinkedHashSet<>(); for (Map record : sAIshowfieldShow) { String chineseName = (String) record.get("label"); if (chineseName != null && !"sSlaveId".equals(record.get("sName"))) { headers.add(chineseName); } } StringBuilder markdown = new StringBuilder(); if(ObjectUtil.isNotEmpty(session.getArgs())){ markdown.append("**查询条件**:"); List pr = session.getCurrentTool().getParamRuleListCheck(); Map argsOld = new HashMap<>(session.getArgs()); pr.forEach(one->{ if(argsOld.containsKey(one.getSParam())){ if(ObjectUtil.isNotEmpty(argsOld.get(one.getSParam()))){ if(one.getSParamValue().startsWith("d")){ if(Double.valueOf(argsOld.get(one.getSParam()).toString())>0){ markdown.append("") .append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" ") .append(" × ") .append(""); } }else{ markdown.append("") .append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" ") .append(" × ") .append(""); } } } }); markdown.append("\n\n"); } markdown.append("**结果**:"); String sStatus = erpResult.getCode()<0?ErrorCode.ERRORMSG.getMessage():ErrorCode.SUCCESSMSG.getMessage(); markdown.append(sStatus).append("\n"); if(erpResult.getCode()<0){ String sMsg = ObjectUtil.isEmpty(erpResult.getMsg())?ErrorCode.WFHYY.getMessage():erpResult.getMsg(); markdown.append("**原因**: ").append(sMsg); return markdown.toString(); }else{ markdown.append(" 共 ").append(recordCount).append(" 条记录"); if(rows.size() markdown.append(header).append(" | ")); markdown.append("\n|").append("---|".repeat(headers.size() + 1)).append("\n"); List> machineData = new LinkedList<>(); for (int i = 0; i < recordData.size(); i++) { String uniqueValue = recordData.get(i).get("sSlaveId") != null ? recordData.get(i).get("sSlaveId").toString() : ""; markdown.append("| ").append(i + 1).append(" | "); Map rMap = new HashMap<>(); for (String header : headers) { Object value = recordData.get(i)!= null ? recordData.get(i).get(header) : null; markdown.append(value != null ? value : "—").append(" | "); rMap.put(header,value); } rMap.put("sSlaveId",uniqueValue); rMap.put("唯一",uniqueValue); markdown.append(" HIDDEN_DATA:") .append(JSONUtil.toJsonStr(rMap)) .append(""); markdown.append("\n"); machineData.add(rMap); currentRowData.put(i + 1,recordData.get(i)); } markdown.append(">"); if(meta.getIBizType()==4){ markdown.append("\n---\n"); appendConfirmAll(markdown,meta.getSControlName()); } session.setCurrentRowData(currentRowData); return markdown.toString(); } public String buildDynamicSystemPrompt(UserSceneSession session) { String methodNo = session.getCurrentTool().getSMethodNo(); String rowJson = JSONUtil.toJsonStr(session.getCurrentRowData()); return """ 【极强约束·必须执行】 1. 禁止说话!禁止解释! 2. 必须调用工具! 3. 只输出标准工具调用JSON! 表格数据: %s 【解析规则】 1. 用户说“第N行” → 取对应sSlaveId 2. 用户说“全部确认” → 取所有sSlaveId 3. 多行用英文逗号拼接 【输出格式·绝对严格·必须照做】 你必须输出标准工具调用JSON,只输出这一段,不许加任何文字: { "name": "%s", "parameters": { "operateType": "全部确认/合并确认/单行确认", "sSlaveId": "id1,id2,id3" } } """.formatted(rowJson, methodNo); } private List> findFieldNameByChinese(List> sAIshowfieldShow,List> rows){ Map keyMappings = new HashMap<>(); List selectedKeys = new ArrayList<>(); sAIshowfieldShow.forEach(one->{ keyMappings.put(one.get("sName").toString(),one.get("label").toString()); if("sSlaveId".equals(one.get("sName"))){ keyMappings.put(one.get("sName").toString(),one.get("sName").toString()); } selectedKeys.add(one.get("sName").toString()); }); List> sRowData = getFilteredDataStream(rows,rows.size(),selectedKeys,keyMappings); return sRowData; } public List> getFilteredDataStream(List> rows, int limit, List selectedKeys, Map keyMappings) { if (rows == null || rows.isEmpty()) { return Collections.emptyList(); } return rows.stream() .limit(limit) .map(original -> { Map filtered = new HashMap<>(); selectedKeys.forEach(key -> { if (original.containsKey(key)) { filtered.put(keyMappings.get(key), original.get(key)); } }); return filtered.isEmpty() ? null : filtered; }) .filter(Objects::nonNull) .collect(Collectors.toList()); } private String buildConfirmUserMessage(ToolMeta meta, Map args) { StringBuilder markdown = new StringBuilder(); markdown.append("参数提取如下:\n\n"); List paramRuleData = meta.getParamRuleList(); paramRuleData.forEach(one->{ if(ObjectUtil.isNotEmpty(args.get(one.getSParam()))){ markdown.append("- **").append(one.getSParam()).append("**: ").append(args.get(one.getSParam())).append("\n"); } }); markdown.append("\n---\n"); appendConfirm(markdown,meta.getSControlName()); return markdown.toString(); } private String buildAskUserMessage(ToolMeta meta, List missing,Map arg) { StringBuilder sb = new StringBuilder(); sb.append("缺少参数请补全:\n"); List paramRuleData = meta.getParamRuleList(); for (String name : missing) { paramRuleData.stream() .filter(pd -> pd.getSParam().equals(name)) .findFirst() .ifPresentOrElse( pd -> { String sTs = ObjectUtil.isEmpty(pd.getSRuleTs())?StrUtil.EMPTY:pd.getSRuleTs(); sb.append("- **").append(name).append("**: "); if(ObjectUtil.isNotEmpty(pd.getSParamMissMemo()) && ObjectUtil.isNotEmpty(arg.get(pd.getSParam())) && ObjectUtil.isNotEmpty(sTs) ){ if(!("string".equals(pd.getSType()) && RuleCode.SQL.equals(pd.getSRule()) && ObjectUtil.isNotEmpty(pd.getSParamConfig()) )) { sb.append(StrUtil.format(pd.getSParamMissMemo(),sTs)); } }else if(ObjectUtil.isNotEmpty(sTs)){ sb.append(sTs); } sb.append("\n"); }, () -> sb.append("- ").append(name).append("\n") ); } return sb.toString(); } private String createEarlySuccessResult(ToolExecutionRequest request, String message) { return JSONUtil.toJsonStr(Map.of( "status", "success", "message", message, "executionCompleted", true, "data", successResult(request, message) )); } private String createTerminationResult(String message) { return JSONUtil.toJsonStr(Map.of( "status", "terminated", "message", message, "shouldContinue", false )); } private ToolExecutionResultMessage errorResult(ToolExecutionRequest request, String errorMsg) { return ToolExecutionResultMessage.from(request, errorMsg); } private ToolExecutionResultMessage successResult(ToolExecutionRequest request, String text) { return ToolExecutionResultMessage.from(request, text); } private String executeWithConfirmation(String initialResult, UserSceneSession session,ToolMeta meta) { Map step1Result = new HashMap<>(); step1Result.put("initialResult", initialResult); step1Result.put("status", "PENDING_CONFIRMATION"); step1Result.put("confirmationRequired", true); step1Result.put("confirmationMessage", initialResult); String userMessage = formatConfirmationResult(step1Result); session.setCurrentTool(meta); return userMessage; } private String formatConfirmationResult(Map result) { return String.format("%s", result.get("initialResult")); } public boolean isConfirmed(String userResponse) { return userResponse.matches("(?i)(确认|全部确认|部分确认|是|yes|confirm|true|是的|可以|没问题|确定|好的|生成|)"); } }