SQL Agent

本教程将指导您构建一个智能SQL代理,该代理能够与数据库交互,生成SQL查询,验证查询,执行查询,并在出现错误时自我纠正。

概述

SQL代理流实现了一个健壮的数据库交互系统,该系统:

  1. 检索数据库模式信息

  2. 根据用户问题生成SQL查询语句

  3. 验证生成的查询是否存在常见错误

  4. 对数据库执行查询

  5. 检查结果是否有误,并在必要时进行自我纠正

  6. 根据查询结果提供自然语言回复

步骤1:设置起始节点

首先,在画布上添加一个Start节点。这将成为SQL代理的入口点。

配置:

  • 输入类型:选择“聊天输入”以接受用户问题

  • Flow State:添加一个键为“sqlQuery”且值为空的状态变量

Start节点使用一个空的sqlQuery变量来初始化流状态,该变量将在整个过程中存储生成的SQL查询。

步骤2:检索数据库模式

添加一个自定义函数节点,并将其连接到开始节点。

配置:

  • Javascript函数:这是一个示例函数,用于连接到您的数据库并检索完整的模式,包括表结构、列定义和示例数据。

const { DataSource } = require('typeorm');;

const HOST = 'localhost';;
const USER = 'testuser';;
const 密码 = 'testpwd';;
const DATABASE = 'testdatabase';;
const PORT = 5432;;

let sqlSchemaPrompt = '';;

const AppDataSource = new DataSource({
  类型:'postgres',
  主机:HOST,
  端口:PORT,
  用户名:USER,
  密码:PASSWORD,
  数据库:DATABASE,
  同步:否,
  日志记录:否,
});

异步函数 getSQLPrompt() {
  尝试 {
    等待 AppDataSource 初始化完成;
    const queryRunner = AppDataSource.createQueryRunner();;

    // 获取所有用户定义的表
    const tablesResult = await queryRunner.query(`
      选择表名
      来自information_schema.tables
      WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
    `);

    对于(tablesResult中的每个)表格行(tableRow) {
      const tableName = tableRow.table_name;;
      const schemaInfo = await queryRunner.query(`
        选择列名、数据类型、是否可以为空
        从information_schema.columns表中选择
        在表名(table_name)等于'${tableName}'的情况下
      `);

      const createColumns = [];;
      const columnNames = [];;

      对于 schemaInfo 中的每个列(column)
        const name = column.column_name;;
        const type = column.data_type.toUpperCase();;
        const notNull = column.is_nullable === 'NO' ? 'NOT NULL' : '';;
        columnNames.push(name);;
        `${name} ${type} ${notNull}` 添加到 createColumns 数组中;
      }

      常量sqlCreateTableQuery定义为`CREATE TABLE ${tableName} (${createColumns.join(', ')})`;
      常量sqlSelectTableQuery定义为:`SELECT * FROM ${tableName} LIMIT 3`;

      将所有值赋值为一个空数组;
      尝试 {
        const rows = await queryRunner.query(sqlSelectTableQuery);;
        allValues = rows.map(row =>
          `columnNames.map(col => row[col]).join(' ')`
        );
      } catch (err) {
        allValues.push('[获取行时出错]');;
      }

      sqlSchemaPrompt +=
        sqlCreateTableQuery + '\n' +
        sqlSelectTableQuery + '\n' +
        列名数组使用空格连接后换行符 + '\n' +
        所有值用换行符连接,然后加上两个换行符;
    }

    等待 queryRunner 释放资源;
  } catch (err) {
    console.error(err);;
    抛出错误;
  }
}

等待获取SQL提示;
返回sqlSchemaPrompt;

步骤 3:生成 SQL 查询

添加一个与“获取数据库模式”节点相连的LLM节点。

配置:

  • 消息:添加一条系统消息:

你是一个旨在与SQL数据库交互的代理。给定一个输入问题,创建一个语法正确的sqlite查询来运行,然后查看查询结果并返回答案。除非用户指定了他们希望获得的特定数量的示例,否则请始终将查询结果限制在最多5个。你可以按相关列对结果进行排序,以返回数据库中最有趣的示例。切勿查询特定表中的所有列,而应根据问题只查询相关列。切勿对数据库执行任何数据操作语言(DML)语句(如INSERT、UPDATE、DELETE、DROP等)。

以下是相关的表格信息:
{{ customFunctionAgentflow_0 }}

注:
- 仅生成一个SQL查询
  • JSON结构化输出:在此,我们指示模型仅返回结构化输出,以防止大型语言模型(LLM)包含除SQL查询外的其他文本。

    • 键:“sql_query

    • 类型:“字符串”

    • 描述:“SQL查询”

  • 更新流状态:将键“sqlQuery”设置为值{{ output.sql_query }}

该节点利用数据库模式信息,将用户的自然语言问题转换为结构化的SQL查询。

步骤 4:验证 SQL 查询语法

添加一个与“生成SQL查询”大型语言模型(LLM)相连接的条件代理节点。

配置:

  • 说明

你是一位注重细节的SQL专家。请仔细检查SQL查询是否存在常见错误,包括:
- 使用NOT IN与NULL值
- 本应使用UNION ALL时却使用了UNION
- 使用 BETWEEN 指定独占范围
- 谓词中的数据类型不匹配
- 正确引用标识符
- 为函数使用正确数量的参数
- 转换为正确的数据类型
- 使用正确的列进行连接
  • 输入{{ $flow.state.sqlQuery }}

  • 场景: 场景1:“SQL查询正确且不包含错误”

    • 场景2:“SQL查询包含错误”

