Commit a3f418f196c4ceb8849379f9f5e8c90e7b33fbb4
1 parent
7b015560
1111
Showing
1 changed file
with
94 additions
and
37 deletions
src/main/java/com/xly/service/XlyErpService.java
| ... | ... | @@ -2,6 +2,7 @@ package com.xly.service; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.hutool.db.Session; | |
| 5 | 6 | import com.alibaba.fastjson2.JSON; |
| 6 | 7 | import com.xly.agent.ChatiAgent; |
| 7 | 8 | import com.xly.agent.DynamicTableNl2SqlAiAgent; |
| ... | ... | @@ -23,6 +24,7 @@ import dev.langchain4j.data.message.AiMessage; |
| 23 | 24 | import dev.langchain4j.model.chat.ChatLanguageModel; |
| 24 | 25 | import dev.langchain4j.model.ollama.OllamaChatModel; |
| 25 | 26 | import dev.langchain4j.service.AiServices; |
| 27 | +import jnr.ffi.annotations.In; | |
| 26 | 28 | import lombok.RequiredArgsConstructor; |
| 27 | 29 | import lombok.extern.slf4j.Slf4j; |
| 28 | 30 | import org.python.antlr.ast.Str; |
| ... | ... | @@ -47,6 +49,11 @@ public class XlyErpService { |
| 47 | 49 | private final DynamicExeDbService dynamicExeDbService; |
| 48 | 50 | private final ToolMetaMapper toolMetaMapper; |
| 49 | 51 | |
| 52 | + //执行动态语句 执行异常的情况下 最多执行次数 | |
| 53 | + private final Integer maxRetries = 5; | |
| 54 | + //没有找到对应方法重走一次补偿次数 | |
| 55 | + public final static Integer maxTollRetries = 1; | |
| 56 | + | |
| 50 | 57 | |
| 51 | 58 | |
| 52 | 59 | /*** |
| ... | ... | @@ -102,26 +109,43 @@ public class XlyErpService { |
| 102 | 109 | // 调用方法,参数缺失部分提示,就直接使用方法返回的 |
| 103 | 110 | if(session.getCurrentTool() != null |
| 104 | 111 | && session.getSFunPrompts()!=null |
| 105 | - ){ // 缺失的参数明细 | |
| 112 | + ){ | |
| 113 | + // 缺失的参数明细 | |
| 106 | 114 | sResponMessage = session.getSFunPrompts(); |
| 107 | 115 | } |
| 108 | 116 | if (session.getCurrentTool()== null){ |
| 109 | 117 | sResponMessage = StrUtil.EMPTY; |
| 110 | 118 | } |
| 119 | +// //说明没有找到动态方法重新走一次 | |
| 120 | +// if(maxToolRetries==1 && session.getCurrentTool()== null){ | |
| 121 | +// Thread.sleep(1000); | |
| 122 | +// return erpUserInput( userInput, | |
| 123 | +// userId , | |
| 124 | +// sUserName , | |
| 125 | +// sBrandsId , | |
| 126 | +// sSubsidiaryId, | |
| 127 | +// sUserType, | |
| 128 | +// authorization, | |
| 129 | +// 0); | |
| 130 | +// } | |
| 131 | + | |
| 132 | + if (session.getCurrentTool()== null){ | |
| 133 | + sResponMessage = StrUtil.EMPTY; | |
| 134 | + } | |
| 111 | 135 | //5.执行工具方法后,清除记忆 |
| 112 | 136 | if(session.getBCleanMemory()){ |
| 113 | - operableChatMemoryProvider.clearSpecifiedMemory(userId); | |
| 114 | - session.setCurrentTool(null); | |
| 115 | - UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); | |
| 116 | - UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); | |
| 117 | - session.setBCleanMemory(false); | |
| 137 | +// operableChatMemoryProvider.clearSpecifiedMemory(userId); | |
| 138 | +// session.setCurrentTool(null); | |
| 139 | +// UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); | |
| 140 | +// UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); | |
| 141 | + doCleanUserMemory(session,userId); | |
| 118 | 142 | } |
| 119 | 143 | // 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 |
| 120 | 144 | if((ObjectUtil.isNotEmpty(session.getCurrentTool()) |
| 121 | 145 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) |
| 122 | 146 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) |
| 123 | 147 | ){ |
| 124 | - sResponMessage = getDynamicTableSql(session, input, userId, userInput); | |
| 148 | + sResponMessage = getDynamicTableSql(session, input, userId, userInput,maxRetries); | |
| 125 | 149 | } |
| 126 | 150 | //如果返回空的进入闲聊模式 |
| 127 | 151 | if (ObjectUtil.isEmpty(sResponMessage)){ |
| ... | ... | @@ -167,46 +191,79 @@ public class XlyErpService { |
| 167 | 191 | * @return java.lang.String |
| 168 | 192 | * @Description 获取执行动态SQL |
| 169 | 193 | **/ |
| 170 | - private String getDynamicTableSql(UserSceneSession session,String input,String userId,String userInput){ | |
| 171 | - String resultExplain = StrUtil.EMPTY; | |
| 194 | + private String getDynamicTableSql(UserSceneSession session,String input,String userId,String userInput,Integer maxRetries){ | |
| 195 | + String resultExplain = "信息模糊,请提供更具体的问题或指令"; | |
| 172 | 196 | try{ |
| 173 | - // 1. 构建自然语言转SQLAgent, | |
| 174 | - DynamicTableNl2SqlAiAgent aiDynamicTableNl2SqlAiAgent = createDynamicTableNl2SqlAiAgent(userId, input, session); | |
| 175 | - String tableNames = session.getCurrentTool().getSInputTabelName(); | |
| 176 | - // "订单表:viw_salsalesorder,客户信息表:elecustomer,结算方式表:sispayment,产品表(无单价,无金额,无数量):viw_product_sort,销售人员表:viw_sissalesman_depart"; | |
| 177 | - String tableStruct = session.getCurrentTool().getSStructureMemo(); | |
| 178 | - String rawSql = aiDynamicTableNl2SqlAiAgent.generateMysqlSql(userId,tableNames,tableStruct,userInput); | |
| 179 | - if (rawSql == null || rawSql.trim().isEmpty()) { | |
| 180 | - throw new SqlGenerateException("AI服务生成SQL失败,返回结果为空"); | |
| 197 | + int attempt = 0; | |
| 198 | + while (attempt < maxRetries) { | |
| 199 | + try{ | |
| 200 | + attempt++; | |
| 201 | + return getDynamicTableSqlExec( session, input, userId, userInput); | |
| 202 | + }catch (Exception e){ | |
| 203 | + if (attempt == maxRetries) { | |
| 204 | + return resultExplain; | |
| 205 | + } else { | |
| 206 | + return getDynamicTableSql( session, input, userId, userInput, maxRetries); | |
| 207 | + } | |
| 208 | + } | |
| 181 | 209 | } |
| 182 | - // 2. 清理SQL多余符号 + 生产级强校验(核心安全保障,不可省略) | |
| 183 | - String cleanSql = SqlValidateUtil.cleanSqlSymbol(rawSql); | |
| 184 | - SqlValidateUtil.validateMysqlSql(cleanSql); | |
| 185 | - log.info("SQL清理并强校验通过,可执行SQL:{}", cleanSql); | |
| 186 | - // 4. 执行SQL获取结构化结果 | |
| 187 | -// Map<String,Object> params = new HashMap<>(); | |
| 188 | - List<Map<String, Object>> sqlResult = dynamicExeDbService.findSql(new HashMap<>(),cleanSql); | |
| 189 | - // 5. 调用AI服务生成自然语言解释(传入表结构,让解释更贴合业务) | |
| 190 | - String resultJson = JSON.toJSONString(sqlResult); | |
| 191 | - resultExplain = aiDynamicTableNl2SqlAiAgent.explainSqlResult( | |
| 192 | - userId, | |
| 193 | - userInput, | |
| 194 | - cleanSql, | |
| 195 | - tableStruct, | |
| 196 | - resultJson | |
| 197 | - ); | |
| 198 | 210 | }catch (Exception e){ |
| 199 | - resultExplain = "信息模糊,请提供更具体的问题或指令"; | |
| 200 | 211 | }finally { |
| 201 | - session.setSceneSelected(false); | |
| 202 | - session.setBCleanMemory(true); | |
| 212 | + doCleanUserMemory(session,userId); | |
| 203 | 213 | } |
| 204 | - log.info("动态表结构NL2SQL流程执行完成"); | |
| 205 | 214 | return resultExplain; |
| 206 | 215 | } |
| 207 | 216 | |
| 217 | + /*** | |
| 218 | + * @Author 钱豹 | |
| 219 | + * @Date 19:59 2026/3/4 | |
| 220 | + * @Param [session, sUserId] | |
| 221 | + * @return void | |
| 222 | + * @Description 删除用户记忆 方法 | |
| 223 | + **/ | |
| 224 | + private void doCleanUserMemory(UserSceneSession session,String userId){ | |
| 225 | + operableChatMemoryProvider.clearSpecifiedMemory(userId); | |
| 226 | + session.setCurrentTool(null); | |
| 227 | + session.setSceneSelected(false); | |
| 228 | + UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); | |
| 229 | + UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); | |
| 230 | + session.setBCleanMemory(false); | |
| 231 | + } | |
| 208 | 232 | |
| 209 | 233 | |
| 234 | + /*** | |
| 235 | + * @Author 钱豹 | |
| 236 | + * @Date 19:49 2026/3/4 | |
| 237 | + * @Param [session, input, userId, userInput] | |
| 238 | + * @return java.lang.String | |
| 239 | + * @Description 执行动态sSql | |
| 240 | + **/ | |
| 241 | + private String getDynamicTableSqlExec(UserSceneSession session,String input,String userId,String userInput){ | |
| 242 | + // 1. 构建自然语言转SQLAgent, | |
| 243 | + DynamicTableNl2SqlAiAgent aiDynamicTableNl2SqlAiAgent = createDynamicTableNl2SqlAiAgent(userId, input, session); | |
| 244 | + String tableNames = session.getCurrentTool().getSInputTabelName(); | |
| 245 | + // "订单表:viw_salsalesorder,客户信息表:elecustomer,结算方式表:sispayment,产品表(无单价,无金额,无数量):viw_product_sort,销售人员表:viw_sissalesman_depart"; | |
| 246 | + String tableStruct = session.getCurrentTool().getSStructureMemo(); | |
| 247 | + String rawSql = aiDynamicTableNl2SqlAiAgent.generateMysqlSql(userId,tableNames,tableStruct,userInput); | |
| 248 | + if (rawSql == null || rawSql.trim().isEmpty()) { | |
| 249 | + throw new SqlGenerateException("AI服务生成SQL失败,返回结果为空"); | |
| 250 | + } | |
| 251 | + // 2. 清理SQL多余符号 + 生产级强校验(核心安全保障,不可省略) | |
| 252 | + String cleanSql = SqlValidateUtil.cleanSqlSymbol(rawSql); | |
| 253 | + SqlValidateUtil.validateMysqlSql(cleanSql); | |
| 254 | + // 4. 执行SQL获取结构化结果 | |
| 255 | +// Map<String,Object> params = new HashMap<>(); | |
| 256 | + List<Map<String, Object>> sqlResult = dynamicExeDbService.findSql(new HashMap<>(),cleanSql); | |
| 257 | + // 5. 调用AI服务生成自然语言解释(传入表结构,让解释更贴合业务) | |
| 258 | + String resultJson = JSON.toJSONString(sqlResult); | |
| 259 | + return aiDynamicTableNl2SqlAiAgent.explainSqlResult( | |
| 260 | + userId, | |
| 261 | + userInput, | |
| 262 | + cleanSql, | |
| 263 | + tableStruct, | |
| 264 | + resultJson | |
| 265 | + ); | |
| 266 | + } | |
| 210 | 267 | |
| 211 | 268 | /*** |
| 212 | 269 | * @Author 钱豹 | ... | ... |