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,6 +2,7 @@ package com.xly.service; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.ObjectUtil; | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.hutool.db.Session; | ||
| 5 | import com.alibaba.fastjson2.JSON; | 6 | import com.alibaba.fastjson2.JSON; |
| 6 | import com.xly.agent.ChatiAgent; | 7 | import com.xly.agent.ChatiAgent; |
| 7 | import com.xly.agent.DynamicTableNl2SqlAiAgent; | 8 | import com.xly.agent.DynamicTableNl2SqlAiAgent; |
| @@ -23,6 +24,7 @@ import dev.langchain4j.data.message.AiMessage; | @@ -23,6 +24,7 @@ import dev.langchain4j.data.message.AiMessage; | ||
| 23 | import dev.langchain4j.model.chat.ChatLanguageModel; | 24 | import dev.langchain4j.model.chat.ChatLanguageModel; |
| 24 | import dev.langchain4j.model.ollama.OllamaChatModel; | 25 | import dev.langchain4j.model.ollama.OllamaChatModel; |
| 25 | import dev.langchain4j.service.AiServices; | 26 | import dev.langchain4j.service.AiServices; |
| 27 | +import jnr.ffi.annotations.In; | ||
| 26 | import lombok.RequiredArgsConstructor; | 28 | import lombok.RequiredArgsConstructor; |
| 27 | import lombok.extern.slf4j.Slf4j; | 29 | import lombok.extern.slf4j.Slf4j; |
| 28 | import org.python.antlr.ast.Str; | 30 | import org.python.antlr.ast.Str; |
| @@ -47,6 +49,11 @@ public class XlyErpService { | @@ -47,6 +49,11 @@ public class XlyErpService { | ||
| 47 | private final DynamicExeDbService dynamicExeDbService; | 49 | private final DynamicExeDbService dynamicExeDbService; |
| 48 | private final ToolMetaMapper toolMetaMapper; | 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,26 +109,43 @@ public class XlyErpService { | ||
| 102 | // 调用方法,参数缺失部分提示,就直接使用方法返回的 | 109 | // 调用方法,参数缺失部分提示,就直接使用方法返回的 |
| 103 | if(session.getCurrentTool() != null | 110 | if(session.getCurrentTool() != null |
| 104 | && session.getSFunPrompts()!=null | 111 | && session.getSFunPrompts()!=null |
| 105 | - ){ // 缺失的参数明细 | 112 | + ){ |
| 113 | + // 缺失的参数明细 | ||
| 106 | sResponMessage = session.getSFunPrompts(); | 114 | sResponMessage = session.getSFunPrompts(); |
| 107 | } | 115 | } |
| 108 | if (session.getCurrentTool()== null){ | 116 | if (session.getCurrentTool()== null){ |
| 109 | sResponMessage = StrUtil.EMPTY; | 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 | //5.执行工具方法后,清除记忆 | 135 | //5.执行工具方法后,清除记忆 |
| 112 | if(session.getBCleanMemory()){ | 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 | // 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 | 143 | // 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 |
| 120 | if((ObjectUtil.isNotEmpty(session.getCurrentTool()) | 144 | if((ObjectUtil.isNotEmpty(session.getCurrentTool()) |
| 121 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) | 145 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) |
| 122 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) | 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 | if (ObjectUtil.isEmpty(sResponMessage)){ | 151 | if (ObjectUtil.isEmpty(sResponMessage)){ |
| @@ -167,46 +191,79 @@ public class XlyErpService { | @@ -167,46 +191,79 @@ public class XlyErpService { | ||
| 167 | * @return java.lang.String | 191 | * @return java.lang.String |
| 168 | * @Description 获取执行动态SQL | 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 | try{ | 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 | }catch (Exception e){ | 210 | }catch (Exception e){ |
| 199 | - resultExplain = "信息模糊,请提供更具体的问题或指令"; | ||
| 200 | }finally { | 211 | }finally { |
| 201 | - session.setSceneSelected(false); | ||
| 202 | - session.setBCleanMemory(true); | 212 | + doCleanUserMemory(session,userId); |
| 203 | } | 213 | } |
| 204 | - log.info("动态表结构NL2SQL流程执行完成"); | ||
| 205 | return resultExplain; | 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 | * @Author 钱豹 | 269 | * @Author 钱豹 |