Commit 6f97d3bd65770adab7dd3f9224d605f8670fc8c1

Authored by qianbao
1 parent 06ca6a05

AI 对于时间的处理

src/main/java/com/xly/agent/DynamicTableNl2SqlAiAgent.java
@@ -28,27 +28,34 @@ public interface DynamicTableNl2SqlAiAgent { @@ -28,27 +28,34 @@ public interface DynamicTableNl2SqlAiAgent {
28 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>''; 28 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>'';
29 3.5 SQL所有的查询条件,如果是日期类型的字段,均需要加不为空判断,用示例格式判断,示例:tmakedate is not Null; 29 3.5 SQL所有的查询条件,如果是日期类型的字段,均需要加不为空判断,用示例格式判断,示例:tmakedate is not Null;
30 3.6 SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期 30 3.6 SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期
31 - 4. 安全约束:禁止生成任何DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等),禁止使用子查询、存储过程、自定义函数、临时表; 31 + 3.7 在AVG聚合函数中不允许使用LAG、LEAD 等窗口函数
  32 + 3.8 AVG(LAG(...))这种嵌套是不允许的
  33 + 3.9 GROUP BY 后面不允许使用窗口函数
  34 + 4. 安全约束:
  35 + - 禁止:DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等)
  36 + - 禁止:存储过程、自定义函数、临时表
  37 + - 允许:子查询(当需要使用窗口函数LAG/ROW_NUMBER等时)
  38 + - 允许:CTE公用表表达式(WITH语句)
32 5. 精准性: 39 5. 精准性:
33 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件; 40 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件;
34 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件 41 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件
35 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。 42 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。
36 7. 当前时间:{{sDataNow}} 43 7. 当前时间:{{sDataNow}}
37 8. 时间处理规则: 44 8. 时间处理规则:
38 - 8.1 当前系统时间:{{sDataNow}}(格式:yyyy年MM月dd日HH时mm分ss秒)  
39 - 8.2 用户需求中的相对时间概念,必须基于{{sDataNow}}进行转换:  
40 - - "本年" → 当前年份:{{sDataNow}}的年份  
41 - - "本月" → 当前月份:{{sDataNow}}的年份和月份  
42 - - "本季度" → 当前季度:基于{{sDataNow}}计算  
43 - - "本日/今天" → {{sDataNow}}的具体日期  
44 - - "昨天" → {{sDataNow}}减1天  
45 - - "本周" → 基于{{sDataNow}}计算周一到周日  
46 - - "近7天" → {{sDataNow}}减7天到{{sDataNow}}  
47 - 8.3 示例转换:  
48 - 当前时间:2024-03-15  
49 - 用户说"查询本年数据" → 查询条件应为:YEAR(日期字段) = 2024  
50 - 用户说"查询本月数据" → 查询条件应为:YEAR(日期字段) = 2024 AND MONTH(日期字段) = 3  
51 - 8.4 如果用户需求中没有明确的时间条件,禁止增加任何时间过滤条件 45 + 8.1 当前系统时间:{{sDataNow}}(格式:yyyy年MM月dd日HH时mm分ss秒)
  46 + 8.2 用户需求中的相对时间概念,必须基于{{sDataNow}}进行转换:
  47 + - "本年" → 当前年份:{{sDataNow}}的年份
  48 + - "本月" → 当前月份:{{sDataNow}}的年份和月份
  49 + - "本季度" → 当前季度:基于{{sDataNow}}计算
  50 + - "本日/今天" → {{sDataNow}}的具体日期
  51 + - "昨天" → {{sDataNow}}减1天
  52 + - "本周" → 基于{{sDataNow}}计算周一到周日
  53 + - "近7天" → {{sDataNow}}减7天到{{sDataNow}}
  54 + 8.3 示例转换:
  55 + 当前时间:2024-03-15
  56 + 用户说"查询本年数据" → 查询条件应为:YEAR(日期字段) = 2024
  57 + 用户说"查询本月数据" → 查询条件应为:YEAR(日期字段) = 2024 AND MONTH(日期字段) = 3
  58 + 8.4 如果用户需求中没有明确的时间条件,禁止增加任何时间过滤条件
