From 6e36ce73ad18b8ac3a2126cda660d0295b9c3824 Mon Sep 17 00:00:00 2001 From: qianbao Date: Wed, 20 May 2026 01:09:07 +0800 Subject: [PATCH] 添加未清选择 改成动态引导语 --- src/main/java/com/xly/agent/AgentSystemPrompt.java | 24 +++++++++++++++++------- src/main/java/com/xly/service/XlyErpService.java | 35 ++++++++++++++++++----------------- src/main/java/com/xly/tool/DynamicToolProvider.java | 51 +++++++++++++++++++++++++++------------------------ src/main/java/com/xly/util/ValiDataUtil.java | 31 +++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/xly/agent/AgentSystemPrompt.java b/src/main/java/com/xly/agent/AgentSystemPrompt.java index 32972dd..f9eb507 100644 --- a/src/main/java/com/xly/agent/AgentSystemPrompt.java +++ b/src/main/java/com/xly/agent/AgentSystemPrompt.java @@ -2,11 +2,21 @@ package com.xly.agent; public class AgentSystemPrompt { - public static final String sSystemPrompt= "1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下;\n" + - " 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容;\n" + - " 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容;\n" + - " 1.3 调用工具前,不需要询问用户提供缺失的参数\n" + - " 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下:\n" + - " 2.1 数字无引号,为空时禁止赋值0;\n" + - " 2.2 如果有空格需要去掉空格后再提取。"; +// public static final String sSystemPrompt= "1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下;\n" + +// " 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容;\n" + +// " 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容;\n" + +// " 1.3 调用工具前,不需要询问用户提供缺失的参数\n" + +// " 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下:\n" + +// " 2.1 数字无引号,为空时禁止赋值0;\n" + +// " 2.2 如果有空格需要去掉空格后再提取。"; + public static final String sSystemPrompt = "你是一个专业的智能助手,请根据以下规则精准匹配并调用工具:\n" + + "【核心决策逻辑】\n" + + "1. 单一工具场景:当系统仅提供一个可用工具时,除非用户是在进行无意义的闲聊(如打招呼),否则必须无条件调用该工具,禁止向用户索要额外信息或进行解释;\n" + + "2. 多工具场景:当系统提供多个工具时,必须先精准识别用户的核心业务意图,然后匹配唯一对应的工具进行调用;\n" + + "\n" + + "【参数提取与调用规范】\n" + + "3. 触发条件:匹配工具时,仅关注工具描述中“当用户”和“时,必须调用本工具”之间的语义关联,无需过度纠结参数的详细描述;\n" + + "4. 缺省处理:调用工具前,不需要询问用户提供缺失的参数。如果某个必填参数在用户输入中找不到,请直接省略该字段(不要填入\"\"、null或0);\n" + + "5. 格式要求:提取参数时严格按标注类型赋值,数字不带引号,字符串需去除首尾空格;\n" + + "6. 绝对禁止:在任何情况下,禁止向用户反问以确认参数或意图,你的输出只能是最终回复或合法的工具调用请求。"; } diff --git a/src/main/java/com/xly/service/XlyErpService.java b/src/main/java/com/xly/service/XlyErpService.java index d069f3b..b6afaa2 100644 --- a/src/main/java/com/xly/service/XlyErpService.java +++ b/src/main/java/com/xly/service/XlyErpService.java @@ -950,8 +950,7 @@ public class XlyErpService { }else {return null;} } // 4. 获取/创建用Agent - // ErpAiAgent aiAgent = UserSceneSessionService.ERP_AGENT_CACHE.get(userId); -// if(ObjectUtil.isEmpty(aiAgent)){ + ErpAiAgent aiAgent = UserSceneSessionService.ERP_AGENT_CACHE.get(userId); List dataList = dynamicToolProvider.sceneToolCacheMap.get(session.getCurrentScene().getSId()); List dataListOne = dataList.stream().filter(m-> @@ -961,26 +960,28 @@ public class XlyErpService { if(ObjectUtil.isNotEmpty(dataListOne)){ dataList = dataListOne; } - Set immediateReturnToolNames = new HashSet<>(); - Map executors = new HashMap<>(); - if(ObjectUtil.isNotEmpty(dataList)){ - dataList.forEach(one->{ - immediateReturnToolNames.add(one.getsName()); - executors.put(one.getToolSpecification(),one.getToolExecutor()); - }); - } - return AiServices.builder(ErpAiAgent.class) - .chatModel(chatModel) - .chatMemoryProvider(operableChatMemoryProvider) - .tools(executors,immediateReturnToolNames) + if(ObjectUtil.isEmpty(aiAgent) || ObjectUtil.isNotEmpty(dataListOne)){ + Set immediateReturnToolNames = new HashSet<>(); + Map executors = new HashMap<>(); + if(ObjectUtil.isNotEmpty(dataList)){ + dataList.forEach(one->{ + immediateReturnToolNames.add(one.getsName()); + executors.put(one.getToolSpecification(),one.getToolExecutor()); + }); + } + + aiAgent = AiServices.builder(ErpAiAgent.class) + .chatModel(chatModel) + .chatMemoryProvider(operableChatMemoryProvider) + .tools(executors,immediateReturnToolNames) // .toolProvider(dynamicToolProvider) // .returnBehavior(ReturnBehavior.IMMEDIATE) // .toolChoice(ChatCompletionToolChoice.ofRequired()) .build(); -// UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); + UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); // log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); -// } -// return aiAgent; + } + return aiAgent; } private ErpAiAgent createConfirmeAgent(UserSceneSession session) { diff --git a/src/main/java/com/xly/tool/DynamicToolProvider.java b/src/main/java/com/xly/tool/DynamicToolProvider.java index d355588..46ac50a 100644 --- a/src/main/java/com/xly/tool/DynamicToolProvider.java +++ b/src/main/java/com/xly/tool/DynamicToolProvider.java @@ -224,8 +224,7 @@ public class DynamicToolProvider implements ToolProvider { return String.valueOf(successResult(toolExecutionRequest, askMsg)); } // ====================== 返回时带终止指令 ====================== - String resp = JSONUtil.toJsonStr(finalArgs) ; -// String resp = doDynamicTool( meta, session); + String resp = JSONUtil.toJsonStr(args) ; return String.valueOf(successResult(toolExecutionRequest, resp)); }; } @@ -493,6 +492,7 @@ public class DynamicToolProvider implements ToolProvider { || 8== meta.getIBizType() ) { + //根据获取的参数获取数据 List missingAfter = checkConfirmAfterParam(args, paramRuleData); if (!missingAfter.isEmpty()) { //合并已选择数据 @@ -775,6 +775,8 @@ public class DynamicToolProvider implements ToolProvider { } if(meta.getIActionType()==1){ session.setBCleanMemory(true); + session.setArgs(new HashMap<>()); + session.setCurrentArgs(new HashMap<>()); } return sReturn; } @@ -802,6 +804,10 @@ public class DynamicToolProvider implements ToolProvider { throw new BusinessException(-1,"请选择操作数据"); } List> sRowData = doGetFromDataWq( meta, args, session); + if(ObjectUtil.isEmpty(sRowData)){ + session.setSFunPrompts("选择的数据ID:"+args.get("sSlaveId")+"不存在,请重新选择。"); + throw new BusinessException(-1,"选择的数据ID:"+args.get("sSlaveId")+"不存在,请重新选择。"); + } data.put("sRowData", JSONObject.toJSONString(sRowData)); } Map searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data); @@ -861,7 +867,7 @@ public class DynamicToolProvider implements ToolProvider { String sUrl = meta.getSendUrl(); Map sBody = new HashMap<>(); sBody.put("pageNum",1); - sBody.put("pageSize",10000); + sBody.put("pageSize",100); log.info("doGetFromData========================"); List> list = new ArrayList<>(); Map serOne = new HashMap<>(4); @@ -897,13 +903,15 @@ public class DynamicToolProvider implements ToolProvider { String sUrl = meta.getSendUrl(); Map sBody = new HashMap<>(); sBody.put("pageNum",1); - sBody.put("pageSize",10000); + sBody.put("pageSize",100); log.info("doGetFromData========================"); List> list = new ArrayList<>(); args.remove("operateType"); - if(ObjectUtil.isNotEmpty(args)){ - List paramDefs = meta.getParamRuleList(); - args.forEach((k,v)->{ + 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<>(); @@ -1049,32 +1057,27 @@ public class DynamicToolProvider implements ToolProvider { */ public String buildMissParamPrompt(UserSceneSession session, List paramRuleDataMiss) { String methodNo = session.getCurrentTool().getSMethodNo(); - String rowJson = JSONUtil.toJsonStr(session.getArgs()); + // 拼接缺失参数的描述 String paramDesc = paramRuleDataMiss.stream() .map(p -> p.getSParam() + ":" + p.getSParamValue() + ",示例:" + p.getSExampleValue()) .collect(Collectors.joining("\n")); - String paramKeys = paramRuleDataMiss.stream() + // 告诉模型需要补充哪些字段 + String missingKeys = paramRuleDataMiss.stream() .map(p -> "\"" + p.getSParamValue() + "\":\"\"") .collect(Collectors.joining(",")); return String.format(""" - 请你补充参数。 - - 【极强约束·必须100%%遵守】 - 1. 必须调用方法:%s - 2. 只输出标准JSON,禁止说话、禁止解释、禁止换行 - - 缺失参数: - %s - - 已填数据: - %s - - 输出格式: - {%s} - """, methodNo, paramDesc, rowJson, paramKeys); + 请你根据用户最新的输入补充缺失的参数,并带着所有完整参数立即发起工具调用。 + + 【执行规则】 + 1. 必须调用工具:%s,绝对禁止直接输出 JSON 文本或向用户索要信息; + 2. 完整调用:请带着合并后的所有参数,直接生成 tool_calls 请求。 + + 缺失参数说明: + %s + """, methodNo, paramDesc, missingKeys); } public String buildDynamicSystemPrompt(UserSceneSession session) { diff --git a/src/main/java/com/xly/util/ValiDataUtil.java b/src/main/java/com/xly/util/ValiDataUtil.java index 4902fb1..d94a76a 100644 --- a/src/main/java/com/xly/util/ValiDataUtil.java +++ b/src/main/java/com/xly/util/ValiDataUtil.java @@ -1,7 +1,14 @@ package com.xly.util; +import cn.hutool.core.util.ObjectUtil; +import com.xly.entity.ParamRule; import lombok.extern.slf4j.Slf4j; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + @Slf4j public class ValiDataUtil { @@ -22,5 +29,29 @@ public class ValiDataUtil { } + public static Map getArgs(Map argsNew, List paramDefs){ + Map rMap = new HashMap<>(); + try{ + if(ObjectUtil.isNotEmpty(argsNew)){ + argsNew.forEach((k,v)->{ + List pdList = paramDefs.stream().filter(m-> m.getSParam().equals(k) + || m.getSParamValue().equals(k) + ).collect(Collectors.toUnmodifiableList()); + if(ObjectUtil.isNotEmpty(pdList)){ + rMap.put(pdList.get(0).getSParamValue(),v); + } + }); + } + }catch (Exception e){ + + }finally { + rMap.remove("sSlaveId"); + rMap.remove("operateType"); + } + return rMap; + } + + + } -- libgit2 0.22.2