package com.xly.tool; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.BooleanUtil; 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.*; 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(),meta.getSMethodName())); 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(),meta.getSMethodName())); 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); addSystemMessage(session, askMsg); // 需要提问用户 → 抛异常停止循环 throw new RuntimeException(askMsg); } // 2.1 【自动补全】应用参数的默认值 List paramRuleData = meta.getParamRuleListAll(); args = applyDefaultValues(args, paramRuleData); //客户选择行号转sSLaveId if(ObjectUtil.isNotEmpty(args) &&( (args.containsKey("rowNumbers") && ObjectUtil.isNotEmpty(args.get("rowNumbers"))) || (args.containsKey("operateType") && "全部确认".equals(args.get("operateType"))) )&& ObjectUtil.isNotEmpty(session.getCurrentRowData()) ){ doSetSlaveIdToArgs( args, session); } session.setArgs(args); // 3. 【自动校验】检查必填项 List missing = checkRequiredParams(args, paramRuleData); if (!missing.isEmpty()) { // 4.1 参数缺失,生成“提问”消息,直接返给客户 String askMsg = buildAskUserMessage(meta, missing,args); session.setSFunPrompts(askMsg); addSystemMessage(session, askMsg); return String.valueOf(successResult(toolExecutionRequest, askMsg)); } // ====================== 返回时带终止指令 ====================== String resp = JSONUtil.toJsonStr(args) ; return String.valueOf(successResult(toolExecutionRequest, resp)); }; } private void doSetSlaveIdToArgs(Map args,UserSceneSession session){ Map> data = session.getCurrentRowData(); List sSlaveIds = new ArrayList<>(); try{ if(args.containsKey("operateType") && "全部确认".equals(args.get("operateType"))){ data.forEach((k,v)->{ sSlaveIds.add(v.get("sSlaveId").toString()); }); return; } List rowNumbers = (List) args.get("rowNumbers"); rowNumbers.forEach(one->{ try{ sSlaveIds.add(data.get(one).get("sSlaveId").toString()); }catch (Exception e){ } }); }finally { args.put("sSlaveId",String.join(",",sSlaveIds)); args.remove("rowNumbers"); } } 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. 当用户输入包含【数据确认】、确认数据、确认、第*条数据确认时,必须调用本工具 """; // String forceToolPrompt = """ // 【工具调用规则】 // 1. 每个自定义方法最多只能调用 1 次 // 2. 只要方法返回结果,必须停止调用 // 3. 禁止重复调用同一个方法 // 4. 禁止无意义循环调用 // 5. 当用户输入包含【数据确认】、确认数据、确认、第*条数据确认时,必须调用本工具 // """; 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 = getArrrayBySql(paramRule); // 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; case "date": case "datetime": // 核心技巧:在描述中强制要求 AI 进行格式转换 String dateDesc = paramDesc + "。【重要】请将用户输入的任意日期(如'明天'、'2026/5/1'、'下周三')自动转换为 'yyyy-MM-dd' 格式的字符串,当前日期:"+ DateUtil.now() +"。"; schemaBuilder.addStringProperty(paramDesc, dateDesc); if (bEmpty) { requiredParams.add(paramDesc); } break; default: schemaBuilder.addStringProperty(paramDesc, paramDesc); break; } if (bEmpty) { requiredParams.add(paramDesc); } } } catch (Exception e) { e.printStackTrace(); } List requiredParamsNew = new ArrayList<>(); if(requiredParams!=null && requiredParams.size()>0){ requiredParamsNew.add(requiredParams.get(0)); } if (meta.getIBizType() == 4 || meta.getIBizType() == 5) { schemaBuilder.addStringProperty("operateType", "操作类型:全部确认/合并确认/单行确认"); requiredParams.add("operateType"); requiredParamsNew.add("operateType"); } if (!requiredParams.isEmpty()) { schemaBuilder.required(requiredParamsNew); } 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 getConstMeg(paramRule); } 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 argsOld = session.getArgs(); if(ObjectUtil.isEmpty(argsOld)){ argsOld = new HashMap<>(); } Map args = session.getArgs(); List missing = checkRequiredParams(args, paramRuleDataCheck); if (!missing.isEmpty()) { String askMsg = buildAskUserMessage(meta, missing,args); addSystemMessage(session, askMsg); 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,session); 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()) { //合并已选择数据 argsOld.putAll(args); session.setArgs(argsOld); String askMsg = buildAskUserMessage(meta, missingAfter,args); session.setSFunPrompts(askMsg); List paramRuleDataMiss = getMissParamRuleAfter(args, paramRuleData); String sSystemPrompt = buildMissParamPrompt(session,paramRuleDataMiss); session.setSSystemPrompt(sSystemPrompt); addSystemMessage(session, askMsg); return 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])); result.put(name, dataList.get(0).get(sValue)); } } } 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())))); } /*** * @Author 钱豹 * @Date 1:08 2026/5/19 * @Param [args, paramDefs] * @return java.util.List * @Description 获取缺失参数提示 **/ private List checkConfirmAfterParam(Map args, List paramDefs) { List paramRuleList = getMissParamRuleAfter( args, paramDefs); return paramRuleList.stream() .map(ParamRule::getSParam) .toList(); } /*** * @Author 钱豹 * @Date 2026/5/19 * @Param [args, paramDefs] * @return java.util.List * @Description 获取保存后的缺失参数 **/ private List getMissParamRuleAfter(Map args, List paramDefs) { Map returnMap = transformationArgs( args, paramDefs); return paramDefs.stream() .filter(pd -> ObjectUtil.isNotEmpty(pd.getBConfirmAfter()) && BooleanUtil.toBoolean(pd.getBConfirmAfter().toString())) .filter(pd -> (!returnMap.containsKey(pd.getSParam()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam())))) && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) ) .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); session.setArgs(new HashMap<>()); session.setCurrentArgs(new HashMap<>()); } 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"))){ //插入AI记忆 String sMsg = "请选择操作数据"; Map sessA = session.getArgs(); sessA.remove("sSlaveId"); sessA.remove("operateType"); session.setArgs(sessA); addSystemMessage(session, sMsg); throw new BusinessException(-1,sMsg); } List> sRowData = doGetFromDataWq( meta, args, session); if(ObjectUtil.isEmpty(sRowData)){ String sMsg = "选择的数据ID:"+args.get("sSlaveId")+"不存在,请重新选择。"; session.setSFunPrompts(sMsg); Map sessA = session.getArgs(); sessA.remove("sSlaveId"); sessA.remove("operateType"); session.setArgs(sessA); //插入AI记忆 addSystemMessage(session, sMsg); throw new BusinessException(-1,sMsg); } Map dataOne = DeepCopyUtils.deepCopy(args); dataOne.remove("sSlaveId"); dataOne.remove("sId"); sRowData.forEach(one->{ one.putAll(dataOne); }); 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); addSystemMessage(session, sMsgText); throw new BusinessException(-1,sMsgText); } } } else if (iBizType == 3) { return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), new HashMap<>(), "POST", "JSON"); } return "操作成功"; } private void addSystemMessage(UserSceneSession session,String sMsg){ // if(ObjectUtil.isNotEmpty(operableChatMemoryProvider) && ObjectUtil.isNotEmpty(operableChatMemoryProvider.get(session.getUserId()))){ // operableChatMemoryProvider.get(session.getUserId()).add(SystemMessage.from("上一次工具调用失败。原因:" + sMsg + "。请根据用户意图修正参数,并再次调用工具。")); // } } private List> doGetFromDataWq(ToolMeta meta, Map args,UserSceneSession session){ String sUrl = meta.getSendUrl(); Map sBody = new HashMap<>(); sBody.put("pageNum",1); sBody.put("pageSize",100); log.info("doGetFromData========================"); List> list = new ArrayList<>(); Map serOne = new HashMap<>(4); if(ObjectUtil.isEmpty(args.get("sSlaveId"))){ return new ArrayList<>(); } String sSlaveId = StrUtil.EMPTY; if(args.get("sSlaveId") instanceof List){ List sSlaveIds = (List) args.get("sSlaveId"); sSlaveId = String.join(",",sSlaveIds); }else{ sSlaveId = args.get("sSlaveId").toString(); } serOne.put("bFilterCondition","IN"); serOne.put("bFilterValue",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",100); log.info("doGetFromData========================"); List> list = new ArrayList<>(); args.remove("operateType"); Map argsDeep = DeepCopyUtils.deepCopy(args); List paramDefs = meta.getParamRuleList(); Map argsNew =ValiDataUtil.getArgs( argsDeep, paramDefs); if(ObjectUtil.isNotEmpty(argsNew)){ argsNew.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); Map cMap = new HashMap<>(); cMap.put("sSlaveId",uniqueValue); currentRowData.put(i + 1,cMap); } markdown.append(">"); if(meta.getIBizType()==4){ markdown.append("\n---\n"); appendConfirmAll(markdown,meta.getSControlName()); } session.setCurrentRowData(currentRowData); return markdown.toString(); } /** * 缺失参数统一提示模板:强制AI调用自定义方法,一次性回填所有参数 */ public String buildMissParamPrompt(UserSceneSession session, List paramRuleDataMiss) { String methodNo = session.getCurrentTool().getSMethodNo(); // 1. 拼接缺失参数的描述(增加“参数名”和“英文名”的对应,方便模型映射) String paramDesc = paramRuleDataMiss.stream() .map(p -> String.format("- 参数名:%s (对应字段: %s),示例值:%s", p.getSParam(), p.getSParamValue(), p.getSExampleValue())) .collect(Collectors.joining("\n")); // 但根据你的需求,其实 prompt 里并不需要强行插入一个空的 JSON 片段, // 直接告诉模型去“合并”即可。 return String.format(""" 请你根据用户最新的输入,补充缺失的参数,并带着【所有完整参数】立即发起工具调用。 【核心执行规则】 1. **参数合并(至关重要)**:你必须保留上一轮对话中已经获取的参数(如 sSlaveId, operateType 等),并将用户本次提供的新参数与旧参数合并。 2. **必须调用工具**:必须调用工具 `%s`。绝对禁止直接输出 JSON 文本,也绝对禁止向用户反问或索要信息。 3. **完整调用**:请直接生成包含所有参数的 tool_calls 请求。 【已获取数据】 %s 【当前缺失的参数说明】 %s """, methodNo,JSONObject.toJSONString(session.getArgs()), paramDesc); } public String buildDynamicSystemPrompt(UserSceneSession session) { // 获取当前工具编号(用于 JSON 的 name 字段) String methodNo = session.getCurrentTool().getSMethodNo(); return """ 【极强约束·必须执行】 1. 禁止说话!禁止解释! 2. 必须调用工具! 3. 只输出标准工具调用JSON! ### 任务背景 ### 用户会输入自然语言指令(如“第1行确认”、“全部合并”等)。 你的任务是:解析出【操作类型】和【目标行号】。 ### 解析规则(必须严格遵守) ### 1. **操作类型 (operateType)**: - 如果用户说“全部确认”、“生成多个单据”,识别为:"全部确认" - 如果用户说“合并确认”、“生成一个单据”,识别为:"合并确认" - 其他情况,默认为:"单行确认" 2. **行号提取 (rowNumbers)**: - 单选:如“第5行”,提取为 [5] - 多选:如“第1、3、5行”,提取为 [1, 3, 5] - 范围:如“第2到4行”,提取为 [2, 3, 4] - 全选:如“全部”、“所有”,提取为 ["ALL"] ### 输出格式规范 ### 请直接输出以下 JSON(不要任何 Markdown 格式,不要 ```json): {"name": "%s", "parameters": {"operateType": "解析出的类型", "rowNumbers": [行号数组或"ALL"]}} """.formatted(methodNo); } // public String buildDynamicSystemPrompt(UserSceneSession session) { // // 获取当前工具编号 // String methodNo = session.getCurrentTool().getSMethodNo(); // // 格式化表格数据(保持缩进,方便模型阅读) // String rowJson = JSONUtil.toJsonPrettyStr(session.getCurrentRowData()); // // return """ // 【极强约束·必须执行】 // 1. 禁止说话!禁止解释! // 2. 必须调用工具! // 3. 只输出标准工具调用JSON! // // ### 任务背景 ### // 用户会输入类似“第5行确认”或“确认第3条”的指令。 // 你的任务是:解析行号 -> 在下方表格中找到对应行 -> 提取 sSlaveId -> 调用工具。 // // ### 数据源(表格 key 是行号) ### // %s // // ### 防错黄金法则(必须严格遵守) ### // 1. **查找阶段**:不要凭空编造 ID。必须先在“思考步骤”中明确写出: // “用户输入是[xx],提取行号[N] -> 查找表格 Key=[N] -> 对应的 sSlaveId 是 [这里填入表格里的完整数字]” // 2. **复制阶段**:sSlaveId 是一长串数字,请务必**直接复制**表格中的原始值,不要加省略号(...),不要改变数字。 // 3. **输出阶段**:只有确认复制无误后,才在 JSON 的 sSlaveId 字段中填入该值。 // // ### 输出格式规范 ### // {"name": "%s", "parameters": {"operateType": "单行确认", "sSlaveId": "在这里填入你从表格中复制的ID"}} // // ### 执行流程(一步一步来) ### // 1. **解析**:阅读用户输入,确定他想操作的是第几行(N)。 // 2. **思考**:在回复的第一行,写出你的查找过程(例如:用户要求第5行...)。 // 3. **JSON**:换行后,输出最终的工具调用 JSON。 // // 【警告】 // 如果用户要求的行号在表格中不存在,请返回错误信息,不要调用工具。 // """.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,UserSceneSession session) { boolean check = userResponse.matches("(?i)(确认|全部确认|部分确认|是|yes|confirm|true|是的|可以|没问题|确定|好的|生成|)"); return check || userResponse.contains("生成") || userResponse.contains("确认") || (ObjectUtil.isNotEmpty(session.getArgs()) && session.getArgs().containsKey("operateType") && session.getArgs().containsKey("sSlaveId") && ObjectUtil.isNotEmpty(session.getArgs().get("sSlaveId")) ); } }