DynamicNl2SqlService.java 3.52 KB
package com.xly.service;


import com.alibaba.fastjson2.JSON;

import com.xly.agent.DynamicTableNl2SqlAiAgent;
import com.xly.entity.DynamicNl2SqlRequest;
import com.xly.entity.Nl2SqlResult;
import com.xly.util.SqlExecuteUtil;
import com.xly.util.SqlValidateUtil;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * 动态表结构的NL2SQL业务服务层
 * 适配任意表结构、多业务场景
 */
@Service
public class DynamicNl2SqlService {
    private static final Logger log = LoggerFactory.getLogger(DynamicNl2SqlService.class);

    @Resource
    private DynamicTableNl2SqlAiAgent dynamicTableNl2SqlAiAgent;

    @Resource
    private SqlExecuteUtil sqlExecuteUtil;

    /**
     * 执行动态表结构的NL2SQL全流程
     * @param request 动态表结构请求(含db名、表名、表结构、用户问题)
     * @return 结构化NL2SQL结果
     */
    public Nl2SqlResult executeDynamicNl2Sql(DynamicNl2SqlRequest request) {
        log.info("开始执行动态表结构NL2SQL流程,请求:{}", JSON.toJSONString(request));
        // 1. 入参非空校验(重点校验表结构和用户问题)
        if (request.getTableStruct() == null || request.getTableStruct().trim().isEmpty()
                || request.getQuestion() == null || request.getQuestion().trim().isEmpty()) {
            throw new IllegalArgumentException("表结构和用户查询问题不能为空");
        }
        // 补全默认值(如数据库名默认取配置中的值)

        String tableNames = request.getTableNames() == null ? "" : request.getTableNames().trim();
        String rawSql = "select * from " + tableNames + " where 1=1 ";
                // 2. 调用AI服务生成SQL(传入所有动态参数)
//        String rawSql = dynamicTableNl2SqlAiAgent.generateMysqlSql(
//                tableNames,
//                request.getTableStruct().trim(),
//                request.getQuestion().trim()
//        );
//        if (rawSql == null || rawSql.trim().isEmpty()) {
//            throw new SqlGenerateException("AI服务生成SQL失败,返回结果为空");
//        }
//        log.info("AI服务生成原始SQL:{}", rawSql);

        // 3. 清理SQL多余符号 + 生产级强校验(核心安全保障,不可省略)
        String cleanSql = SqlValidateUtil.cleanSqlSymbol(rawSql);
        SqlValidateUtil.validateMysqlSql(cleanSql);
        log.info("SQL清理并强校验通过,可执行SQL:{}", cleanSql);

        // 4. 执行SQL获取结构化结果
        List<Map<String, Object>> sqlResult = sqlExecuteUtil.executeSelectSql(cleanSql);
        log.info("MySQL SQL执行完成,返回结果条数:{}", sqlResult.size());
        String resultExplain ="";
        // 5. 调用AI服务生成自然语言解释(传入表结构,让解释更贴合业务)
        String resultJson = JSON.toJSONString(sqlResult);
//        String resultExplain = dynamicTableNl2SqlAiAgent.explainSqlResult(
//                request.getQuestion().trim(),
//                cleanSql,
//                request.getTableStruct().trim(),
//                resultJson
//        );

        // 6. 封装结果返回
        Nl2SqlResult nl2SqlResult = new Nl2SqlResult();
        nl2SqlResult.setGenerateSql(cleanSql);
        nl2SqlResult.setSqlResult(sqlResult);
        nl2SqlResult.setResultExplain(resultExplain);

        log.info("动态表结构NL2SQL流程执行完成");
        return nl2SqlResult;
    }
}