為了讓不熟悉SQL語言的用戶能方便地從數據庫中取數分析,PolarDB for AI推出自研的基于大語言模型的自然語言到數據庫查詢語言轉義(Large Language Model based Nature Language to SQL,簡稱LLM-based NL2SQL)解決方案,PolarDB for AI會幫助用戶將輸入的自然語言轉換為SQL語句。和傳統NL2SQL的方法相比,LLM-based NL2SQL在語言理解方面會更強大,生成的SQL語句中能支持更多的函數,如日期加減等。LLM-based NL2SQL甚至能夠理解一些簡單的映射關系,如有效->isValid=1
等。經過適當調整后還能理解用戶的一些常用SQL搭配,如條件中默認選用datastatus=1
等。本文介紹了LLM-based NL2SQL的使用方法。
前提條件
已開啟PolarDB for AI功能。建議增加AI節點時,節點規格選擇包含GU30的規格。
已通過PolarDB MySQL版的集群地址連接數據庫集群。
使用LLM-based NL2SQL解決方案涉及的表在指定庫內。
注意事項
使用LLM-based NL2SQL功能時,提出的問題中要明確表達出限制條件和相關的實體值。同時,盡量將條件前置,然后是需要找的列值對應的實體,最后是可能的列名。示例如下:
超過1個房間的“房子”或“公寓”的屬性名稱是什么?
其中,超過1個房間是條件,房子和公寓是列值對應的實體,屬性名稱是可能的列名。
使用說明
規范數據表
NL2SQL的前提是模型要理解表的含義,包括列名代表的意思。所以使用LLM-based NL2SQL時,需要對常用的數據表以及表中的列添加注釋。
表注釋
表注釋能夠幫助LLM-based NL2SQL模型更好地理解表的基礎信息,能更好地定位SQL語句中涉及的表。注釋可以簡潔明了地說明表的大致內容。如訂單、庫存等,注釋盡量控制在10個字以內,不要引入過多解釋。
列注釋
列注釋由用戶常用的名詞或短語構成。例如,訂單編號、日期、店鋪名稱等,能精確體現列名所表達的含義。
您可以在列注釋中添加列的樣例數據或映射關系。例如,列名為isValid
,它的注釋可以為是否有效。0:否。1:是。
。
如果原有注釋無法修改,您可以使用進階功能中的自定義表列注釋能力進行注釋調整,具體請參見自定義表列注釋。
數據準備
構建數據表的檢索索引表。
為了提取數據表中的數據,需要構建數據表的檢索索引表,支持自由指定表名(需滿足數據庫規范),本文以
schema_index
為例,構建檢索索引表的SQL語句如下:/*創建數據庫表索引*/ /*polar4ai*/CREATE TABLE schema_index(id integer, table_name varchar, table_comment text_ik_max_word, table_ddl text_ik_max_word, column_names text_ik_max_word, column_comments text_ik_max_word, sample_values text_ik_max_word, vecs vector_768,ext text_ik_max_word, primary key (id));
將數據表中的信息導入檢索索引表。
將數據表中的信息導入檢索索引表的SQL語句如下:
/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_text2vec, select '') WITH (mode='async', resource='schema') into schema_index;
執行以上SQL語句后,PolarDB for AI默認會對當前庫下的所有表執行轉向量操作,并對列值進行取樣。其中,
into
后需要填寫上一步創建的檢索索引表名。以上SQL默認會對當前庫下的所有表轉向量,并會對列進行值取樣。with()
內支持多個參數對相關行為進行設置:tables_included:用于設置轉向量的表,默認為
''
,表示對所有的表執行轉向量操作。設置時多個表名之間使用英文逗號分隔,并拼接為字符串。to_sample:用于設置是否對列值進行取樣。對列值進行取樣會使得數據表導入索引表的任務時間變長,但在表的列數較少(<15列)時能提高生成的SQL的質量。取值范圍如下:
0(默認):表示不對列值取樣。
1:表示對列值取樣。
columns_excluded:用于設置不參與LLM-based NL2SQL操作的列。默認為
''
,表示所有參與LLM-based NL2SQL操作的表的所有列均參與后續LLM-based NL2SQL操作。設置時需要將選中的表中不參與后續LLM-based NL2SQL操作的列按照table_name1.column_name1,table_name1.column_name2,table_name2.column_name3
的格式拼接為字符串。
示例如下:
/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_text2vec, select '') WITH (mode='async', resource='schema', tables_included='graph_info,image_info,text_info', to_sample=1, columns_excluded='graph_info.time,text_info.ext') into schema_index;
該語句表示對當前庫中的
graph_info
、image_info
以及text_info
表執行轉向量操作,并且對列進行值取樣。同時表graph_info
中的time
列和表text_info
中的ext
列不參與后續的LLM-based NL2SQL操作。執行完該語句后,會返回該任務的
taskid
,如bce632ea-97e9-11ee-bdd2-492f4dfe0918
。您可以執行以下命令來查看導入狀態,當返回值顯示為finish
時,表示索引構建完成。/*polar4ai*/SHOW TASK `bce632ea-97e9-11ee-bdd2-492f4dfe0918`;
說明如果
polar4ai_nl2sql_table_extra_info
中的數據發生變更,則需要重新執行步驟1和步驟2。
在線使用LLM-based NL2SQL
您可以執行以下SQL語句來在線使用LLM-based NL2SQL:
/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_nl2sql, select '按照老師名字的字母升序排列,顯示老師的名字和安排他們教的課程名稱。') WITH (basic_index_name='schema_index');
上述SQL語句中,SELECT后需要輸入待轉換為SQL語句的用戶問題,basic_index_name
為數據庫索引表名稱。with()
內支持設置的參數如下:
參數名稱 | 參數描述 | 取值范圍 |
to_optimize | 是否進行SQL優化。 | 取值范圍:0或1。默認值為0。
|
basic_index_top | 召回表的最相近個數 | 取值范圍:[1,10]。
|
basic_index_threshold | 召回表判斷是否相近時所使用的閾值 | 取值范圍:(0,1]。 默認值為0.1,表示當數據庫表向量匹配超過0.1時才會被選中。 |
推薦的問句樣例如下:
進行過兩次或更多次治療的專家的ID、角色和名字是什么?
被養最多數量狗的品種名稱是什么?
被喂養最多數量的狗都有哪些品種?給我這個品種的名字。
哪一位主人為他或她的狗支付了最多的治療費?列出主人的ID和姓氏。
告訴我花在他或她的狗身上最多治療費的主人的ID和姓氏。
總花費最少的治療類型的描述是什么?
進階使用
配置問題模板
您可以使用一些通用的問題模板,通過引入特定知識來指導模型,使得模型能按特定的知識來生成SQL語句。
初次體驗LLM-based NL2SQL操作時不需要執行該操作。
創建問題模板表。
創建問題模板表的SQL語句如下:
DROP TABLE IF EXISTS `polar4ai_nl2sql_pattern`; CREATE TABLE `polar4ai_nl2sql_pattern` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `pattern_question` text COMMENT '模板問題', `pattern_description` text COMMENT '模板描述', `pattern_sql` text COMMENT '模板SQL', `pattern_params` text COMMENT '模板參數', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
其中,表名必須以
polar4ai_nl2sql_pattern
開頭,表結構中必須包含上述建表語句中的五個列。問題模板是為特定領域知識而制定的,能夠方便模型更好地理解當前問題。問題模板由模板問題、模板描述、模板SQL、模板參數四部分組成。
模板問題:帶參數的用戶問題。會作為輸入提供給LLM-based NL2SQL模型。在模板問題中,需要按照
#{XXX}
格式來寫入參數。模板描述:對用戶問題進行提煉,會將一些實體作為參數。如日期、年份、機構等,這些實體通常會對應表中的特定列。在模板描述中使用
【XXX】
格式表示,并且需要與模板問題中的參數順序保持一致。模板SQL:與用戶問題對應的正確的SQL語句,且需要將一些變量作為參數,參數需要和模板問題中的參數保持一致。
模板問題和模板SQL中同前綴的參數,其參數值存在一一映射關系。例如,
#{category}
和#{categoryCode}
,category
有普通商標、特殊商標和集體商標這三個參數值,則對應的categoryCode
為0、1、2。模板參數:模板參數由一個JSON數組構成,其中每個JSON中的具體參數如下:
table_name:模板SQL中的表名。為字符串類型。
param_info:
table_name
表中的參數,其中param_name
表示參數名稱,為字符串類型。value
是參數的取值樣例,為數組類型。如果參數對應的是有限的枚舉值,則盡量在value
中將所有的值列出來。如果只是樣例值,可以列出2~4個值。如果存在相互對應的參數(如intCls
和intClsCode
、category
和categoryCode
),則需要通過list
順序來映射。例如,intCls
中的化學原料對應inClsCode
中的1,顏料油漆對應inClsCode
中的2。explanation:補充說明。通常是對生成的SQL語句的一些要求,比如,輸出哪些信息或者對字段進行說明。
創建問題模板表的示例如下:
主鍵
模板問題
模板描述
模板SQL
模板參數
1
查詢年份為#{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;計劃號;項目狀態"}]
2
查詢商標類型為#{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。"}]
說明當不需要填寫模板參數時,您可以將模板參數值設置為以下任意一種形式:
NULL
空字符串
空的list字符串[]
創建問題模板索引表。
您可以自由選擇索引表名,索引表名需符合數據庫規范,建議與步驟1中指定的表名保持一致。接下來的介紹將以
pattern_index
作為示例:創建問題模板索引表的SQL語句如下:
/*創建問題模版索引*/ /*polar4ai*/drop table if exists pattern_index; /*polar4ai*/create table pattern_index(id integer, pattern_question text_ik_max_word, pattern_description text_ik_max_word, pattern_sql text_ik_max_word, pattern_params text_ik_max_word, pattern_tables text_ik_max_word, vecs vector_768, primary key (id));
將問題模板信息導入索引表。
將問題模板信息導入索引表的SQL語句如下:
/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_text2vec, select '') WITH (mode='async', resource='pattern') into pattern_index;
其中,
INTO
后需要填寫步驟2中的問題模板索引表名。with()
中支持多個參數,mode='async'
表示異步,resource='pattern'
表示對問題模板進行向量化,這2個參數的值不可缺少,亦不可更改。除此之外,with()
中還支持配置pattern_table_name
參數,不填寫該參數值時默認為polar4ai_nl2sql_pattern
。填寫時必須填寫以polar4ai_nl2sql_pattern
開頭的字符串格式的表名,該名稱對應步驟1創建問題模板索引表時指定的表名。如果用戶希望為不同場景或業務維護不同的pattern index
,可以在創建問題模板索引表時指定不同的表名。如為用戶相關場景創建polar4ai_nl2sql_pattern_user
表,則第二步創建問題模板索引時,將索引名定為pattern_index_user
,在將信息導入索引表時,使用如下SQL語句:/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_text2vec, select '') WITH (mode='async', resource='pattern', pattern_table_name='polar4ai_nl2sql_pattern_user') into pattern_index_user;
查看任務狀態,并等待任務完成。
您可以根據返回的
taskid
信息來查看任務執行狀態,查看任務執行狀態的SQL語句如下:/*polar4ai*/SHOW TASK `6d629f42-98c5-11ee-85c2-894330dff27f`;
等待返回
finish
信息后,問題模板信息將會被模型引用。您可以執行以下SQL語句來查看問題模板索引信息:/*polar4ai*/SELECT * FROM pattern_index;
說明如果
polar4ai_nl2sql_pattern
表中的數據有更新,則需要重新執行步驟2和步驟3。在線使用問題模板。
您可以執行以下SQL語句來在線使用LLM-based NL2SQL和問題模板:
/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_nl2sql, select '按照老師名字的字母升序排列,顯示老師的名字和安排他們教的課程名稱。') WITH (basic_index_name='schema_index',pattern_index_name='pattern_index');
上述SQL語句中,SELECT后需要輸入待轉換為SQL語句的用戶問題,
basic_index_name
為數據庫索引表名稱,pattern_index_name
為問題模板索引名稱。with()
內支持設置的與問題模板有關的參數如下(其他參數說明請參見在線使用LLM-based NL2SQL):參數名稱
參數描述
取值范圍
pattern_index_top
召回問題模板的最相近個數。
取值范圍:[1,10]。
默認值為2,表示對當前問題模板只選出最優的2條模板。
pattern_index_threshold
召回問題模板是否相近時所使用的閾值。
取值范圍:(0,1]。
默認值為0.85,表示當問題模板向量匹配超過0.85時才會被選中。
構建配置表
若您希望對問題進行前置處理,或者對最終生成的SQL進行后置處理時,可以使用配置表進行配置。
適用場景
場景一:對問題中的確定性詞語進行替換,如人名、行業用語、商品名替換等。
比如:對所有包含
張三
的問題,將張三
替換為ZS001
。此時,對于問題張三上個月的銷售額是多少?
、張三今年的總銷售額是多少?
,在最終調用大模型之前都可以通過配置表將其全部前置處理為ZS001上個月的銷售額是多少?
、ZS001今年的總銷售額是多少?
。場景二:對包含特定詞語的問題補充額外信息。
比如:對所有包含
總銷售額
的問題,都補充總銷售額
的計算公式總銷售額:SUM(銷售額)
,在最終調用大模型之前都可以通過配置表添加此類信息,當問題滿足對應的條件時進行補充。場景三:對特定表或列的值進行映射替換。
比如:對所有最終關于表user_info的SQL,都將其中的
status = '已創建'
替換為status = 0
,作為一種列值映射的兜底措施。
語法說明
構建配置表的SQL語句如下:
CREATE TABLE `polar4ai_nl2sql_llm_config` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`is_functional` int(11) NOT NULL DEFAULT '1' COMMENT '是否生效',
`text_condition` text COMMENT '文本條件',
`query_function` text COMMENT '查詢處理',
`formula_function` text COMMENT '公式信息',
`sql_condition` text COMMENT 'SQL條件',
`sql_function` text COMMENT 'SQL處理',
PRIMARY KEY (`id`)
);
相關說明如下:
列名 | 說明 | 取值范圍 | 示例 |
is_functional | 表示該行配置是否生效。 說明 當配置表存在時,默認每次進行NL2SQL時均采用。若存在不希望采用又暫時不想刪除的配置項,可將 |
| 若 |
text_condition | 對問題進行文本條件判斷。 如果判斷為匹配,則使用 |
| 若 例如,對于問題 |
query_function | 對問題進行處理。 當 | 當前支持 | 若 例如,對于問題 |
formula_function | 在問題中補充與具體業務/概念相關的計算公式信息或其他信息。 當 | - | 若 |
sql_condition | 對大模型生成的SQL進行后置處理的條件。 如果判斷為匹配,則使用 |
| 若 例如,對于SQL |
sql_function | 對SQL進行處理,可用于對業務邏輯中的值映射進行強制處理。 當 | 當前支持 | 若 |
示例
id | is_functional | text_condition | query_function | formula_function | sql_condition | sql_function |
1 | 1 |
|
| |||
2 | 1 |
| ||||
3 | 1 |
|
|
自定義表列注釋
在對數據庫表中的列添加注釋時,如果原有的注釋不能改變,您可以在polar4ai_nl2sql_table_extra_info
表中對列添加注釋,且在使用LLM-based NL2SQL解決方案的過程中,該表中的注釋會覆蓋原表中的注釋內容。
語法說明
polar4ai_nl2sql_table_extra_info
表的建表語句如下:
DROP TABLE IF EXISTS `polar4ai_nl2sql_table_extra_info`;
CREATE TABLE `polar4ai_nl2sql_table_extra_info` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`table_name` text COMMENT '表名稱',
`table_comment` text COMMENT '表說明',
`column_name` text COMMENT '列名稱',
`column_comment` text COMMENT '列說明',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
示例
id | table_name | table_comment | column_name | column_comment |
1 | sy_cd_me_buss_ip_patn_new | 專利 | patType | 專利類型。取值范圍如下:
|
2 | sy_cd_ms_base_ipr_devdemo_list | 知識產權優勢和示范企業 | certName | 知識產權優勢和示范企業認定名稱。取值范圍如下:
|
寬表支持
當用戶判斷庫中存在列數較多的寬表,或在NL2SQL的使用過程中收到如Please use column index to avoid oversize table information.
的錯誤消息時,可以使用以下流程以支持寬表:
構建列索引表。
構建列索引表時,表名
column_index
可以自由指定,但不能與庫中已存在的表名相同,一個庫中存在一張列索引表即可。建表語句如下:/*polar4ai*/CREATE TABLE column_index(id integer, table_name varchar, table_comment text_ik_max_word, column_name text_ik_max_word, column_comment text_ik_max_word, is_primary integer, is_foreign integer, vecs vector_768, ext text_ik_max_word, primary key (id));
將數據表信息以列為粒度導入列索引表中。
/*polar4ai*/SELECT * FROM PREDICT (MODEL _polar4ai_text2vec, select '') WITH (mode='async', resource='column') into column_index;
執行該語句后,會顯示一個
taskid
,如bce632ea-97e9-11ee-bdd2-492f4dfe0918
。通過執行以下SQL語句可以查看導入狀態,當顯示finish后,則表示索引構建完成。/*polar4ai*/SHOW TASK `bce632ea-97e9-11ee-bdd2-492f4dfe0918`;
在線使用寬表。
/*polar4ai*/SELECT * FROM PREDICT (MODEL_polar4ai_nl2sql, SELECT '按照老師名字的字母升序排列,顯示老師的名字和安排他們教的課程名稱。') WITH (basic_index_name='schema_index',column_index_name='column_index');
其中,無論使用哪一個
schema index
或者pattern index
,在數據庫中都可以使用同一個column_index_name
,不需要像schema
或者pattern
一樣區分場景或者業務語義,因為這里僅作信息的精簡。column_index_name
參數對于絕大多數沒有超長的請求不會產生影響,僅僅對于觸發了長度限制的NL2SQL,會通過column_index_name
精簡表信息,因此會丟失一部分準確度,但避免了因Prompt過長導致大模型報錯的問題。
小結
LLM-based NL2SQL屬于AI算法,AI算法的效果與諸多因素有關。為了使得查詢結果不脫離預期,總結了下列可能會影響整體準確率的幾個因素:
表和列注釋的豐富程度:每張表及表中的列都添加注釋,會提高查詢的準確率。
用戶問題與表中列注釋的匹配程度:用戶問題中的關鍵詞和列注釋保持一致,語義上越接近,查詢效果越好。
生成的SQL語句長度:SQL語句中涉及的列越少、條件越簡單,查詢會越準確。
SQL語句中的邏輯復雜程度:SQL語句中涉及的高級語法越少,查詢越準確。