这个验证步骤会在执行前发现常见的SQL错误。

步骤5:处理查询重新生成(错误路径)

对于来自上一个条件代理节点的错误查询(输出1),请添加一个循环节点。

配置:

  • 循环回溯至:“生成SQL查询”

  • 最大循环次数:设置为5

这形成了一个反馈循环,使系统能够在验证失败时重新尝试生成查询。

步骤 6:执行有效的 SQL 查询

对于正确的查询(输出为0),请添加一个自定义函数节点。

配置:

  • 输入变量:在此,我们将生成的SQL查询作为变量传入,以在函数中使用。

    • 变量名:“sqlQuery”

    • 变量值:{{ $flow.state.sqlQuery }}

  • Javascript函数:此函数对数据库执行经过验证的SQL查询,并对结果进行格式化。


/// 译文内容:
---
根据上面的信息,执行如下指令:
缺失译文,请检查输入
const { DataSource } = require('typeorm');;

const HOST = 'localhost';;
const USER = 'testuser';;
const 密码 = 'testpwd';;
const DATABASE = 'testdatabase';;
const 端口 = 5432;;

const sqlQuery = $sqlQuery;;

const AppDataSource = new DataSource({
  类型:'postgres',
  主机:HOST,
  端口:PORT,
  用户名:USER,
  密码:PASSWORD,
  数据库:DATABASE,
  同步:否,
  日志记录:否,
});

let formattedResult = '';;

异步函数 runSQLQuery(query) {
  尝试 {
    等待 AppDataSource 初始化完成;
    const queryRunner = AppDataSource.createQueryRunner();;

    const rows = await queryRunner.query(query);;
    console.log('行数 =', rows);;

    如果 (rows.length === 0) {
      格式化结果 = '[无结果返回]';;
    } else {
      const columnNames = Object.keys(rows[0]);;
      const header = columnNames.join(' ');;
      const values = rows.map(row =>
        `columnNames.map(col => row[col]).join(' ')`
      );

      格式化结果 = 查询 + '\n' + 头部 + '\n' + 值.join('\n');;
    }

    等待 queryRunner 释放资源;
  } catch (err) {
    console.error('[错误]', err);;
    格式化结果 = `[执行查询时出错]:${err}`;
  }

  返回格式化结果;
}

等待执行SQL查询(sqlQuery);
返回 formattedResult;

步骤7:检查查询执行结果

添加一个与“运行SQL查询”功能相连接的条件代理节点。

配置:

  • 说明:“您是一位SQL专家。请检查查询结果是否正确或是否存在错误。”

  • 输入{{ customFunctionAgentflow_1 }}

  • 场景: 场景1:“结果正确且不包含错误”

    • 场景2:“结果查询包含错误”

这一步骤验证执行结果,并确定是否需要进一步修正。

第8步:生成最终响应(成功路径)

为了获得成功的结果(条件代理输出0),请添加一个LLM节点。

配置:

  • 输入消息{{ customFunctionAgentflow_1 }}

该节点根据查询结果生成自然语言回复。

步骤9:处理查询重新生成(运行时错误路径)

对于执行失败的情况(条件代理输出1),请添加一个LLM节点。

配置:

  • 消息:添加与步骤3相同的系统消息

  • 输入消息

给定生成的SQL查询:{{ $flow.state.sqlQuery }}
我遇到了以下错误:{{ customFunctionAgentflow_1 }}
重新生成一个能修复错误的新的SQL查询
  • JSON结构化输出:与步骤3相同

  • 更新流状态:将键“sqlQuery”设置为值{{ output.sql_query }}

此节点用于分析运行时错误并生成已更正的SQL查询。

步骤10:添加第二个环回

添加一个与“重新生成SQL查询”LLM(大型语言模型)相连接的循环节点。

配置:

  • 循环回溯至:“检查SQL查询”

  • 最大循环次数:设置为5

这为运行时错误纠正创建了第二个反馈循环。


完整流程结构

{"name": "SQL Agent", "description": "SQL Agent 是一个用于管理 SQL 数据库的工具。", "version": "1.0.0", "author": "zhangjing", "license": "MIT"}

摘要

  1. 开始 → 获取数据库结构

  2. 获取数据库结构 → 生成SQL查询

  3. 生成SQL查询 → 检查SQL查询

  4. 检查SQL查询(是否正确)→ 运行SQL查询

  5. 检查SQL查询(不正确)→ 重新生成查询(回环)

  6. 运行SQL查询 → 查看结果

  7. 检查结果(成功)→ 返回响应

  8. 检查结果(错误)→ 重新生成SQL查询

  9. 重新生成SQL查询 → 重新检查SQL查询(循环回溯)


测试您的SQL代理

用各种类型的数据库问题来测试你的代理:

  • 简单查询:“显示所有客户”

  • 复杂查询:“销售额最高的前5个产品是什么?”

  • 分析查询:“按月份计算平均订单价值”

此SQL代理流为数据库交互提供了一个健壮的、具有自我纠正功能的系统,能够处理自然语言中的SQL查询。

Last updated