Commit 6f97d3bd65770adab7dd3f9224d605f8670fc8c1
1 parent
06ca6a05
AI 对于时间的处理
Showing
3 changed files
with
51 additions
and
33 deletions
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"); |