ChatBI系统架构思考—自动生成SQL

2023-09-23 11:49:30 浏览数 (2)

主要是通过prompt优化,能够让LLMs大模型自动生成对应SQL查询语句,涉及到难点: 1、不同类型数据库,对应sql方言有些不同;

2、数据库、表等元数据信息影响SQL的准确度,避免大模型幻觉产生不存在的字段;

3、返回格式要求,方便SQL进行验证后提交执行。

这部分挑战来自于prompt的写法,大体思路通过问题描述说明 指令方式进行,主要:

一、问题描述

1、数据库类型:mysql、pgsql等

2、提问的问题

3、提供的元数据:Table schema,格式{db_name:{ table_name :{field_name,field_type}}}

二、SQL生成指令

1、指定特殊的sql方言,例如日期函数

2、指定只查询SELECT,不能生成修改、删除等sql语句

3、不能幻觉新的元数据,生成的SQL语句字段、表名一定在数据库存在。

4、返回结果的要求json格式,不能是markdown等格式。{database:$, table:$, assumption:$, query:sql}

三、演示示例

1、OPEN AI 大模型调用

代码语言:javascript复制
I will give you a list of postgresql tables schemas in JSON format, and some instructions.
Then I will ask you some questions about tables provided like Question: 
Query which students in Class 1 with scores greater than 90 where teacher name is zhangSan. 
 You might need to join tables to answer the questions.

Below is the format:
  Table Schema: (JSON array)
  Instructions: (sentences)

Table Schema:
{"sz_school":{"teachers":["teacher_name","teacher_class"],"students":["student_name","student_score","student_class"]}} ;

Instructions:
  * The table in the where clause appear in the tables or temp tables you selected from.
  * Use TO_CHAR(), DO NOT use FORMAT_DATE().
  * Convert TIMESTAMP to DATE using CAST().
  * Use full column name including the table name.
  * You can ONLY read, cannot UPDATE or DELETE or MAKE ANY CHANGES to the data.
  * It is Okay to make assumptions to answer the question.
  * DO NOT use any field not included in schemas.
  * Keep the assumptions concise.
  * You should return assumptions and PLAIN TEXT postgresql query for the question ONLY, NO explanation, NO markdown.
  * Use UNNEST() for ARRAY field.
  * Wrap table name with ``
  * NO content after the query.
  * Table name in the query should be without database name.

  Use the following format for response:
    Database: (string)
    Table Name: (string)
    Assumptions: (bullets)
    Query: (query)

对应返回结果:

代码语言:javascript复制
Database: sz_school_db

Table Name: sz_school.teachers, sz_school.students

Assumptions:
- Teacher ZhangSan teaches Class 1.
- There is only one teacher per class.

Query:
SELECT sz_school.students.student_name
FROM sz_school.students
JOIN sz_school.teachers ON sz_school.students.student_class = sz_school.teachers.teacher_class
WHERE sz_school.students.student_class = 1 AND sz_school.students.student_score > 90 AND sz_school.teachers.teacher_name = 'ZhangSan';

说明,这里和指令要求不符,生成了sql表名带了数据库名称。

2、中文大模型

代码语言:javascript复制
我将给你一份PostgreSQL数据库的表元数据信息的JSON格式数据以及一些指令。然后,我会根据这些表信息提出一些问题,例如:“查询Class 1中分数大于90的学生,教师名字为zhangSan。”您可能需要通过关联表生成SQL语句来回答这些问题。

以下是数据格式: 
   表元数据信息格式: (JSON数组) ,
   指令: (句子)

表元数据信息格式: {"sz_school":{"teachers":["teacher_name","teacher_class"],"students":["student_name","student_score","student_class"]}} ;

指令:
1、WHERE子查询语句中提到的表应该出现在存在的数据库中或者是查询语句的临时表。
2、支持对应PostgreSQL的方言,例如日期函数使用TO_CHAR(),不使用DATE_FORMAT (); 使用CAST()将TIMESTAMP转换为DATE。
3、应该使用完整的列名,包含表名。
4、你只能生成查询数据的SQL语句,不能生成修改更新或删除数据或对数据进行任何更改的SQL语句。
5、可以做出回答问题的假设,对假设做简明的解释。
6、不能使用表元数据信息中未包含的任何字段。
7、生成的SQL查询语句后不使用任何内容。
8、查询中的表名应不带数据库名。
9、请使用以下格式进行回复: 
  数据库: (字符串) 
  表名: (字符串) 
  假设: (句子) 
  查询: (生成的查询SQL语句)   

结果返回:

代码语言:javascript复制
{
  "数据库": "sz_school",
  "表名": "students",
  "假设": "在这个查询中,我们假设存在表名为'teachers'和'students'的两个表,它们通过'teacher_class'和'student_class'字段进行关联。同时,我们假设'teacher_name'字段的数据类型为VARCHAR,'teacher_class'字段的数据类型为VARCHAR,'students'表的'student_score'字段的数据类型为INTEGER,'student_class'字段的数据类型为VARCHAR。",
  "查询": "SELECT students.student_name FROM students INNER JOIN teachers ON students.student_class = teachers.teacher_class WHERE teachers.teacher_name = 'zhangSan' AND students.student_score > 90;"
}

四、总结

1、tocken限制的问题

如果prompt太长(潜在影响因素就是所有库名表名字段名太多影响,按需发送),可以把问题说明和指令分开发送,让指令依赖问题说明parentMessageId的方式。

代码语言:javascript复制
parentMessageId = ChatGPTAPI.sendMessage( promptDescribe,null);
ChatGPTAPI.sendMessage( promptInstructions,parentMessageId );         

2、prompt的优化是一门玄学

相同的prompt不断重试大模型回复的结果会不同,准确率还是一个现实的问题,另外prompt的优化,虽然是准确生成SQL的一个方向,但感觉还是很有挑战性。

3、费用说明

在线大模型服务,要做训练都费用成本都比较高。在线服务调用,目前OPEN AI :1000 tokens 仅为 0.2 美分,最好你的提示(prompt)或生成内容,不要超过 2048 个 tokens,大概相当于 1500 个单词。文心一言在线服务调用:0.012元/千tokens,中文字数为27,总计tokens为27。

0 人点赞