Commit 6e36ce73ad18b8ac3a2126cda660d0295b9c3824

Authored by qianbao
1 parent 5c38d571

添加未清选择 改成动态引导语

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 }