Commit 59c677099f122cc4437bd40f48402b3886627fd9

Authored by qianbao
1 parent a14f98e1

AI 对于时间的处理

src/main/java/com/xly/agent/DynamicTableNl2SqlAiAgent.java
@@ -81,81 +81,59 @@ public interface DynamicTableNl2SqlAiAgent { @@ -81,81 +81,59 @@ public interface DynamicTableNl2SqlAiAgent {
81 @V("sDataNow") String sDataNow, 81 @V("sDataNow") String sDataNow,
82 @V("userInput") String userInput); 82 @V("userInput") String userInput);
83 83
84 - /**  
85 - * SQL错误重试引导提示词  
86 - * 当第一次生成的SQL执行错误时,将错误信息传入,让AI重新生成  
87 - */ 84 +
88 /** 85 /**
89 * 动态表结构:自然语言转MySQL SELECT语句 86 * 动态表结构:自然语言转MySQL SELECT语句
90 * 入参:数据库名、表名(多表用,分隔)、表结构、用户查询 87 * 入参:数据库名、表名(多表用,分隔)、表结构、用户查询
91 */ 88 */
92 @SystemMessage(""" 89 @SystemMessage("""
93 - 你是资深MySQL数据分析师,严格遵循以下**通用规则**生成SQL,适用于所有业务场景:  
94 - 1. 语法规范:仅生成符合MySQL8.0.36的标准SELECT语句,兼容低版本,多表关联用JOIN而非逗号;  
95 - 2. 输出格式:仅返回SQL语句本身,无任何解释、换行、```sql/```包裹、备注、多余空格,直接输出可执行SQL;  
96 - 3. 编写规范:  
97 - 3.1 多表关联必须使用 表名+字段名(如表名.字段名),严格按下面[涉及表名]中的表次序关联,聚合函数(SUM/COUNT/AVG/MIN/MAX)必须加业务化别名,日期过滤使用标准DATE格式(yyyy-MM-dd);  
98 - 3.2 SQL所有字段均采用 表名.字段名 方式生成,务必确保 字段名 在相应的 表名 描述的字段中存在,如果不存在重试其它方式,直到满足条件;  
99 - 3.3 SQL所有字段涉及的所有表名,都要**严格**按下面[涉及表名]中的表次序关联,没有关联不允许使用;  
100 - 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>'';  
101 - 3.5 SQL所有的查询条件,如果是日期类型的字段,均需要加不为空判断,用示例格式判断,示例:tmakedate is not Null;  
102 - 3.6 SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期  
103 - 3.7 在AVG聚合函数中禁止用LAG窗口函数  
104 - 4. 安全约束:  
105 - - 禁止:DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等)  
106 - - 禁止:存储过程、自定义函数、临时表  
107 - - 允许:子查询(当需要使用窗口函数LAG/ROW_NUMBER等时)  
108 - - 允许:CTE公用表表达式(WITH语句)  
109 - 5. 精准性:  
110 - 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件;  
111 - 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件  
112 - 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。  
113 - 7. 当前时间:{{sDataNow}}  
114 - 8. 时间处理规则:  
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 如果用户需求中没有明确的时间条件,禁止增加任何时间过滤条件  
129 - """) 90 + 【系统角色】
  91 + 你是资深MySQL 8.0.36数据分析师,严格杜绝以下错误,生成100%可执行的SELECT语句;
  92 + 【生成前自检要求】
  93 + 1. 先检查是否违反上述禁止规则,再生成SQL;
  94 + 2. 每条SQL生成后,模拟MySQL执行逻辑自检:
  95 + - 语法是否合法(无COUNT()、聚合嵌套窗口函数等);
  96 + - 字段是否存在于表结构中;
  97 + - 差异化是否满足「结构/函数/格式」2个维度;
  98 + 3. 若自检发现错误,立即重新生成,直至所有SQL符合要求。
  99 + 【严格禁止的错误类型(强制遵守)】
  100 + 1. 语法错误:
  101 + - 禁止使用COUNT()无参数写法,必须写COUNT(*)、COUNT(1)或COUNT(具体非空字段);
  102 + - 禁止在AVG/SUM等聚合函数内嵌套LAG/ROW_NUMBER等窗口函数(如 AVG(dMaterialsPrice - LAG(dMaterialsPrice, 1, dMaterialsPrice))/SUM(viw_ai_purchaseorder.dMaterialsPrice - LAG(viw_ai_purchaseorder.dMaterialsPrice, 1)));
  103 + - 禁止ORDER BY中直接使用未别名的窗口函数表达式(如ORDER BY dMaterialsPrice - LAG(...));
  104 + - 禁止GROUP BY字段与SELECT非聚合字段不一致;
  105 + 2. 规则违规:
  106 + - 禁止字段不写表名前缀(必须是「表名.字段名」格式);
  107 + - 禁止日期字段非空判断用ifnull(日期字段,'')<>''(仅字符字段用此写法,日期字段用IS NOT NULL);
  108 + - 禁止生成与{{errorSql}}/{{historySqlList}}重复的语句,禁止仅修改排序字段/别名的“伪差异化”,可以使用子查询修复或者修改查询字段,不要使用窗口函数(如 LAG);
  109 + - 禁止LAG窗口函数缺失ORDER BY子句(必须按时间字段排序);
  110 + - 禁止HAVING条件使用COUNT()无参数写法,禁止过滤条件与业务需求无关;
  111 + - 禁止在 AVG/SUM 等聚合函数中嵌套窗口函数;
  112 + 3. 编写规范:
  113 + - 多表关联必须使用 表名+字段名(如表名.字段名),严格按下面[涉及表名]中的表次序关联,聚合函数(SUM/COUNT/AVG/MIN/MAX)必须加业务化别名,日期过滤使用标准DATE格式(yyyy-MM-dd);
  114 + - SQL所有字段均采用 表名.字段名 方式生成,务必确保 字段名 在相应的 表名 描述的字段中存在,如果不存在重试其它方式,直到满足条件;
  115 + - SQL所有字段涉及的所有表名,都要**严格**按下面[涉及表名]中的表次序关联,没有关联不允许使用;
  116 + - SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>'';
  117 + - SQL所有的查询条件,如果是日期类型的字段,均需要加不为空判断,用示例格式判断,示例:tmakedate is not Null;
  118 + - SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期
  119 + - 在AVG聚合函数中不允许使用LAG、LEAD 等窗口函数
  120 + - AVG(LAG(...))这种嵌套是不允许的
  121 + - GROUP BY 后面不允许使用窗口函数
  122 + """)
