Commit 6e36ce73ad18b8ac3a2126cda660d0295b9c3824
1 parent
5c38d571
添加未清选择 改成动态引导语
Showing
4 changed files
with
93 additions
and
48 deletions
src/main/java/com/xly/agent/AgentSystemPrompt.java
| @@ -2,11 +2,21 @@ package com.xly.agent; | @@ -2,11 +2,21 @@ package com.xly.agent; | ||
| 2 | 2 | ||
| 3 | public class AgentSystemPrompt { | 3 | public class AgentSystemPrompt { |
| 4 | 4 | ||
| 5 | - public static final String sSystemPrompt= "1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下;\n" + | ||
| 6 | - " 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容;\n" + | ||
| 7 | - " 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容;\n" + | ||
| 8 | - " 1.3 调用工具前,不需要询问用户提供缺失的参数\n" + | ||
| 9 | - " 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下:\n" + | ||
| 10 | - " 2.1 数字无引号,为空时禁止赋值0;\n" + | ||
| 11 | - " 2.2 如果有空格需要去掉空格后再提取。"; | 5 | +// public static final String sSystemPrompt= "1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下;\n" + |
| 6 | +// " 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容;\n" + | ||
| 7 | +// " 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容;\n" + | ||
| 8 | +// " 1.3 调用工具前,不需要询问用户提供缺失的参数\n" + | ||
| 9 | +// " 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下:\n" + | ||
| 10 | +// " 2.1 数字无引号,为空时禁止赋值0;\n" + | ||
| 11 | +// " 2.2 如果有空格需要去掉空格后再提取。"; | ||
| 12 | + public static final String sSystemPrompt = "你是一个专业的智能助手,请根据以下规则精准匹配并调用工具:\n" + | ||
| 13 | + "【核心决策逻辑】\n" + | ||
| 14 | + "1. 单一工具场景:当系统仅提供一个可用工具时,除非用户是在进行无意义的闲聊(如打招呼),否则必须无条件调用该工具,禁止向用户索要额外信息或进行解释;\n" + | ||
| 15 | + "2. 多工具场景:当系统提供多个工具时,必须先精准识别用户的核心业务意图,然后匹配唯一对应的工具进行调用;\n" + | ||
| 16 | + "\n" + | ||
| 17 | + "【参数提取与调用规范】\n" + | ||
| 18 | + "3. 触发条件:匹配工具时,仅关注工具描述中“当用户”和“时,必须调用本工具”之间的语义关联,无需过度纠结参数的详细描述;\n" + | ||
| 19 | + "4. 缺省处理:调用工具前,不需要询问用户提供缺失的参数。如果某个必填参数在用户输入中找不到,请直接省略该字段(不要填入\"\"、null或0);\n" + | ||
| 20 | + "5. 格式要求:提取参数时严格按标注类型赋值,数字不带引号,字符串需去除首尾空格;\n" + | ||
| 21 | + "6. 绝对禁止:在任何情况下,禁止向用户反问以确认参数或意图,你的输出只能是最终回复或合法的工具调用请求。"; | ||
| 12 | } | 22 | } |
src/main/java/com/xly/service/XlyErpService.java
| @@ -950,8 +950,7 @@ public class XlyErpService { | @@ -950,8 +950,7 @@ public class XlyErpService { | ||
| 950 | }else {return null;} | 950 | }else {return null;} |
| 951 | } | 951 | } |
| 952 | // 4. 获取/创建用Agent | 952 | // 4. 获取/创建用Agent |
| 953 | - // ErpAiAgent aiAgent = UserSceneSessionService.ERP_AGENT_CACHE.get(userId); | ||
| 954 | -// if(ObjectUtil.isEmpty(aiAgent)){ | 953 | + ErpAiAgent aiAgent = UserSceneSessionService.ERP_AGENT_CACHE.get(userId); |
| 955 | List<ToolSpecificationHolder> dataList = dynamicToolProvider.sceneToolCacheMap.get(session.getCurrentScene().getSId()); | 954 | List<ToolSpecificationHolder> dataList = dynamicToolProvider.sceneToolCacheMap.get(session.getCurrentScene().getSId()); |
| 956 | List<ToolSpecificationHolder> dataListOne = | 955 | List<ToolSpecificationHolder> dataListOne = |
| 957 | dataList.stream().filter(m-> | 956 | dataList.stream().filter(m-> |
| @@ -961,26 +960,28 @@ public class XlyErpService { | @@ -961,26 +960,28 @@ public class XlyErpService { | ||
| 961 | if(ObjectUtil.isNotEmpty(dataListOne)){ | 960 | if(ObjectUtil.isNotEmpty(dataListOne)){ |
| 962 | dataList = dataListOne; | 961 | dataList = dataListOne; |
| 963 | } | 962 | } |
| 964 | - Set<String> immediateReturnToolNames = new HashSet<>(); | ||
| 965 | - Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | ||
| 966 | - if(ObjectUtil.isNotEmpty(dataList)){ | ||
| 967 | - dataList.forEach(one->{ | ||
| 968 | - immediateReturnToolNames.add(one.getsName()); | ||
| 969 | - executors.put(one.getToolSpecification(),one.getToolExecutor()); | ||
| 970 | - }); | ||
| 971 | - } | ||
| 972 | - return AiServices.builder(ErpAiAgent.class) | ||
| 973 | - .chatModel(chatModel) | ||
| 974 | - .chatMemoryProvider(operableChatMemoryProvider) | ||
| 975 | - .tools(executors,immediateReturnToolNames) | 963 | + if(ObjectUtil.isEmpty(aiAgent) || ObjectUtil.isNotEmpty(dataListOne)){ |
| 964 | + Set<String> immediateReturnToolNames = new HashSet<>(); | ||
| 965 | + Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); | ||
| 966 | + if(ObjectUtil.isNotEmpty(dataList)){ | ||
| 967 | + dataList.forEach(one->{ | ||
| 968 | + immediateReturnToolNames.add(one.getsName()); | ||
| 969 | + executors.put(one.getToolSpecification(),one.getToolExecutor()); | ||
| 970 | + }); | ||
| 971 | + } | ||
| 972 | + | ||
| 973 | + aiAgent = AiServices.builder(ErpAiAgent.class) | ||
| 974 | + .chatModel(chatModel) | ||
| 975 | + .chatMemoryProvider(operableChatMemoryProvider) | ||
| 976 | + .tools(executors,immediateReturnToolNames) | ||
| 976 | // .toolProvider(dynamicToolProvider) | 977 | // .toolProvider(dynamicToolProvider) |
| 977 | // .returnBehavior(ReturnBehavior.IMMEDIATE) | 978 | // .returnBehavior(ReturnBehavior.IMMEDIATE) |
| 978 | // .toolChoice(ChatCompletionToolChoice.ofRequired()) | 979 | // .toolChoice(ChatCompletionToolChoice.ofRequired()) |
| 979 | .build(); | 980 | .build(); |
| 980 | -// UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); | 981 | + UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); |
| 981 | // log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); | 982 | // log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); |
| 982 | -// } | ||
| 983 | -// return aiAgent; | 983 | + } |
| 984 | + return aiAgent; | ||
| 984 | } | 985 | } |
| 985 | 986 | ||
| 986 | private ErpAiAgent createConfirmeAgent(UserSceneSession session) { | 987 | private ErpAiAgent createConfirmeAgent(UserSceneSession session) { |
src/main/java/com/xly/tool/DynamicToolProvider.java
| @@ -224,8 +224,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -224,8 +224,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 224 | return String.valueOf(successResult(toolExecutionRequest, askMsg)); | 224 | return String.valueOf(successResult(toolExecutionRequest, askMsg)); |
| 225 | } | 225 | } |
| 226 | // ====================== 返回时带终止指令 ====================== | 226 | // ====================== 返回时带终止指令 ====================== |
| 227 | - String resp = JSONUtil.toJsonStr(finalArgs) ; | ||
| 228 | -// String resp = doDynamicTool( meta, session); | 227 | + String resp = JSONUtil.toJsonStr(args) ; |
| 229 | return String.valueOf(successResult(toolExecutionRequest, resp)); | 228 | return String.valueOf(successResult(toolExecutionRequest, resp)); |
| 230 | }; | 229 | }; |
| 231 | } | 230 | } |
| @@ -493,6 +492,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -493,6 +492,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 493 | || 8== meta.getIBizType() | 492 | || 8== meta.getIBizType() |
| 494 | ) | 493 | ) |
| 495 | { | 494 | { |
| 495 | + //根据获取的参数获取数据 | ||
| 496 | List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); | 496 | List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); |
| 497 | if (!missingAfter.isEmpty()) { | 497 | if (!missingAfter.isEmpty()) { |
| 498 | //合并已选择数据 | 498 | //合并已选择数据 |
| @@ -775,6 +775,8 @@ public class DynamicToolProvider implements ToolProvider { | @@ -775,6 +775,8 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 775 | } | 775 | } |
| 776 | if(meta.getIActionType()==1){ | 776 | if(meta.getIActionType()==1){ |
| 777 | session.setBCleanMemory(true); | 777 | session.setBCleanMemory(true); |
| 778 | + session.setArgs(new HashMap<>()); | ||
| 779 | + session.setCurrentArgs(new HashMap<>()); | ||
| 778 | } | 780 | } |
| 779 | return sReturn; | 781 | return sReturn; |
| 780 | } | 782 | } |
| @@ -802,6 +804,10 @@ public class DynamicToolProvider implements ToolProvider { | @@ -802,6 +804,10 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 802 | throw new BusinessException(-1,"请选择操作数据"); | 804 | throw new BusinessException(-1,"请选择操作数据"); |
| 803 | } | 805 | } |
| 804 | List<Map<String,Object>> sRowData = doGetFromDataWq( meta, args, session); | 806 | List<Map<String,Object>> sRowData = doGetFromDataWq( meta, args, session); |
| 807 | + if(ObjectUtil.isEmpty(sRowData)){ | ||
| 808 | + session.setSFunPrompts("选择的数据ID:"+args.get("sSlaveId")+"不存在,请重新选择。"); | ||
| 809 | + throw new BusinessException(-1,"选择的数据ID:"+args.get("sSlaveId")+"不存在,请重新选择。"); | ||
| 810 | + } | ||
| 805 | data.put("sRowData", JSONObject.toJSONString(sRowData)); | 811 | data.put("sRowData", JSONObject.toJSONString(sRowData)); |
| 806 | } | 812 | } |
| 807 | Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data); | 813 | Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data); |
| @@ -861,7 +867,7 @@ public class DynamicToolProvider implements ToolProvider { | @@ -861,7 +867,7 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 861 | String sUrl = meta.getSendUrl(); | 867 | String sUrl = meta.getSendUrl(); |
| 862 | Map<String,Object> sBody = new HashMap<>(); | 868 | Map<String,Object> sBody = new HashMap<>(); |
| 863 | sBody.put("pageNum",1); | 869 | sBody.put("pageNum",1); |
| 864 | - sBody.put("pageSize",10000); | 870 | + sBody.put("pageSize",100); |
| 865 | log.info("doGetFromData========================"); | 871 | log.info("doGetFromData========================"); |
| 866 | List<Map<String,Object>> list = new ArrayList<>(); | 872 | List<Map<String,Object>> list = new ArrayList<>(); |
| 867 | Map<String,Object> serOne = new HashMap<>(4); | 873 | Map<String,Object> serOne = new HashMap<>(4); |
| @@ -897,13 +903,15 @@ public class DynamicToolProvider implements ToolProvider { | @@ -897,13 +903,15 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 897 | String sUrl = meta.getSendUrl(); | 903 | String sUrl = meta.getSendUrl(); |
| 898 | Map<String,Object> sBody = new HashMap<>(); | 904 | Map<String,Object> sBody = new HashMap<>(); |
| 899 | sBody.put("pageNum",1); | 905 | sBody.put("pageNum",1); |
| 900 | - sBody.put("pageSize",10000); | 906 | + sBody.put("pageSize",100); |
| 901 | log.info("doGetFromData========================"); | 907 | log.info("doGetFromData========================"); |
| 902 | List<Map<String,Object>> list = new ArrayList<>(); | 908 | List<Map<String,Object>> list = new ArrayList<>(); |
| 903 | args.remove("operateType"); | 909 | args.remove("operateType"); |
| 904 | - if(ObjectUtil.isNotEmpty(args)){ | ||
| 905 | - List<ParamRule> paramDefs = meta.getParamRuleList(); | ||
| 906 | - args.forEach((k,v)->{ | 910 | + Map<String, Object> argsDeep = DeepCopyUtils.deepCopy(args); |
| 911 | + List<ParamRule> paramDefs = meta.getParamRuleList(); | ||
| 912 | + Map<String, Object> argsNew =ValiDataUtil.getArgs( argsDeep, paramDefs); | ||
| 913 | + if(ObjectUtil.isNotEmpty(argsNew)){ | ||
| 914 | + argsNew.forEach((k,v)->{ | ||
| 907 | if(ObjectUtil.isNotEmpty(v)){ | 915 | if(ObjectUtil.isNotEmpty(v)){ |
| 908 | List<ParamRule> pdList = paramDefs.stream().filter(m-> m.getSParam().equals(k) || m.getSParamValue().equals(k)).collect(Collectors.toUnmodifiableList()); | 916 | List<ParamRule> pdList = paramDefs.stream().filter(m-> m.getSParam().equals(k) || m.getSParamValue().equals(k)).collect(Collectors.toUnmodifiableList()); |
| 909 | List<Object> data = new ArrayList<>(); | 917 | List<Object> data = new ArrayList<>(); |
| @@ -1049,32 +1057,27 @@ public class DynamicToolProvider implements ToolProvider { | @@ -1049,32 +1057,27 @@ public class DynamicToolProvider implements ToolProvider { | ||
| 1049 | */ | 1057 | */ |
| 1050 | public String buildMissParamPrompt(UserSceneSession session, List<ParamRule> paramRuleDataMiss) { | 1058 | public String buildMissParamPrompt(UserSceneSession session, List<ParamRule> paramRuleDataMiss) { |
| 1051 | String methodNo = session.getCurrentTool().getSMethodNo(); | 1059 | String methodNo = session.getCurrentTool().getSMethodNo(); |
| 1052 | - String rowJson = JSONUtil.toJsonStr(session.getArgs()); | ||
| 1053 | 1060 | ||
| 1061 | + // 拼接缺失参数的描述 | ||
| 1054 | String paramDesc = paramRuleDataMiss.stream() | 1062 | String paramDesc = paramRuleDataMiss.stream() |
| 1055 | .map(p -> p.getSParam() + ":" + p.getSParamValue() + ",示例:" + p.getSExampleValue()) | 1063 | .map(p -> p.getSParam() + ":" + p.getSParamValue() + ",示例:" + p.getSExampleValue()) |
| 1056 | .collect(Collectors.joining("\n")); | 1064 | .collect(Collectors.joining("\n")); |
| 1057 | 1065 | ||
| 1058 | - String paramKeys = paramRuleDataMiss.stream() | 1066 | + // 告诉模型需要补充哪些字段 |
| 1067 | + String missingKeys = paramRuleDataMiss.stream() | ||
| 1059 | .map(p -> "\"" + p.getSParamValue() + "\":\"\"") | 1068 | .map(p -> "\"" + p.getSParamValue() + "\":\"\"") |
| 1060 | .collect(Collectors.joining(",")); | 1069 | .collect(Collectors.joining(",")); |
| 1061 | 1070 | ||
| 1062 | return String.format(""" | 1071 | return String.format(""" |
| 1063 | - 请你补充参数。 | ||
| 1064 | - | ||
| 1065 | - 【极强约束·必须100%%遵守】 | ||
| 1066 | - 1. 必须调用方法:%s | ||
| 1067 | - 2. 只输出标准JSON,禁止说话、禁止解释、禁止换行 | ||
| 1068 | - | ||
| 1069 | - 缺失参数: | ||
| 1070 | - %s | ||
| 1071 | - | ||
| 1072 | - 已填数据: | ||
| 1073 | - %s | ||
| 1074 | - | ||
| 1075 | - 输出格式: | ||
| 1076 | - {%s} | ||
| 1077 | - """, methodNo, paramDesc, rowJson, paramKeys); | 1072 | + 请你根据用户最新的输入补充缺失的参数,并带着所有完整参数立即发起工具调用。 |
| 1073 | + | ||
| 1074 | + 【执行规则】 | ||
| 1075 | + 1. 必须调用工具:%s,绝对禁止直接输出 JSON 文本或向用户索要信息; | ||
| 1076 | + 2. 完整调用:请带着合并后的所有参数,直接生成 tool_calls 请求。 | ||
| 1077 | + | ||
| 1078 | + 缺失参数说明: | ||
| 1079 | + %s | ||
| 1080 | + """, methodNo, paramDesc, missingKeys); | ||
| 1078 | } | 1081 | } |
| 1079 | 1082 | ||
| 1080 | public String buildDynamicSystemPrompt(UserSceneSession session) { | 1083 | public String buildDynamicSystemPrompt(UserSceneSession session) { |
src/main/java/com/xly/util/ValiDataUtil.java
| 1 | package com.xly.util; | 1 | package com.xly.util; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.ObjectUtil; | ||
| 4 | +import com.xly.entity.ParamRule; | ||
| 3 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 4 | 6 | ||
| 7 | +import java.util.HashMap; | ||
| 8 | +import java.util.List; | ||
| 9 | +import java.util.Map; | ||
| 10 | +import java.util.stream.Collectors; | ||
| 11 | + | ||
| 5 | @Slf4j | 12 | @Slf4j |
| 6 | public class ValiDataUtil { | 13 | public class ValiDataUtil { |
| 7 | 14 | ||
| @@ -22,5 +29,29 @@ public class ValiDataUtil { | @@ -22,5 +29,29 @@ public class ValiDataUtil { | ||
| 22 | } | 29 | } |
| 23 | 30 | ||
| 24 | 31 | ||
| 32 | + public static Map<String, Object> getArgs(Map<String, Object> argsNew, List<ParamRule> paramDefs){ | ||
| 33 | + Map<String, Object> rMap = new HashMap<>(); | ||
| 34 | + try{ | ||
| 35 | + if(ObjectUtil.isNotEmpty(argsNew)){ | ||
| 36 | + argsNew.forEach((k,v)->{ | ||
| 37 | + List<ParamRule> pdList = paramDefs.stream().filter(m-> m.getSParam().equals(k) | ||
| 38 | + || m.getSParamValue().equals(k) | ||
| 39 | + ).collect(Collectors.toUnmodifiableList()); | ||
| 40 | + if(ObjectUtil.isNotEmpty(pdList)){ | ||
| 41 | + rMap.put(pdList.get(0).getSParamValue(),v); | ||
| 42 | + } | ||
| 43 | + }); | ||
| 44 | + } | ||
| 45 | + }catch (Exception e){ | ||
| 46 | + | ||
| 47 | + }finally { | ||
| 48 | + rMap.remove("sSlaveId"); | ||
| 49 | + rMap.remove("operateType"); | ||
| 50 | + } | ||
| 51 | + return rMap; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + | ||
| 55 | + | ||
| 25 | 56 | ||
| 26 | } | 57 | } |