当模型输出动态 SQL 时,如何采用参数化查询重写?

解读

在大模型落地业务系统时,模型可能直接生成“可执行 SQL 字符串”,例如“SELECT * FROM user WHERE id = ” + userInput。
国内监管对数据安全、等保 2.0、个人信息保护要求极严,任何字符串拼接 SQL 都会被安全团队一票否决
因此,面试官真正想考察的是:

  1. 你能否在 LLM 输出侧拦截危险 SQL
  2. 你能否把不可信部分转化为参数占位符
  3. 你能否在 LLMOps 流程里把“参数化重写”做成自动化卡点,而不是靠人眼 review。

知识点

  1. 参数化查询(PreparedStatement / ORM 参数绑定):SQL 骨架与数据分离,数据库驱动自动转义。
  2. AST 解析与重写:用 JSqlParser、Druid SQL Parser 把 LLM 输出的字符串解析成语法树,将字面量节点替换成 ? 或 :name 占位符,同时收集参数列表。
  3. 白名单校验:只允许 SELECT,禁止 DROP/ALTER;表名、列名必须在元数据白名单内。
  4. LLM 后处理链路:在模型输出→服务化封装之间插入“SQL 重写微服务”,返回 {sql: "SELECT … WHERE id = ?", params: [123]}
  5. 国产数据库兼容:OceanBase、PolarDB、TiDB 均支持 标准 JDBC 参数化协议,占位符统一用 ? 可避免方言差异。
  6. 性能与并发:重写逻辑必须 <10 ms,用单例 Parser + 对象池;高并发场景可下沉到 Go 或 Rust sidecar。
  7. 审计与监控:把重写前后 SQL 都打印到统一日志格式(traceId+userId+sqlHash),方便等保审计和事后溯源。

答案

以国内最常见的 Spring Boot + MyBatis Plus + Druid 为例,给出可直接落地的三步法:

  1. 拦截:在 Controller AOP 里识别 LLM 返回字段 generatedSql
  2. 解析与重写
    String sql = llmOutput.getGeneratedSql();
    Statement stmt = CCJSqlParserUtil.parse(sql);
    if (!new SqlWhitelistVisitor().isSafe(stmt)) {
        throw new SecurityException("SQL 含高危操作");
    }
    ParameterizedRewriter rewriter = new ParameterizedRewriter();
    String safeSql = rewriter.rewrite(stmt);   // 返回 SELECT … WHERE id = ?
    List<Object> params = rewriter.getParams(); // 返回 [123]
    
  3. 执行
    Map<String,Object> map = new HashMap<>();
    map.put("safeSql", safeSql);
    map.put("params", params);
    return sqlSession.selectList("com.xxx.mapper.DynamicSqlMapper.execSafe", map);
    
    其中 Mapper XML 使用 ${safeSql} 作为静态骨架#{params} 作为参数绑定,MyBatis 会自动完成 JDBC parameterMapping。

核心要点

  • 绝不把 LLM 原文直接送进 JDBC;
  • 所有字面量必须替换成占位符;
  • 重写服务要灰度发布+实时熔断,一旦解析失败立即降级到“人工审核”流程,保证线上 0 阻断。

拓展思考

  1. 多轮对话场景:用户可能分三次补充“时间范围、状态、分页”,模型最终才拼出完整 SQL。
    解决思路:在对话状态机里维护一个“参数累积器”,每轮只让模型输出“增量条件”,后端用 AST merge 而不是字符串拼接,避免最后一轮爆炸性注入
  2. 国产信创环境:如果数据库换成达梦、人大金仓,驱动仍支持 JDBC 4.2 参数化,但占位符名大小写敏感,需在重写阶段统一转大写并做双引号转义。
  3. LLMOps 持续监控:把“SQL 重写耗时、解析失败率、参数化成功率”埋点到 Prometheus,配置告警规则 >1% 失败就@值班,实现安全左移。
  4. 未来趋势:用模型即服务(MaaS)反向训练一个小型 SQL 参数化模型(百兆级),输入用户问题,直接输出参数化骨架+参数列表,跳过传统解析器,延迟可再降 50%,但需投入人工标注 5 万条安全 SQL 对,这是团队下一步 OKR。