自然语言到SQL语言转义(基于大语言模型的NL2SQL)

为了使不熟悉SQL语言的用户能够方便地从数据库中进行数据分析,PolarDB for AI推出了自研的基于大语言模型的自然语言到SQL语言转义(Large Language Model based Natural Language to SQL,简称LLM-based NL2SQL)AI模型,作为内置模型供您使用。该功能利用大语言模型(LLM)将日常语言提问直接转换为精确的SQL查询语句,让您无需编写代码即可与数据库对话,从而显著提升数据分析和开发效率。

功能简介

PolarDB for AI提供的NL2SQL功能,本质上是一个智能翻译器。它将您用自然语言提出的问题(例如“上海哪家店收入最高?”),结合您数据库中的表结构信息,通过大语言模型(LLM)分析和理解,最终生成一条可以直接在数据库中执行的SQL查询语句。

其核心工作流程包括:

  1. 构建表结构索引:将数据库的表结构、列信息、注释甚至示例数据进行向量化,形成一个“数据库地图”,供大模型理解您的数据。

  2. 执行NL2SQL转换:您发起提问后,系统将问题和“数据库地图”一同发送给大模型,由大模型生成对应的SQL语句。

  3. (可选)模型微调:对于通用模型无法理解的行业术语(如“人流量”)或特定的查询模式,您可以通过配置模板和提示词,对模型进行微调,持续提升其准确性。

适用范围

  • 您的PolarDB PostgreSQL集群需满足以下条件:

    • 产品版本:企业版。

    • 计算节点:增加AI节点,并设置AI节点的连接数据库账号:添加与管理AI节点

      说明
      • 若您在购买集群时已添加AI节点,则可以直接为AI节点设置连接数据库的账号。

      • AI节点的连接数据库账号需具有读写权限,以确保能够顺利读取和写入目标数据库。

  • 访问地址:使用集群地址连接PolarDB集群。