52 """) 59 """)
53 @UserMessage(""" 60 @UserMessage("""
54 【业务场景表结构信息】 61 【业务场景表结构信息】
@@ -93,27 +100,32 @@ public interface DynamicTableNl2SqlAiAgent { @@ -93,27 +100,32 @@ public interface DynamicTableNl2SqlAiAgent {
93 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>''; 100 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>'';
94 3.5 SQL所有的查询条件,如果是日期类型的字段,均需要加不为空判断,用示例格式判断,示例:tmakedate is not Null; 101 3.5 SQL所有的查询条件,如果是日期类型的字段,均需要加不为空判断,用示例格式判断,示例:tmakedate is not Null;
95 3.6 SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期 102 3.6 SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期
96 - 4. 安全约束:禁止生成任何DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等),禁止使用子查询、存储过程、自定义函数、临时表; 103 + 3.7 在AVG聚合函数中禁止用LAG窗口函数
  104 + 4. 安全约束:
  105 + - 禁止:DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等)
  106 + - 禁止:存储过程、自定义函数、临时表
  107 + - 允许:子查询(当需要使用窗口函数LAG/ROW_NUMBER等时)
  108 + - 允许:CTE公用表表达式(WITH语句)
97 5. 精准性: 109 5. 精准性:
98 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件; 110 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件;
99 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件 111 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件
100 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。 112 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。
101 7. 当前时间:{{sDataNow}} 113 7. 当前时间:{{sDataNow}}
102 8. 时间处理规则: 114 8. 时间处理规则:
103 - 8.1 当前系统时间:{{sDataNow}}(格式:yyyy年MM月dd日HH时mm分ss秒)  
104 - 8.2 用户需求中的相对时间概念,必须基于{{sDataNow}}进行转换:  
105 - - "本年" → 当前年份:{{sDataNow}}的年份  
106 - - "本月" → 当前月份:{{sDataNow}}的年份和月份  
107 - - "本季度" → 当前季度:基于{{sDataNow}}计算  
108 - - "本日/今天" → {{sDataNow}}的具体日期  
109 - - "昨天" → {{sDataNow}}减1天  
110 - - "本周" → 基于{{sDataNow}}计算周一到周日  
111 - - "近7天" → {{sDataNow}}减7天到{{sDataNow}}  
112 - 8.3 示例转换:  
113 - 当前时间:2024-03-15  
114 - 用户说"查询本年数据" → 查询条件应为:YEAR(日期字段) = 2024  
115 - 用户说"查询本月数据" → 查询条件应为:YEAR(日期字段) = 2024 AND MONTH(日期字段) = 3  
116 - 8.4 如果用户需求中没有明确的时间条件,禁止增加任何时间过滤条件 115 + 8.1 当前系统时间:{{sDataNow}}(格式:yyyy年MM月dd日HH时mm分ss秒)
  116 + 8.2 用户需求中的相对时间概念,必须基于{{sDataNow}}进行转换:
  117 + - "本年" → 当前年份:{{sDataNow}}的年份
  118 + - "本月" → 当前月份:{{sDataNow}}的年份和月份
  119 + - "本季度" → 当前季度:基于{{sDataNow}}计算
  120 + - "本日/今天" → {{sDataNow}}的具体日期
  121 + - "昨天" → {{sDataNow}}减1天
  122 + - "本周" → 基于{{sDataNow}}计算周一到周日
  123 + - "近7天" → {{sDataNow}}减7天到{{sDataNow}}
  124 + 8.3 示例转换:
  125 + 当前时间:2024-03-15
  126 + 用户说"查询本年数据" → 查询条件应为:YEAR(日期字段) = 2024
  127 + 用户说"查询本月数据" → 查询条件应为:YEAR(日期字段) = 2024 AND MONTH(日期字段) = 3
  128 + 8.4 如果用户需求中没有明确的时间条件,禁止增加任何时间过滤条件
117 """) 129 """)
118 @UserMessage(""" 130 @UserMessage("""
119 【业务场景表结构信息】 131 【业务场景表结构信息】
@@ -127,6 +139,8 @@ public interface DynamicTableNl2SqlAiAgent { @@ -127,6 +139,8 @@ public interface DynamicTableNl2SqlAiAgent {
127 {{errorSql}} 139 {{errorSql}}
128 【执行错误信息】 140 【执行错误信息】
129 {{errorMessage}} 141 {{errorMessage}}
  142 + 【生成SQL语句要求】
  143 + 1.不能生成{{errorSql}}一样的语句
130 【错误分析指引】 144 【错误分析指引】
131 1. 错误类型:请根据错误代码判断 145 1. 错误类型:请根据错误代码判断
132 - "Unknown column":字段不存在,检查字段名拼写或改用表中存在的字段 146 - "Unknown column":字段不存在,检查字段名拼写或改用表中存在的字段
@@ -134,12 +148,12 @@ public interface DynamicTableNl2SqlAiAgent { @@ -134,12 +148,12 @@ public interface DynamicTableNl2SqlAiAgent {
134 - "You have an error in your SQL syntax":语法错误,检查关键词、括号、引号 148 - "You have an error in your SQL syntax":语法错误,检查关键词、括号、引号
135 - "Column not found in ON clause":JOIN条件字段不存在 149 - "Column not found in ON clause":JOIN条件字段不存在
136 - "Non unique table/alias":表别名重复 150 - "Non unique table/alias":表别名重复
137 -  
138 2. 修复建议: 151 2. 修复建议:
139 - 如果是字段错误:查看表结构{{tableStruct}},找到正确的字段名替换 152 - 如果是字段错误:查看表结构{{tableStruct}},找到正确的字段名替换
140 - 如果是语法错误:检查SELECT、FROM、WHERE、JOIN等关键词用法 153 - 如果是语法错误:检查SELECT、FROM、WHERE、JOIN等关键词用法
141 - 如果是类型错误:字符串加单引号,数字不加引号,日期用'yyyy-MM-dd'格式 154 - 如果是类型错误:字符串加单引号,数字不加引号,日期用'yyyy-MM-dd'格式
142 - 如果是关联错误:确保所有表都通过外键正确JOIN 155 - 如果是关联错误:确保所有表都通过外键正确JOIN
  156 + - 如果是未知错误:确保函数之间不互斥,函数能正常使用,然后重新生成新的语句
143 请根据以上信息,重新生成正确的MySQL SELECT语句。 157 请根据以上信息,重新生成正确的MySQL SELECT语句。
144 只返回SQL语句本身,不要任何解释和包装。 158 只返回SQL语句本身,不要任何解释和包装。
145 """) 159 """)
src/main/java/com/xly/service/XlyErpService.java
@@ -259,9 +259,9 @@ public class XlyErpService { @@ -259,9 +259,9 @@ public class XlyErpService {
259 log.info("当前时间:"+sDataNow); 259 log.info("当前时间:"+sDataNow);
260 String rawSql = StrUtil.EMPTY; 260 String rawSql = StrUtil.EMPTY;
261 if(ObjectUtil.isEmpty(errorSql) && ObjectUtil.isEmpty(errorMessage)){ 261 if(ObjectUtil.isEmpty(errorSql) && ObjectUtil.isEmpty(errorMessage)){
262 - rawSql = aiDynamicTableNl2SqlAiAgent.generateMysqlSql(userId,tableNames,tableStruct,sDataNow,userInput); 262 + rawSql = aiDynamicTableNl2SqlAiAgent.generateMysqlSql(userId,tableNames,tableStruct,sDataNow,userInput);
263 }else{ 263 }else{
264 - rawSql = aiDynamicTableNl2SqlAiAgent.regenerateSqlWithError(userId, tableNames,tableStruct,sDataNow,userInput,errorSql,errorMessage); 264 + rawSql = aiDynamicTableNl2SqlAiAgent.regenerateSqlWithError(userId, tableNames,tableStruct,sDataNow,userInput,errorSql,errorMessage);
265 } 265 }
266 266
267 if (rawSql == null || rawSql.trim().isEmpty()) { 267 if (rawSql == null || rawSql.trim().isEmpty()) {
src/main/java/com/xly/util/EnhancedErrorGuidance.java
@@ -59,6 +59,10 @@ public class EnhancedErrorGuidance { @@ -59,6 +59,10 @@ public class EnhancedErrorGuidance {
59 guidance.append("【生成SQL】\n"); 59 guidance.append("【生成SQL】\n");
60 guidance.append("- 错误原因:生成的SQL语句为空\n"); 60 guidance.append("- 错误原因:生成的SQL语句为空\n");
61 guidance.append("- 修复方法:请重新生成\n"); 61 guidance.append("- 修复方法:请重新生成\n");
  62 + } else if(errorMessage.contains("You cannot use the window function 'lag' in this context.")){
  63 + guidance.append("【LAG函数用法不对】\n");
  64 + guidance.append("- 错误原因: 这个错误是因为在MySQL中,不能在聚合函数(如AVG)中直接使用窗口函数(如LAG)。窗口函数是在聚合之前计算的,但不能嵌套在聚合函数内部。\n");
  65 + guidance.append("- 修复方法:在AVG聚合函数中禁止用LAG窗口函数\n");
62 } else { 66 } else {
63 guidance.append("【未知错误】\n"); 67 guidance.append("【未知错误】\n");
64 guidance.append("- 错误信息:").append(errorMessage).append("\n"); 68 guidance.append("- 错误信息:").append(errorMessage).append("\n");