130 @UserMessage(""" 123 @UserMessage("""
131 【业务场景表结构信息】 124 【业务场景表结构信息】
132 - 涉及表名:{{tableNames}}(多表用,分隔,需关联时请按规范使用JOIN)  
133 - 表结构详情:{{tableStruct}}(多表请标注表名+字段,格式:表名(字段1:类型,字段2:类型,主键/外键))  
134 - 当前时间:{{sDataNow}} 125 + 涉及表名:{{tableNames}}
  126 + 表结构详情:{{tableStruct}}
  127 + 当前时间:{{sDataNow}}
135 【原始用户需求】 128 【原始用户需求】
136 {{userInput}} 129 {{userInput}}
  130 + 【错误信息】
  131 + 之前生成的错误SQL:{{errorSql}}
  132 + 执行错误信息:{{errorMessage}}
  133 + 【生成要求】
  134 + 1. 先修复错误SQL的所有问题,确保语法/逻辑合规;
  135 + 2. 生成与{{errorSql}}/{{historySqlList}}重复的语句,禁止仅修改排序字段/别名的“伪差异化”,可以使用子查询修复或者修改查询字段,不要使用窗口函数(如 LAG)的SELECT语句;
137 请根据上述表结构+通用规则,生成符合要求的MySQL SELECT语句; 136 请根据上述表结构+通用规则,生成符合要求的MySQL SELECT语句;
138 - 【之前生成的错误SQL】  
139 - {{errorSql}}  
140 - 【执行错误信息】  
141 - {{errorMessage}}  
142 - 【生成SQL语句要求】  
143 - 1.不能生成{{errorSql}}一样的语句  
144 - 【错误分析指引】  
145 - 1. 错误类型:请根据错误代码判断  
146 - - "Unknown column":字段不存在,检查字段名拼写或改用表中存在的字段  
147 - - "Table doesn't exist":表名错误,检查表名拼写  
148 - - "You have an error in your SQL syntax":语法错误,检查关键词、括号、引号  
149 - - "Column not found in ON clause":JOIN条件字段不存在  
150 - - "Non unique table/alias":表别名重复  
151 - 2. 修复建议:  
152 - - 如果是字段错误:查看表结构{{tableStruct}},找到正确的字段名替换  
153 - - 如果是语法错误:检查SELECT、FROM、WHERE、JOIN等关键词用法  
154 - - 如果是类型错误:字符串加单引号,数字不加引号,日期用'yyyy-MM-dd'格式  
155 - - 如果是关联错误:确保所有表都通过外键正确JOIN  
156 - - 如果是未知错误:确保函数之间不互斥,函数能正常使用,然后重新生成新的语句  
157 - 请根据以上信息,重新生成正确的MySQL SELECT语句。  
158 - 只返回SQL语句本身,不要任何解释和包装。  
159 """) 137 """)
160 String regenerateSqlWithError(@MemoryId String userId, 138 String regenerateSqlWithError(@MemoryId String userId,
161 @V("tableNames") String tableNames, 139 @V("tableNames") String tableNames,
@@ -163,7 +141,9 @@ public interface DynamicTableNl2SqlAiAgent { @@ -163,7 +141,9 @@ public interface DynamicTableNl2SqlAiAgent {
163 @V("sDataNow") String sDataNow, 141 @V("sDataNow") String sDataNow,
164 @V("userInput") String userInput, 142 @V("userInput") String userInput,
165 @V("errorSql") String errorSql, 143 @V("errorSql") String errorSql,
166 - @V("errorMessage") String errorMessage 144 + @V("errorMessage") String errorMessage,
  145 + @V("n") String iErroCount,
  146 + @V("historySqlList") String historySqlList
167 ); 147 );
168 /** 148 /**
169 * 动态表结构:自然语言解释SQL执行结果 149 * 动态表结构:自然语言解释SQL执行结果
@@ -179,11 +159,11 @@ public interface DynamicTableNl2SqlAiAgent { @@ -179,11 +159,11 @@ public interface DynamicTableNl2SqlAiAgent {
179 """) 159 """)
180 @UserMessage(""" 160 @UserMessage("""
181 【业务场景表结构信息】 161 【业务场景表结构信息】
182 - 表结构详情:{{tableStruct}} 162 + 表结构详情:{{tableStruct}}
183 【查询相关信息】 163 【查询相关信息】
184 用户原始查询:{{userInput}} 164 用户原始查询:{{userInput}}
185 执行的MySQL SQL:{{sql}} 165 执行的MySQL SQL:{{sql}}
186 - SQL执行结果(JSON格式):{{result}} 166 + SQL执行结果(JSON格式):{{result}}
187 请根据上述信息+通用规则,对查询结果做业务解释: 167 请根据上述信息+通用规则,对查询结果做业务解释:
188 """) 168 """)
189 String explainSqlResult(@MemoryId String userId, 169 String explainSqlResult(@MemoryId String userId,
src/main/java/com/xly/runner/AppStartupRunner.java
@@ -151,9 +151,9 @@ public class AppStartupRunner implements CommandLineRunner { @@ -151,9 +151,9 @@ public class AppStartupRunner implements CommandLineRunner {
151 /** 151 /**
152 * 根据编码获取AI代理 152 * 根据编码获取AI代理
153 */ 153 */
154 - public static SceneDto getAiAgentByCode(String sCode) { 154 + public static SceneDto getAiAgentByCode(String sName) {
155 return AI_AGENT_CACHE.stream() 155 return AI_AGENT_CACHE.stream()
156 - .filter(agent -> agent.getSSceneNo().equals(sCode)) 156 + .filter(agent -> agent.getSSceneName().equals(sName))
157 .findFirst() 157 .findFirst()
158 .orElse(null); 158 .orElse(null);
159 } 159 }
src/main/java/com/xly/service/XlyErpService.java
@@ -4,7 +4,6 @@ import cn.hutool.core.date.DatePattern; @@ -4,7 +4,6 @@ import cn.hutool.core.date.DatePattern;
4 import cn.hutool.core.date.DateUtil; 4 import cn.hutool.core.date.DateUtil;
5 import cn.hutool.core.util.ObjectUtil; 5 import cn.hutool.core.util.ObjectUtil;
6 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
7 -import cn.hutool.db.Session;  
8 import com.alibaba.fastjson2.JSON; 7 import com.alibaba.fastjson2.JSON;
9 import com.xly.agent.ChatiAgent; 8 import com.xly.agent.ChatiAgent;
10 import com.xly.agent.DynamicTableNl2SqlAiAgent; 9 import com.xly.agent.DynamicTableNl2SqlAiAgent;
@@ -29,17 +28,9 @@ import dev.langchain4j.data.message.ChatMessageType; @@ -29,17 +28,9 @@ import dev.langchain4j.data.message.ChatMessageType;
29 import dev.langchain4j.model.chat.ChatLanguageModel; 28 import dev.langchain4j.model.chat.ChatLanguageModel;
30 import dev.langchain4j.model.ollama.OllamaChatModel; 29 import dev.langchain4j.model.ollama.OllamaChatModel;
31 import dev.langchain4j.service.AiServices; 30 import dev.langchain4j.service.AiServices;
32 -import dev.langchain4j.service.V;  
33 -import jnr.ffi.annotations.In;  
34 import lombok.RequiredArgsConstructor; 31 import lombok.RequiredArgsConstructor;
35 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
36 -import org.python.antlr.ast.Str;  
37 import org.springframework.stereotype.Service; 33 import org.springframework.stereotype.Service;
38 -  
39 -import java.math.BigDecimal;  
40 -import java.text.DateFormat;  
41 -import java.time.LocalDate;  
42 -import java.time.format.DateTimeFormatter;  
43 import java.util.*; 34 import java.util.*;
44 35
45 @Service 36 @Service
@@ -123,30 +114,12 @@ public class XlyErpService { @@ -123,30 +114,12 @@ public class XlyErpService {
123 // 缺失的参数明细 114 // 缺失的参数明细
124 sResponMessage = session.getSFunPrompts(); 115 sResponMessage = session.getSFunPrompts();
125 } 116 }
126 -// //说明没有找到动态方法重新走一次  
127 -// if(maxToolRetries==1 && session.getCurrentTool()== null){  
128 -// Thread.sleep(1000);  
129 -// doCleanUserMemory(session,userId);  
130 -// return erpUserInput( userInput,  
131 -// userId ,  
132 -// sUserName ,  
133 -// sBrandsId ,  
134 -// sSubsidiaryId,  
135 -// sUserType,  
136 -// authorization,  
137 -// 0);  
138 -// }  
139 -  
140 if (session.getCurrentTool()== null){ 117 if (session.getCurrentTool()== null){
141 sResponMessageOld = sResponMessage; 118 sResponMessageOld = sResponMessage;
142 sResponMessage = StrUtil.EMPTY; 119 sResponMessage = StrUtil.EMPTY;
143 } 120 }
144 //5.执行工具方法后,清除记忆 121 //5.执行工具方法后,清除记忆
145 if(session.getBCleanMemory()){ 122 if(session.getBCleanMemory()){
146 -// operableChatMemoryProvider.clearSpecifiedMemory(userId);  
147 -// session.setCurrentTool(null);  
148 -// UserSceneSessionService.ERP_AGENT_CACHE.remove(userId);  
149 -// UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId);  
150 doCleanUserMemory(session,userId); 123 doCleanUserMemory(session,userId);
151 } 124 }
152 // 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 125 // 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体
@@ -154,7 +127,7 @@ public class XlyErpService { @@ -154,7 +127,7 @@ public class XlyErpService {
154 && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) 127 && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName())
155 && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) 128 && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo()))
156 ){ 129 ){
157 - sResponMessage = getDynamicTableSql(session, input, userId, userInput,0,StrUtil.EMPTY,StrUtil.EMPTY); 130 + sResponMessage = getDynamicTableSql(session, input, userId, userInput,0,StrUtil.EMPTY,StrUtil.EMPTY,"0",StrUtil.EMPTY);
158 } 131 }
159 //如果返回空的进入闲聊模式 132 //如果返回空的进入闲聊模式
160 if (ObjectUtil.isEmpty(sResponMessage)){ 133 if (ObjectUtil.isEmpty(sResponMessage)){
@@ -200,24 +173,30 @@ public class XlyErpService { @@ -200,24 +173,30 @@ public class XlyErpService {
200 * @return java.lang.String 173 * @return java.lang.String
201 * @Description 获取执行动态SQL 174 * @Description 获取执行动态SQL
202 **/ 175 **/
203 - private String getDynamicTableSql(UserSceneSession session,String input,String userId,String userInput,Integer attempt,String errorSql,String errorMessage ){ 176 + private String getDynamicTableSql(UserSceneSession session,String input,String userId,String userInput,Integer attempt,String errorSql,String errorMessage,String iErroCount,String historySqlList ){
204 String resultExplain = "信息模糊,请提供更具体的问题或指令"; 177 String resultExplain = "信息模糊,请提供更具体的问题或指令";
205 try{ 178 try{
206 while (attempt < maxRetries) { 179 while (attempt < maxRetries) {
207 try{ 180 try{
208 attempt = attempt+1; 181 attempt = attempt+1;
209 - return getDynamicTableSqlExec(session, input, userId, userInput,errorSql,errorMessage); 182 + return getDynamicTableSqlExec(session, input, userId, userInput,errorSql,errorMessage,iErroCount,historySqlList);
210 }catch (Exception e){ 183 }catch (Exception e){
211 String erroMsg = e.getMessage(); 184 String erroMsg = e.getMessage();
212 String errorSqlOld = StrUtil.EMPTY; 185 String errorSqlOld = StrUtil.EMPTY;
213 if(erroMsg.contains(EnhancedErrorGuidance.splitString) && erroMsg.split(EnhancedErrorGuidance.splitString).length>1){ 186 if(erroMsg.contains(EnhancedErrorGuidance.splitString) && erroMsg.split(EnhancedErrorGuidance.splitString).length>1){
214 errorSqlOld = erroMsg.split(EnhancedErrorGuidance.splitString)[1]; 187 errorSqlOld = erroMsg.split(EnhancedErrorGuidance.splitString)[1];
  188 + errorSqlOld = StrUtil.replace(errorSqlOld,";","");
  189 + if(StrUtil.isNotEmpty(historySqlList)){
  190 + historySqlList = historySqlList+"/"+errorSqlOld;
  191 + }else{
  192 + historySqlList = errorSqlOld;
  193 + }
215 } 194 }
216 - String errorMessageOld = EnhancedErrorGuidance.getErrorGuidance(erroMsg); 195 + String errorMessageOld = erroMsg;
217 if (attempt == maxRetries) { 196 if (attempt == maxRetries) {
218 - return resultExplain+"查询的SQL语句:"+errorSqlOld; 197 + return resultExplain+"查询的SQL语句:"+historySqlList;
219 } else { 198 } else {
220 - return getDynamicTableSql( session, input, userId, userInput, attempt,errorSqlOld,errorMessageOld); 199 + return getDynamicTableSql( session, input, userId, userInput, attempt,errorSqlOld,errorMessageOld,attempt.toString(),historySqlList);
221 } 200 }
222 } 201 }
223 } 202 }
@@ -252,7 +231,7 @@ public class XlyErpService { @@ -252,7 +231,7 @@ public class XlyErpService {
252 * @return java.lang.String 231 * @return java.lang.String
253 * @Description 执行动态sSql 232 * @Description 执行动态sSql
254 **/ 233 **/
255 - private String getDynamicTableSqlExec(UserSceneSession session,String input,String userId,String userInput,String errorSql,String errorMessage){ 234 + private String getDynamicTableSqlExec(UserSceneSession session,String input,String userId,String userInput,String errorSql,String errorMessage,String iErroCount,String historySqlList){
256 // 1. 构建自然语言转SQLAgent, 235 // 1. 构建自然语言转SQLAgent,
257 DynamicTableNl2SqlAiAgent aiDynamicTableNl2SqlAiAgent = createDynamicTableNl2SqlAiAgent(userId, input, session); 236 DynamicTableNl2SqlAiAgent aiDynamicTableNl2SqlAiAgent = createDynamicTableNl2SqlAiAgent(userId, input, session);
258 String tableNames = session.getCurrentTool().getSInputTabelName(); 237 String tableNames = session.getCurrentTool().getSInputTabelName();
@@ -264,9 +243,12 @@ public class XlyErpService { @@ -264,9 +243,12 @@ public class XlyErpService {
264 if(ObjectUtil.isEmpty(errorSql) && ObjectUtil.isEmpty(errorMessage)){ 243 if(ObjectUtil.isEmpty(errorSql) && ObjectUtil.isEmpty(errorMessage)){
265 rawSql = aiDynamicTableNl2SqlAiAgent.generateMysqlSql(userId,tableNames,tableStruct,sDataNow,userInput); 244 rawSql = aiDynamicTableNl2SqlAiAgent.generateMysqlSql(userId,tableNames,tableStruct,sDataNow,userInput);
266 }else{ 245 }else{
267 - rawSql = aiDynamicTableNl2SqlAiAgent.regenerateSqlWithError(userId, tableNames,tableStruct,sDataNow,userInput,errorSql,errorMessage); 246 + rawSql = aiDynamicTableNl2SqlAiAgent.regenerateSqlWithError(userId, tableNames,tableStruct,sDataNow,userInput,errorSql,errorMessage,iErroCount,historySqlList);
  247 + }
  248 + String[] rawSqlA = rawSql.split(";");
  249 + if(rawSqlA.length>1){
  250 + rawSql = rawSqlA[rawSqlA.length-1];
268 } 251 }
269 -  
270 if (rawSql == null || rawSql.trim().isEmpty()) { 252 if (rawSql == null || rawSql.trim().isEmpty()) {
271 throw new SqlGenerateException("SQL EMPTY"); 253 throw new SqlGenerateException("SQL EMPTY");
272 } 254 }
@@ -407,7 +389,7 @@ public class XlyErpService { @@ -407,7 +389,7 @@ public class XlyErpService {
407 return null; 389 return null;
408 } 390 }
409 // 4. 将场景编码转换为BusinessScene枚举 391 // 4. 将场景编码转换为BusinessScene枚举
410 - String sSceneNo = parseResp.getSceneCode(); 392 + String sSceneNo = parseResp.getScene();
411 return AppStartupRunner.getAiAgentByCode(sSceneNo); 393 return AppStartupRunner.getAiAgentByCode(sSceneNo);
412 } catch (Exception e) { 394 } catch (Exception e) {
413 log.error("用户{}大模型意图解析失败,输入:{}", userId, userInput, e); 395 log.error("用户{}大模型意图解析失败,输入:{}", userId, userInput, e);