计费说明

  • 添加AI节点会收取相应的AI节点的费用,AI节点按照普通的计算节点收费

  • 除普通的计算节点规格外,AI节点还支持三个特定规格,其主要应用于AI模型的创建和推理。价格信息,请参见特定AI节点计费规则

    • 830 GB + 中等规格GPU(polar.pg.g8.2xlarge.gpu

    • 11112.5 GB + 高规格GPU(polar.pg.g8.xlarge.guu

    • 24125 GB + 特高规格GPU(polar.pg.g6.2xlarge.guh

注意事项

  • 提问方式:在提出的问题中,应明确表达出限制条件及相关的实体值。同时,应尽量将条件前置,然后列出需寻找的列值对应的实体,最后提供可能的列名。示例如下:

    SELECT '超过1个房间的“房子”或“公寓”的属性名称是什么?'

    其中,超过1个房间是条件,房子和公寓是列值对应的实体,属性名称是可能的列名。

  • 查询结果准确率LLM-based NL2SQL是一个基于大语言模型的AI模型,其效果与诸多因素有关。为了使查询结果不脱离预期,总结了下列可能会影响整体准确率的几个因素:

    • 表和列注释的丰富程度:每张表及表中的列都添加注释,会提高查询的准确率。

    • 用户问题与表中列注释的匹配程度:用户问题中的关键词和列注释保持一致,语义上越接近,查询效果越好。

    • 生成的SQL语句长度:SQL语句中涉及的列越少、条件越简单,查询会越准确。

    • SQL语句中的逻辑复杂程度:SQL语句中涉及的高级语法越少,查询越准确。

使用说明

规范数据表

NL2SQL的前提是需要模型能够理解表的含义,包括列名代表的意思。因此,在使用LLM-based NL2SQL前,需要为常用的数据表以及表中的列添加注释。

  • 表注释

    表注释能够帮助LLM-based NL2SQL模型更好地理解表的基础信息,从而能更好地定位SQL语句中涉及的表。注释应简洁明了地概述表的主要内容。如订单、库存等,且尽量控制在10个字以内,避免引入过多的解释。

  • 列注释

    列注释通常由常用的名词或短语构成,例如订单编号、日期、店铺名称等,这些内容能够精确体现列名所表达的含义。同时,您可以在列注释中添加列的样例数据或映射关系。例如,对于列名为isValid,注释可以为是否有效。0:否。1:是。

说明

若原有注释无法修改,您可以使用进阶功能中的自定义表列注释能力调整相关注释。具体信息,请参见。

数据准备

此处以一个虚构的“阿里香”餐饮管理系统为例,通过一个完整的实践教程,指导您如何一步步使用NL2SQL功能,以及如何通过微调模型来优化特定业务场景下的查询准确率。

  1. 使用高权限账号登录集群。

  2. 创建polar_ai扩展并配置密钥。

    在数据库中执行以下命令,创建功能扩展并设置访问大模型服务所需的密钥。

    说明

    目前暂不支持在控制台上获取密钥。若您有相关需求,请提交工单联系我们获取密钥。

    -- 创建扩展
    CREATE EXTENSION polar_ai;
    
    -- 设置您的密钥
    SELECT polar_ai._ai_nl2sql_alter_token('sk-xxx');
  3. 准备示例数据。 执行以下SQL语句,创建“阿里香”餐饮系统的三张核心表:门店表、菜品表和账单表。

    点击展开查看详细SQL

    -- 门店表
    CREATE TABLE restaurant_info (
      id INT PRIMARY KEY,
      position VARCHAR(128)
    );
    COMMENT ON TABLE restaurant_info IS '门店表';
    COMMENT ON COLUMN restaurant_info.id IS '门店ID';
    COMMENT ON COLUMN restaurant_info.position IS '门店地点';
    
    -- 菜品表
    CREATE TABLE menu_info (
      id INT PRIMARY KEY,
      name VARCHAR(64),
      type INT,
      unit_price float8
    );
    COMMENT ON TABLE menu_info IS '菜品表';
    COMMENT ON COLUMN menu_info.id IS '菜品ID';
    COMMENT ON COLUMN menu_info.name IS '菜品名称';
    COMMENT ON COLUMN menu_info.type IS '菜品类型';
    COMMENT ON COLUMN menu_info.unit_price IS '菜品单价';
    
    -- 账单表
    CREATE TABLE bill_info (
      id INT PRIMARY KEY,
      items VARCHAR(512),
      actural_amount INT,
      restaurant_id INT,
      waiter VARCHAR(16),
      diner_count INT,
      pay_time DATE
    );
    COMMENT ON TABLE bill_info IS '账单表';
    COMMENT ON COLUMN bill_info.id IS '账单ID';
    COMMENT ON COLUMN bill_info.items IS '下单菜品';
    COMMENT ON COLUMN bill_info.actural_amount IS '实际付费';
    COMMENT ON COLUMN bill_info.restaurant_id IS '就餐门店';
    COMMENT ON COLUMN bill_info.waiter IS '服务员';
    COMMENT ON COLUMN bill_info.diner_count IS '就餐人数';
    COMMENT ON COLUMN bill_info.pay_time IS '下单时间';
    
    INSERT INTO restaurant_info (id, position) VALUES
    (1, '北京市朝阳区三里屯太古里南区'),
    (2, '上海市黄浦区南京东路步行街'),
    (3, '广州市天河区天河城B座'),
    (4, '深圳市南山区科技园科兴科学园'),
    (5, '杭州市西湖区文三路黄龙时代广场'),
    (6, '成都市锦江区春熙路IFS国际金融中心'),
    (7, '重庆市渝中区解放碑步行街'),
    (8, '西安市雁塔区大雁塔南广场'),
    (9, '南京市玄武区新街口德基广场'),
    (10, '武汉市江汉区汉口武商广场'),
    (11, '天津市和平区滨江道商业街'),
    (12, '长沙市岳麓区梅溪湖步步高广场'),
    (13, '青岛市市南区五四广场万象城'),
    (14, '大连市中山区友好广场百年城'),
    (15, '厦门市思明区中山路步行街'),
    (16, '苏州市工业园区金鸡湖时代广场'),
    (17, '宁波市鄞州区天一广场'),
    (18, '无锡市梁溪区南长街南禅寺'),
    (19, '合肥市蜀山区华润万象城'),
    (20, '南昌市红谷滩区红谷中大道万达广场');
    
    INSERT INTO menu_info (id, name, type, unit_price) VALUES
    (1, '宫保鸡丁', 1, 38.0),
    (2, '红烧肉', 1, 48.0),
    (3, '麻婆豆腐', 1, 22.0),
    (4, '清蒸鲈鱼', 1, 68.0),
    (5, '鱼香肉丝', 1, 32.0),
    (6, '酸辣土豆丝', 2, 16.0),
    (7, '手撕包菜', 2, 18.0),
    (8, '蒜蓉空心菜', 2, 15.0),
    (9, '西红柿炒蛋', 2, 18.0),
    (10, '干锅花菜', 2, 26.0),
    (11, '水煮牛肉', 1, 58.0),
    (12, '回锅肉', 1, 36.0),
    (13, '小炒黄牛肉', 1, 42.0),
    (14, '辣子鸡', 1, 46.0),
    (15, '东坡肉', 1, 52.0),
    (16, '冰镇酸梅汤', 3, 12.0),
    (17, '椰汁西米露', 3, 14.0),
    (18, '红豆沙', 3, 10.0),
    (19, '柠檬蜂蜜水', 3, 16.0),
    (20, '银耳莲子羹', 3, 18.0);
    
    INSERT INTO bill_info (id, items, actural_amount, restaurant_id, waiter, diner_count, pay_time) VALUES
    (1, '宫保鸡丁*1,麻婆豆腐*1,酸辣土豆丝*1', 92, 1, '张丽', 4, '2025-03-01'),
    (2, '清蒸鲈鱼*1,红烧肉*1,手撕包菜*1', 132, 2, '王强', 5, '2025-03-02'),
    (3, '鱼香肉丝*2,西红柿炒蛋*1', 82, 3, '李娜', 3, '2025-03-03'),
    (4, '水煮牛肉*1,干锅花菜*1,冰镇酸梅汤*2', 92, 4, '刘洋', 6, '2025-03-04'),
    (5, '回锅肉*1,蒜蓉空心菜*1,椰汁西米露*1', 76, 5, '陈芳', 2, '2025-03-05'),
    (6, '小炒黄牛肉*1,辣子鸡*1,手撕包菜*1', 104, 6, '赵敏', 4, '2025-03-06'),
    (7, '东坡肉*1,西红柿炒蛋*1,银耳莲子羹*1', 88, 7, '周杰', 3, '2025-03-07'),
    (8, '宫保鸡丁*1,清蒸鲈鱼*1', 106, 8, '吴婷', 2, '2025-03-08'),
    (9, '麻婆豆腐*2,酸辣土豆丝*1,柠檬蜂蜜水*1', 70, 9, '徐浩', 4, '2025-03-09'),
    (10, '红烧肉*1,水煮牛肉*1,手撕包菜*1', 122, 10, '孙莉', 5, '2025-03-10'),
    (11, '鱼香肉丝*1,干锅花菜*1,红豆沙*1', 68, 11, '高翔', 3, '2025-03-11'),
    (12, '辣子鸡*1,蒜蓉空心菜*1,冰镇酸梅汤*1', 74, 12, '林雪', 4, '2025-03-12'),
    (13, '回锅肉*1,西红柿炒蛋*1,椰汁西米露*1', 68, 13, '郑凯', 2, '2025-03-13'),
    (14, '小炒黄牛肉*1,酸辣土豆丝*1', 58, 14, '何静', 2, '2025-03-14'),
    (15, '东坡肉*1,麻婆豆腐*1,银耳莲子羹*1', 90, 15, '冯磊', 3, '2025-03-15'),
    (16, '宫保鸡丁*1,清蒸鲈鱼*1,手撕包菜*1', 124, 16, '邓超', 6, '2025-03-16'),
    (17, '水煮牛肉*1,西红柿炒蛋*1,柠檬蜂蜜水*1', 94, 17, '韩梅', 4, '2025-03-17'),
    (18, '红烧肉*2,蒜蓉空心菜*1', 112, 18, '唐军', 5, '2025-03-18'),
    (19, '鱼香肉丝*1,干锅花菜*1,酸梅汤*1', 66, 19, '许巍', 3, '2025-03-19'),
    (20, '宫保鸡丁*1,回锅肉*1,椰汁西米露*1', 92, 20, '乔峰', 4, '2025-03-20');
  4. 授权业务表权限给AI节点的数据库账号。

    例如,若您为AI节点配置的数据库连接账号为polarai_user,则需将restaurant_infomenu_infobill_info表的权限授予polarai_user

    说明

    在应用于业务环境时,请确保所设置的AI节点数据库账号具备相关业务表的权限。

    -- 授权
    GRANT ALL PRIVILEGES ON TABLE public."restaurant_info" TO polarai_user;
    GRANT ALL PRIVILEGES ON TABLE public."menu_info" TO polarai_user;
    GRANT ALL PRIVILEGES ON TABLE public."bill_info" TO polarai_user;

基础查询

  1. 创建表结构索引 执行以下命令,为当前数据库中的所有表创建一个名为schema_index的表结构索引。此操作会采集表的结构、注释等信息并进行向量化,为大模型提供上下文。

    SELECT polar_ai.ai_BuildSchemaIndex('schema_index');

    该命令会返回一个任务ID(如bce632ea-97e9-11ee-bdd2-492f4dfe0918)。您可以通过以下命令查询任务状态,当taskStatus显示为finish时,表示索引构建完成。

    SELECT polar_ai.ai_ShowTask('<your_task_id>');
  2. 执行NL2SQL查询 现在,您可以使用ai_nl2sql函数,将自然语言问题转换为SQL。

    简单查询

    • 提问:“这一周的总收入有多少?”。

    • 执行:

      SELECT polar_ai.ai_nl2sql('这一周的总收入有多少?', 'schema_index');
    • 预期返回SQL:

      SELECT SUM(actural_amount) AS total_income FROM bill_info WHERE pay_time BETWEEN '2025-08-25' AND '2025-08-31';

    更复杂的查询场景

    NL2SQL能够处理包含排序、连接、分组和计算的复杂问题。

    用户问题

    NL2SQL生成的SQL

    每个门店收入情况排序。

    SELECT restaurant_id, SUM(actural_amount) AS total_income FROM bill_info GROUP BY restaurant_id ORDER BY total_income DESC;

    在上海哪家门店收入最高?

    SELECT b.restaurant_id FROM restaurant_info r JOIN bill_info b ON r.id = b.restaurant_id WHERE r.position LIKE '%上海%' GROUP BY r.position ORDER BY SUM(b.actural_amount) DESC LIMIT 1;

    上海平均每个人消费多少?

    SELECT AVG(bill_info.actural_amount / bill_info.diner_count) AS average_consumption_per_person FROM bill_info WHERE bill_info.restaurant_id IN (SELECT id FROM restaurant_info WHERE position = '上海');

    这个月菜品下单量前十有哪些?

    SELECT mi.name, SUM(bi.items) as total_orders FROM bill_info bi JOIN menu_info mi ON bi.items = mi.id WHERE bi.pay_time >= '2024-10-01' AND bi.pay_time < '2024-11-01' GROUP BY mi.name ORDER BY total_orders DESC LIMIT 10;

    这个月比上个月收入的环比增长百分比多少?

    SELECT (SUM(CASE WHEN MONTH(pay_time) = 10 AND YEAR(pay_time) = 2024 THEN actural_amount ELSE 0 END) - SUM(CASE WHEN MONTH(pay_time) = 9 AND YEAR(pay_time) = 2024 THEN actural_amount ELSE 0 END)) / SUM(CASE WHEN MONTH(pay_time) = 9 AND YEAR(pay_time) = 2024 THEN actural_amount ELSE 0 END) * 100 AS growth_percentage FROM bill_info;

    上海的哪家门店人流量最高?

    SELECT r.position, COUNT(b.id) AS customer_flow FROM restaurant_info r JOIN bill_info b ON r.id = b.restaurant_id WHERE r.position LIKE '%上海%' GROUP BY r.id ORDER BY customer_flow DESC LIMIT 1;

    从以上示例中您可以看到,NL2SQL能够准确处理大部分包含排序、连接和分组的复杂查询。然而,您可能也注意到了,在某些情况下,模型的回复虽然在逻辑上正确,却未能完全符合您的预期。

    例如,对于问题“在上海哪家门店收入最高”,模型返回了门店ID (restaurant_id),但您实际想要的可能是门店的地址或名称。这是因为通用大模型虽然理解了查询的核心逻辑,但未能精确捕捉到您对返回结果格式的隐含期望。虽然您可以通过调整提问方式(例如,明确说明“请返回店名”)来临时解决这个问题,但要系统性地提升准确率并固化业务知识,更有效的方法是使用PolarDB for AI提供的模型微调功能。接下来的步骤将向您展示如何通过微调模型,来解决这类问题。

进阶使用:微调模型提升准确率

PolarDB for AI为您提供四种进阶使用方法。若您遇到以下问题时,可参考相应的进阶使用说明以解决相关问题。

  • 配置问题模板:通过配置通用的问题模板,使模型能够基于特定知识生成SQL语句。

  • 构建配置表:对问题进行前置处理或对生成SQL语句进行后置处理。

  • 自定义表列注释:如果原表或列的注释无法进行修改,可以为该表及相关列添加新的注释,以覆盖原表中的注释内容。

配置问题模板

问题模板是为特定领域知识而制定的,能够帮助模型更好地理解当前问题。您可以配置一些通用的问题模板,通过引入特定知识来指导模型,使得模型能按特定的知识来生成SQL语句。

使用说明

  1. 配置问题模板

    polar_ai扩展已自动为您创建了问题模板表,表结构如下:

    CREATE TABLE public.polar4ai_nl2sql_pattern (
      id serial NOT NULL COMMENT '主键' primary key,
      pattern_question text COMMENT '模板问题',
      pattern_description text COMMENT '模板描述',
      pattern_sql text COMMENT '模板SQL',
      pattern_params text COMMENT '模板参数'
    ) ;

    问题模板列说明

    列名

    说明

    模板问题

    带参数的问题,作为输入提供给LLM-based NL2SQL模型。

    在模板问题中,需要按照#{XXX}格式来写入参数。

    模板描述

    对模板问题进行提炼,并将一些实体作为参数,例如日期、年份、机构等。这些实体通常对应于表中的特定列。

    在模板描述中,需要按照【XXX】格式来写入参数,并且需要与模板问题中的参数顺序保持一致。

    模板SQL

    与模板问题相对应的正确SQL语句。该SQL语句中需将模板问题中的参数作为变量进行处理。

    说明

    模板问题与模板SQL中的参数可不相同,但需具备关联关系。例如,参数应具有相同的前缀,并且参数值之间存在一一映射关系。以#{category}#{categoryCode}为例,当category的参数值为普通商标、特殊商标和集体商标时,相应的categoryCode值分别为0、12。详细说明,请参见下述示例

    模板参数

    模板参数为一个JSON字符串,其结构由table_nameparam_infoexplanation三个参数组成,具体参数如下:

    • table_name string:模板SQL中的表名。

    • param_info array:模板SQL中的参数说明。

      • param_name string:参数名称。

      • value array:参数的取值样例。

        说明
        • 如果参数对应的是有限的枚举值,则尽量在value中将所有的值列出来。

        • 如果只是样例值,可以列出2~4个值。

        • 如果存在相互对应的参数,则需要通过数组索引来映射。以#{category}#{categoryCode}为例,category中的普通商标对应categoryCode中的1,特殊商标对应categoryCode中的2。详细说明,请参见下述示例

    • explanation string:补充说明。通常是对生成SQL语句的一些要求。比如,输出哪些信息或者对字段的一些说明。

    说明

    当不需要填写模板参数时,您可以将模板参数值设置为以下任意一种形式:

    • NULL

    • 空字符串

    • 空的list字符串[]

    示例

    模板问题

    模板描述

    模板SQL

    模板参数

    查询课程名称为#{courseName}授课状态为#{status}的课程

    【课程名称】【授课状态】的课程有哪些?

    SELECT course_name, course_time, course_location 
    FROM courses 
    WHERE 
    course_name=#{courseName} 
    AND status=#{statusCode}

    [{"table_name":"courses","param_info":[{"param_name":"#{courseName}","value":["数学","物理","化学","英语","历史","地理","生物","计算机科学","艺术","音乐","体育","编程","文学","心理学","哲学","经济学","社会学","物理学实验","化学实验","生物学实验"]},{"param_name": "#{status}", "value": ["未开课","授课中"]},{"param_name": "#{statusCode}","value": [0,1]}], "explanation": "输出课程名称course_name、课程时间course_time、课程地点course_location。注:status为常量映射类型。变量映射字段:statusCode。"}]

    查询年份为#{issueDate}年项目状态为#{projectStat}状态计划发布的国家标准有哪些?

    【年份】【项目状态】计划发布的国家标准有哪些?

    SELECT DISTINCT planNum, projectCnName, projectStat 
    FROM sy_cd_me_buss_std_gjbzjh 
    WHERE 
    `planNum` IS NOT NULL 
    AND `dataStatus` != 3 
    AND `isValid` = 1 
    AND projectStat=#{projectStat} 
    AND DATE_FORMAT(`issueDate`, '%Y')=#{issueDate}

    [{"table_name":"sy_cd_me_buss_std_gjbzjh","param_info":[{"param_name":"#{issueDate}","value":[2009,2010,2011,2012]},{"param_name":"#{projectStat}","value":["正在征求意见","已发布","正在审查"]}],"explanation":"输出标准名称projectCnName、计划号、项目状态"}]

    查询商标类型为#{category}国际分类为#{intCls}类型的商标有哪些?

    【商标类型】【国际分类】的商标有哪些?

    SELECT DISTINCT tmName, regNo, status 
    FROM sy_cd_me_buss_ip_tdmk_new 
    WHERE 
    dataStatus!=3 
    AND isValid = 1 
    AND category=#{categoryCode} 
    AND intCls=#{intClsCode}

    [{"table_name":"sy_cd_me_buss_ip_tdmk_new","param_info":[{"param_name":"#{intCls}","value":["化学原料","颜料油漆","日化用品","燃料油脂","医药"]},{"param_name":"#{category}","value":["普通商标","特殊商标","集体商标"]},{"param_name":"#{intClsCode}","value":[1,2,3,4,5]},{"param_name":"#{categoryCode}","value":[0,1,2]}],"explanation":"输出商标名称tmName、regNo申请号/注册号、status商标状态。注:category为常量映射类型。变量映射字段:categoryCode。intCls为常量映射类型。变量映射字段:intClsCode。"}]

    以本文示例场景为例,在public.polar4ai_nl2sql_pattern表中插入一条模板。例如,您希望“在xx哪家门店收入最高”这个问题能准确返回门店位置。

    INSERT INTO public.polar4ai_nl2sql_pattern (pattern_question, pattern_description, pattern_sql, pattern_params) VALUES (
      '在#{position}哪家门店收入最高', 
      '在【地点】哪家门店收入最高', 
      'SELECT r.position FROM bill_info b JOIN restaurant_info r ON b.restaurant_id = r.id WHERE r.position LIKE ''%#{position}%'' ORDER BY b.actural_amount DESC LIMIT 1;', 
      '[{"table_name":"bill_info","param_info":[{"param_name":"#{position}","value":["上海"]}], "explanation": "消费地点"}]'
    );

    这里的#{position}是槽位,可以匹配任意地点。pattern_sql是您期望生成的标准SQL。

  2. 创建问题模板索引表

    支持自定义索引表名(需符合数据库规范)。本文以pattern_index为例,创建问题模板索引表的SQL语句如下:

    SELECT polar_ai.ai_BuildSchemaIndex('pattern_index', '{"mode": "async", "resource": "pattern"}');
    说明

    创建问题模板索引表前,需确保问题模板表中存在至少一条记录。

    参数说明

    参数

    必填

    说明

    mode

    数据写入模式。固定为async,表示为异步模式。

    resource

    资源类型。固定为pattern,表示对问题模板信息进行向量化。

    该命令会返回一个任务ID(如bce632ea-97e9-11ee-bdd2-492f4dfe0918)。您可以通过以下命令查询任务状态,当taskStatus显示为finish时,表示索引构建完成。

    SELECT polar_ai.ai_ShowTask('<your_task_id>');
    说明

    如果public.polar4ai_nl2sql_pattern表中的数据发生了变更,则需要重新构建索引表pattern_index

  3. 在线使用问题模板

    在查询时,通过pattern_index_name参数指定您刚刚创建的模板索引。

    SELECT polar_ai.ai_nl2sql('在上海哪家门店收入最高', 'schema_index', '{"pattern_index_name":"pattern_index"}');

    参数说明

    • schema_index为当前数据库检索索引表名称。

    • pattern_index_name为问题模板索引表名称。

    • options内支持配置多个参数,以便对相关行为进行设置:

      参数名称

      参数描述

      取值范围

      pattern_index_top

      召回问题模板的最相近个数。

      取值范围:[1,10]。

      默认值为2,表示对当前问题模板只选出最优的2条模板。

      pattern_index_threshold

      召回问题模板是否相近时所使用的阈值。

      取值范围:(0,1]。

      默认值为0.85,表示当问题模板向量匹配超过0.85时才会被选中。

构建配置表

若您希望对问题进行前置处理,或对最终生成的SQL进行后置处理,可以通过配置表进行相应配置。

适用场景

  • 场景一:对问题中的确定性词语进行替换,如人名、行业用语、商品名替换等。

    例如:对于所有涉及张三的问题,将张三替换为ZS001。在此情况下,对于问题张三上个月的销售额是多少?张三今年的总销售额是多少?,在最终调用大模型之前,可以通过配置表将其全部预处理为ZS001上个月的销售额是多少?ZS001今年的总销售额是多少?

  • 场景二:对包含特定词语的问题补充额外信息。

    例如,对于所有涉及总销售额的问题,应补充总销售额的计算公式:总销售额 = SUM(销售额)。在最终调用大型模型之前,可以通过配置表添加此类信息,当问题满足相应条件时进行补充。

  • 场景三:对特定表或列的值进行映射替换。

    例如:对所有最终涉及student_courses表的SQL,将其中的status = '请假'替换为status = 0,以作为一种列值映射的兜底措施。

语法说明

polar_ai扩展已自动为您创建了构建配置表,表结构如下:

CREATE TABLE polar_ai.polar4ai_nl2sql_llm_config (
  id SERIAL NOT NULL COMMENT '主键' Primary Key,
  is_functional tinyint NOT NULL DEFAULT 't' COMMENT '是否生效',
  text_condition text COMMENT '文本条件',
  query_function text COMMENT '查询处理',
  formula_function text COMMENT '公式信息',
  sql_condition text COMMENT 'SQL条件',
  sql_function text COMMENT 'SQL处理'
) ;
说明

polar4ai_nl2sql_llm_config表中的数据发生变更时,您无需进行任何操作,变更的数据将立即生效。

参数说明

列名

说明

取值范围

示例

is_functional

表示该行配置是否生效。

当配置表存在时,默认每次进行NL2SQL时均采用。若存在不希望采用又暂时不想删除的配置项,可将is_functional置为0。使该配置行不生效。

  • 1(默认):生效

  • 0:不生效

  • is_functional=1,则表示该行配置生效。

  • is_functional=0,则表示该行配置不生效。

text_condition

前置处理:对问题进行文本条件判断。

如果判断为匹配,则使用query_functionformula_function两列进行处理,反之则不使用。
  • 当前支持三种条件运算符:&&||!!,分别表示以及

  • text_condition为空或空字符串时,表示对于所有问题均匹配。

text_condition张三||李四&&!!王五,则表示当问题包含张三,或者包含李四且不包含王五时,条件匹配。

例如:

  • 问题张三今年总销售额多少?:条件匹配。

  • 问题李四今年总销售额多少?:条件匹配。

  • 问题李四王五今年总销售额多少?:条件不匹配。

query_function

前置处理:对问题进行处理。

text_condition判断为匹配时使用。
  • 当前支持三种处理方式:appenddeletereplace,分别表示尾部追加删除以及替换

  • 格式需为JSON字符串。

query_function{"append":["一","二"],"delete":["?"],"replace":{"张三":"a","李四":"b"}},则表示:当text_condition匹配时,在问题的结尾添加,并删除问题中的。最后,将问题中的张三替换为a,将李四替换为b

例如:

  • 问题张三今年总销售额是多少?:在text_condition匹配时,会最终被处理为a今年总销售额是多少一二

  • 问题李四今年总销售额多少?:在text_condition匹配时,会最终被处理为b今年总销售额是多少一二

formula_function

前置处理:在问题中补充与具体业务/概念相关的计算公式信息或其他信息。

text_condition判断为匹配时使用。

-

formula_function总销售额:SUM(销售额),则在最终处理时,问题中的总销售额将采用SUM(销售额)公式作为附加信息一并进行处理。

sql_condition

后置处理:对模型生成的SQL进行条件判断。

如果判断为匹配,则使用sql_functionSQL进行处理,反之则不使用。

  • 当前支持三种条件运算符:&&||!!,分别表示以及

  • sql_condition为空或空字符串时,表示对于所有生成SQL均匹配。

sql_condition=students||student_courses&&!!courses,则表示:如果表students或表student_coursesSQL中,且表courses不在SQL中,则条件匹配。

例如:

  • SQL语句SELECT * FROM student_courses:条件匹配。

  • SQL语句SELECT c.course_name FROM student_courses sc JOIN courses c ON sc.courses_id = c.id;:条件不匹配。

sql_function

后置处理:对SQL进行处理,可用于对业务逻辑中的值映射进行强制处理。

sql_condition判断为匹配时使用。

  • 当前仅支持replace处理方式,代表替换

  • 格式需为JSON字符串。

sql_function={"replace":{"status = '请假'":"status = 0","status = '出勤'":"status = 1"}},则表示:在sql_condition匹配的情况下,将SQL中的status = '请假'替换为status = 0status = '出勤'替换status = 1

示例

样例数据

is_functional

text_condition

query_function

formula_function

sql_condition

sql_function

1

张三||李四&&!!王五

{"append":["一","二"],"delete":["?"],"replace":{"张三":"a","李四":"b"}}

1

总销售额:SUM(销售额)

1

students||student_courses&&!!courses

{"replace":{"status = '请假'":"status = 0","status = '出勤'":"status = 1"}}

场景示例

场景1:解释业务术语

大模型可能不理解“人流量”的含义。您可以告诉它“人流量”或“客流量”就是“就餐人数的总和”。

INSERT INTO public.polar4ai_nl2sql_llm_config (id, is_functional, text_condition, query_function, formula_function, sql_condition, sql_function) VALUES (
  1,
  1, 
  '人流量||客流量', -- 匹配问题中的关键词
  '', 
  '人流量或客流量使用就餐人数总和进行统计', -- 向大模型提供的解释
  '', 
  ''
);

配置后,无需重建索引,再次提问“上海哪家门店人流量最高”,模型就能生成基于diner_count字段(就餐人数)的正确SQL。

实践效果

  • 提问:“上海哪家门店人流量最高”。

  • 执行:

    SELECT polar_ai.ai_nl2sql('上海哪家门店人流量最高', 'schema_index', '{"pattern_index_name":"pattern_index"}');
  • 预期返回SQL:

    SELECT r.position, SUM(b.diner_count) AS total_customer_flow FROM restaurant_info r JOIN bill_info b ON r.id = b.restaurant_id WHERE r.position LIKE '%上海%' GROUP BY r.id ORDER BY total_customer_flow DESC LIMIT 1;

同理,在这个月比上个月收入的环比增长百分比多少?这个问题中,“环比”和“同比”的计算公式也可以录入到public.polar4ai_nl2sql_llm_config配置表中,以提高生成SQL的精确度。您可以自行进行挑战尝试。

场景2:提示SQL查询方式

默认情况下,模型可能对地名使用精确匹配(=),导致查询失败。您可以提示它对门店地点使用模糊匹配(LIKE)。

INSERT INTO public.polar4ai_nl2sql_llm_config (id, is_functional, text_condition, query_function, formula_function, sql_condition, sql_function) VALUES ( 
  2,
  1, 
  '', -- text_condition为空,表示全局生效
  '', 
  '门店地点position的匹配需要使用模糊搜索', 
  '', 
  ''
);

此配置将帮助模型在处理涉及“门店地点”的查询时,优先使用LIKE

说明

text_condition为空,表示全局生效。

实践效果

  • 提问:“上海平均每个人消费多少?”。

  • 执行:

    SELECT polar_ai.ai_nl2sql('上海平均每个人消费多少?', 'schema_index');
  • 预期返回SQL:

    SELECT AVG(b.actural_amount / b.diner_count) FROM bill_info b JOIN restaurant_info r ON b.restaurant_id = r.id WHERE r.position LIKE '%上海%';

同理,在这个月比上个月收入的环比增长百分比多少?这个问题中,“环比”和“同比”的计算公式也可以录入到public.polar4ai_nl2sql_llm_config配置表中,以提高生成SQL的精确度。您可以自行进行挑战尝试。

自定义表列注释

若您在规范数据表的过程中发现原有数据表或列的注释无法修改,您可在polar4ai_nl2sql_table_extra_info表中为该表及相关列添加新的注释。在使用NL2SQL时,该表中的注释将覆盖原表中的注释内容。

语法说明

polar_ai扩展已自动为您创建了polar4ai_nl2sql_table_extra_info表,表结构如下:

CREATE TABLE polar_ai.polar4ai_nl2sql_table_extra_info (
  id SERIAL NOT NULL PRIMARY KEY COMMENT '主键',
  table_name text COMMENT '表名称',
  table_comment text COMMENT '表说明',
  column_name text COMMENT '列名称',
  column_comment text COMMENT '列说明'
);
说明

polar4ai_nl2sql_table_extra_info表中的数据发生变更时,需重新执行创建表结构索引,才可使polar4ai_nl2sql_table_extra_info表中变更的数据生效。

示例

  1. 创建自定义表列注释表。

  2. menu_info表中type列的注释进行修改。此处,为type列添加额外的选项说明:菜品类型 1-荤菜,2-素菜,3-甜点

    INSERT INTO `polar4ai_nl2sql_table_extra_info` (`table_name`,`table_comment`,`column_name`,`column_comment`) VALUES ('menu_info','菜品表','type','菜品类型 1-荤菜,2-素菜,3-甜点');
  3. 重新执行创建表结构索引

    SELECT polar_ai.ai_BuildSchemaIndex('schema_index_new');

    该命令会返回一个任务ID(如bce632ea-97e9-11ee-bdd2-492f4dfe0918)。您可以通过以下命令查询任务状态,当taskStatus显示为finish时,表示索引构建完成。

    SELECT polar_ai.ai_ShowTask('<your_task_id>');

实践效果

  • 提问:“在哪家门店素菜卖的最多”。

  • 执行:

    SELECT polar_ai.ai_nl2sql('在哪家门店素菜卖的最多?', 'schema_index_new');
  • 预期返回SQL:

    SELECT r.position FROM bill_info b, menu_info m, restaurant_info r WHERE b.restaurant_id = r.id AND b.items::jsonb ? m.id::text AND m.type = 2 GROUP BY r.position ORDER BY COUNT(*) DESC LIMIT 1;

从上述输出结果中可以看出,模型已经将菜品类型对应为menu_info表中type列的列值2

附录:相关函数

_ai_nl2sql_alter_token

配置访问模型服务所需的密钥(Token)。这是使用NL2SQL功能前必须执行的初始化步骤。

说明

目前暂不支持在控制台上获取密钥。若您有相关需求,请提交工单联系我们获取密钥。

语法说明

text _ai_nl2sql_alter_token(text token);

参数说明

参数

描述

示例

token

访问模型服务的密钥。

sk-xxxxxx

示例

SELECT polar_ai._ai_nl2sql_alter_token('sk-xxxxxx');

ai_BuildSchemaIndex

为数据库的Schema或问题模板创建向量化索引。该索引帮助大语言模型(LLM)理解您的数据结构,是实现NL2SQL功能的核心步骤。这是一个异步任务。

语法说明

text ai_BuildSchemaIndex(text name, jsonb text2vecOption default '{"mode": "async", "resource": "schema"}');

参数说明

参数

描述

示例

name

创建的索引名称,必须符合对象名称规范。

my_schema_index

text2vecOption

(可选) 一个jsonb类型的对象,用于配置向量化过程的详细选项。

{"mode": "async", "resource": "schema", "tables_included": "tbl1,tbl2"}

text2vecOption说明

参数

必填

说明

mode

数据写入模式。默认为async,表示异步执行。

resource

资源类型,对何种信息进行向量化。

  • schema(默认):对数据表结构信息进行向量化。

  • pattern:对问题模板信息进行向量化。

tables_included

指定需要进行向量化的表名列表,多个表名用英文逗号,分隔。默认为空字符串'',表示对所有表进行操作。

to_sample

是否对列值进行采样。在列数较少(如小于15)的表中,采样有助于提高生成SQL的质量,但会增加索引构建时间。

  • 0(默认):不采样。

  • 1:进行采样。

columns_excluded

指定不参与NL2SQL操作的列。默认为空字符 '',表示所有列都参与。格式为'table1.col1,table1.col2,table2.col1'

pattern_table_name

resourcepattern时,指定问题模板表的名称。默认为polar4ai_nl2sql_pattern

返回值
返回一个唯一的异步任务 ID (job_id),可用于查询任务状态。

示例

-- 为 Schema 创建索引
SELECT polar_ai.ai_BuildSchemaIndex('my_schema_index');

-- 为指定的两个表创建 Schema 索引
SELECT polar_ai.ai_BuildSchemaIndex('my_schema_index_2', '{"mode": "async", "resource": "schema", "tables_included": "my_table1, my_table2"}');

ai_ShowTask

根据任务ID查询由ai_BuildSchemaIndex等函数创建的异步任务的执行状态。

语法说明

text ai_ShowTask(text job_id);

参数说明

参数

描述

示例

job_id

异步任务的唯一编号,由ai_BuildSchemaIndex等函数返回。

bce632ea-97e9-11ee-bdd2-492f4dfe0918

返回值
返回任务的状态:

  • init:任务正在初始化中。

  • Working:任务仍在进行中。

  • Finish:任务已成功完成。

示例

SELECT polar_ai.ai_ShowTask('bce632ea-97e9-11ee-bdd2-492f4dfe0918');

ai_nl2sql

将自然语言文本转换为可执行的SQL查询语句。

语法说明

text ai_nl2sql(text nl, text basic_index_name, jsonb options default '{}');

参数说明

参数

描述

示例

nl

需要转换的自然语言问题。

这一周的总收入有多少?

basic_index_name

使用的Schema索引名称,需通过ai_BuildSchemaIndex预先创建的。

my_schema_index

options

(可选) 一个jsonb类型的对象,用于配置 SQL 生成的高级选项,例如启用优化、调整召回策略等。

{"to_optimize": 1, "basic_index_top": 5}

options说明

参数

必填

说明

to_optimize

是否对生成的SQL进行优化。

  • 0(默认):不优化。

  • 1:执行优化,PolarDB for AI会对生成的SQL语句进行加工,使其更优。

basic_index_top

召回最相关表的数量。取值范围[1, 10],默认值为3。如果查询涉及多张表,可适当增大此值(如4或更大)以提高召回效果。

basic_index_threshold

召回表的相关性阈值。取值范围(0, 1],默认值为0.1。只有相关度得分超过此阈值的表才会被选中。

pattern_index_name

指定要使用的问题模板索引名称。

pattern_index_top

(仅当pattern_index_name指定时有效)召回最相关问题模板的数量。取值范围[1, 10],默认值为2

pattern_index_threshold

(仅当pattern_index_name 指定时有效)召回问题模板的相关性阈值。取值范围(0, 1],默认值为0.85

返回值
返回生成的可执行SQL字符串。

示例

SELECT polar_ai.ai_nl2sql('这一周的总收入有多少?', 'schema_index');

-- 返回结果
SELECT SUM(actural_amount) AS total_income FROM bill_info WHERE pay_time BETWEEN '2025-08-25' AND '2025-08-31';