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 2  
3 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 950 }else {return null;}
951 951 }
952 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 954 List<ToolSpecificationHolder> dataList = dynamicToolProvider.sceneToolCacheMap.get(session.getCurrentScene().getSId());
956 955 List<ToolSpecificationHolder> dataListOne =
957 956 dataList.stream().filter(m->
... ... @@ -961,26 +960,28 @@ public class XlyErpService {
961 960 if(ObjectUtil.isNotEmpty(dataListOne)){
962 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 977 // .toolProvider(dynamicToolProvider)
977 978 // .returnBehavior(ReturnBehavior.IMMEDIATE)
978 979 // .toolChoice(ChatCompletionToolChoice.ofRequired())
979 980 .build();
980   -// UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent);
  981 + UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent);
981 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 987 private ErpAiAgent createConfirmeAgent(UserSceneSession session) {
... ...
src/main/java/com/xly/tool/DynamicToolProvider.java
... ... @@ -224,8 +224,7 @@ public class DynamicToolProvider implements ToolProvider {
224 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 228 return String.valueOf(successResult(toolExecutionRequest, resp));
230 229 };
231 230 }
... ... @@ -493,6 +492,7 @@ public class DynamicToolProvider implements ToolProvider {
493 492 || 8== meta.getIBizType()
494 493 )
495 494 {
  495 + //根据获取的参数获取数据
496 496 List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData);
497 497 if (!missingAfter.isEmpty()) {
498 498 //合并已选择数据
... ... @@ -775,6 +775,8 @@ public class DynamicToolProvider implements ToolProvider {
775 775 }
776 776 if(meta.getIActionType()==1){
777 777 session.setBCleanMemory(true);
  778 + session.setArgs(new HashMap<>());
  779 + session.setCurrentArgs(new HashMap<>());
778 780 }
779 781 return sReturn;
780 782 }
... ... @@ -802,6 +804,10 @@ public class DynamicToolProvider implements ToolProvider {
802 804 throw new BusinessException(-1,"请选择操作数据");
803 805 }
804 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 811 data.put("sRowData", JSONObject.toJSONString(sRowData));
806 812 }
807 813 Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data);
... ... @@ -861,7 +867,7 @@ public class DynamicToolProvider implements ToolProvider {
861 867 String sUrl = meta.getSendUrl();
862 868 Map<String,Object> sBody = new HashMap<>();
863 869 sBody.put("pageNum",1);
864   - sBody.put("pageSize",10000);
  870 + sBody.put("pageSize",100);
865 871 log.info("doGetFromData========================");
866 872 List<Map<String,Object>> list = new ArrayList<>();
867 873 Map<String,Object> serOne = new HashMap<>(4);
... ... @@ -897,13 +903,15 @@ public class DynamicToolProvider implements ToolProvider {
897 903 String sUrl = meta.getSendUrl();
898 904 Map<String,Object> sBody = new HashMap<>();
899 905 sBody.put("pageNum",1);
900   - sBody.put("pageSize",10000);
  906 + sBody.put("pageSize",100);
901 907 log.info("doGetFromData========================");
902 908 List<Map<String,Object>> list = new ArrayList<>();
903 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 915 if(ObjectUtil.isNotEmpty(v)){
908 916 List<ParamRule> pdList = paramDefs.stream().filter(m-> m.getSParam().equals(k) || m.getSParamValue().equals(k)).collect(Collectors.toUnmodifiableList());
909 917 List<Object> data = new ArrayList<>();
... ... @@ -1049,32 +1057,27 @@ public class DynamicToolProvider implements ToolProvider {
1049 1057 */
1050 1058 public String buildMissParamPrompt(UserSceneSession session, List<ParamRule> paramRuleDataMiss) {
1051 1059 String methodNo = session.getCurrentTool().getSMethodNo();
1052   - String rowJson = JSONUtil.toJsonStr(session.getArgs());
1053 1060  
  1061 + // 拼接缺失参数的描述
1054 1062 String paramDesc = paramRuleDataMiss.stream()
1055 1063 .map(p -> p.getSParam() + ":" + p.getSParamValue() + ",示例:" + p.getSExampleValue())
1056 1064 .collect(Collectors.joining("\n"));
1057 1065  
1058   - String paramKeys = paramRuleDataMiss.stream()
  1066 + // 告诉模型需要补充哪些字段
  1067 + String missingKeys = paramRuleDataMiss.stream()
1059 1068 .map(p -> "\"" + p.getSParamValue() + "\":\"\"")
1060 1069 .collect(Collectors.joining(","));
1061 1070  
1062 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 1083 public String buildDynamicSystemPrompt(UserSceneSession session) {
... ...
src/main/java/com/xly/util/ValiDataUtil.java
1 1 package com.xly.util;
2 2  
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import com.xly.entity.ParamRule;
3 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 12 @Slf4j
6 13 public class ValiDataUtil {
7 14  
... ... @@ -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 }
... ...