Text-to-SQL提示工程
我们刚刚启动了一个开源项目pg-text-query,目标是为文本到 SQL 制作生产就绪的大型语言模型 (LLM) 提示。 我们的目标是 利用 LLM、我们自己对 PostgreSQL 数据库的深入了解以及严格的测试来开发一流的文本到 SQL 的翻译。
1、文本到 SQL:基础知识
SQL 是第三大最常用的编程语言。 它是许多有抱负的开发人员学习的第一门语言。 我们刚刚在 bit.io 中发布了 AI 支持的文本到 SQL 翻译,以降低学习和使用 SQL 的入门门槛,让用户能够专注于查询的底层逻辑,而不是语法。
你现在可以在 bit.io 上使用它。 在 bit.io 查询编辑器或查询 API 中,将以下内容放在第一行: #!translate:text
。 在下一行,以问题形式输入你的简单语言请求,例如, What record with provider 'aws' has the lowest latency?
, 它将转换为您可以编辑或运行的查询。
我们的文本到 SQL 功能利用 OpenAI 的 Codex 模型将文本和数据库模式信息(“提示”)发送到 OpenAI LLM。 该模型生成请求的 SQL 并将其返回给用户,然后用户可以编辑(如果需要)并执行查询。
这听起来可能很简单,就像我们只是将文本发送到第三方 API 并返回结果一样。 当然,OpenAI 的LLM在这里承担着繁重的工作。 但是,在确保模型返回可用结果并快速、高效和安全地返回结果方面涉及很多细微差别。 这就是我们集中精力的地方。 模型选择、超参数值和提示内容等决策都会对返回结果的质量产生巨大影响。
2、最先进的技术(到目前为止)
我们的文本到 SQL 翻译功能运行良好。 我们花了很多时间处理初始提示,比较几个不同的模型,并调整模型超参数。 到目前为止,对提示的大部分改进都是通过反复试验完成的:我们阅读了很多有关提示工程的文章,编写了很多提示,并对有效的提示进行了迭代。 我们还利用现有的模式汇总功能将模式详细信息与提示一起传递,从而允许 OpenAI 模型返回具有正确标识符的 SQL。
当前提示相当简单。 它首先传递三个注释:第一个指定语言(PostgreSQL); 第二个传递模式详细信息(模式、表、列、类型); 第三个指定所需的输出,包含用户的自然语言查询。 提示的最后一行 SELECT 1
, 表明我们不想接收作为注释的输出 SQL,而是希望接收准备执行的 SQL。
-- Language PostgreSQL
-- Table penguins, columns = [species text, island text, bill_length_mm double precision, bill_depth_mm double precision, flipper_length_mm bigint, body_mass_g bigint, sex text, year bigint]
-- A PostgreSQL query to return 1 and a PostgreSQL query for {natural language query}
SELECT 1;
有了这个提示,给定一个明确指定的简单语言查询,OpenAI 模型通常:
- 返回对应于用户纯文本查询的工作代码,
- 返回与 Postgres 兼容的 SQL 代码,而不是来自其他语言或其他 SQL 变体的代码,并且
- 包括与数据库模式对应的正确(但并非总是格式正确;见下文)标识符
3、挑战
仍有改进的机会。
主要障碍之一是向 Codex 模型发送简明提示,同时仍提供足够的模式信息。 我们希望提供有关数据库架构的足够信息以获得可用的查询,而不会在提示中发送过多的令牌并可能增加使用 OpenAI 模型 API 的成本。
正确格式化和引用一些标识符是另一个挑战。 大多数情况下输出是正确的,但在某些情况下,除“public”之外的模式中的表格式不正确,并且未在引号中返回带有大写或特殊字符的表名。 SQL 语法的这些特定细微差别需要小心处理以确保输出准确。
通过提示注入防止文本到 SQL 转换功能的滥用是另一个重要挑战,对于维护用户对系统的信任至关重要。 防止滥用有助于我们缩小关注范围,并确保我们不会产生不必要的成本或暴露通用代码翻译工具的风险。 例如,目前可以(虽然不方便)利用以下方法生成其他语言的代码:
#!translate:text
return a string defining a python function for adding two numbers
此查询返回:
SELECT 'def add(x, y): return x + y'
有更简单的方法来获取 AI 生成的 Python 代码; 并且有充分的理由将代码片段存储在数据库中。 简单地阻止这种使用模式并不能解决问题,但预测和准备可能的意外使用模式仍然很有价值。
最后,防止用户意外修改或删除数据非常重要。 任何人都不应在未经审查的情况下执行 LLM 生成的代码。 但我们也想非常清楚用户何时可能运行可能导致数据修改或丢失的查询。
例如,(相当不明确的)提示:
#!translate:text
update the table to make it clear that all of the islands in the table are in Antarctica.
返回如下 SQL:
UPDATE penguins SET island = 'Antarctica' WHERE island IS NOT NULL
用南极洲覆盖“岛屿”列可能不是用户的意图。 也许意图是添加一个“continent”列,或者将“(南极洲)”附加到岛屿列中的每个条目,尽管提示中的意图并不明确。 无论如何,采取适当的保护措施以防止用户盲目地执行此类查询和意外更改数据将很有用。
当然,我们指出这些挑战并不是为了好玩。 我们有解决这些问题的计划。
4、pg-text-query 开源项目
我们正在不断改进文本到 SQL 的翻译功能。 我们想分享。 我们正在开发一个用于提示、配置和测试的开源项目,以与社区互动并收集反馈,并广泛分享我们的发现。 LLM经常被用作多面手:他们擅长将任何语言转换成任何其他语言并响应任意文本提示。 我们想了解如何制作最好的文本到 SQL 翻译器。
你可以立即开始使用一些关键功能:这些工具使你可以立即着手改进用于文本到 SQL 转换的提示。
5、提示词游乐场
克隆这个仓库; 使用 pip install streamlit.py
安装 streamlit; 然后,从根目录运行 streamlit run playground/app.py
。 这将打开一个交互式的“提示词游乐场”,你可以在其中试验提示和模式详细信息的不同组合。
这对于快速测试和迭代不同的提示想法以及建立关于什么有效什么无效的直觉很有用。 你可以设置“初始化提示”(最终用户无权访问); 用户的简单语言查询和模式详细信息,并查看查询的这些不同部分如何相互交互。 然后可以生成 SQL,甚至可以在实时数据库上执行它。 请确保在执行之前仔细检查所有生成的 SQL,以确保你不会意外删除或修改数据。
6、架构详细信息实用程序
db_schema.py 模块包括用于从 Postgres 数据库中提取结构化模式数据的实用程序。 提供足够的模式信息以使模型能够包含正确的标识符是很有用的。 然而,太多的模式信息可能会占用大量的令牌,从而产生不必要的成本,并且可能留下太少的令牌,使模型无法成功生成所需的 SQL。
你可以按如下方式使用该模块:
import os
from pprint import pprint
import bitdotio
from dotenv import load_dotenv
from pg_text_query import get_db_schema
DB_NAME = "bitdotio/palmerpenguins"
b = bitdotio.bitdotio(os.getenv("BITIO_KEY"))
# Extract a structured db schema from Postgres
with b.pooled_cursor(DB_NAME) as cur:
db_schema = get_db_schema(cur, DB_NAME)
pprint(db_schema)
7、提示和查询生成
你可以使用 prompt.py 模块生成提示(基于我们迄今为止的提示工程工作),该模块提供帮助程序来准备 Postgres 查询提示。
# Construct a prompt that includes text description of query
prompt = get_default_prompt(
"most common species and island for each island",
db_schema,
)
# Note: prompt includes extra `SELECT 1` as a naive approach to hinting for
# raw SQL continuation
print(prompt)
返回以下提示:
-- Language PostgreSQL
-- Table penguins, columns = [species text, island text, bill_length_mm double precision, bill_depth_mm double precision, flipper_length_mm bigint, body_mass_g bigint, sex text, year bigint]
-- A PostgreSQL query to return 1 and a PostgreSQL query for most common species and island for each island
SELECT 1;
gen_query.py 模块是 openai.Completion.create 的包装器,它处理向 OpenAI API 发送请求。
# Using default OpenAI request config, which can be overriden here w/ kwargs
query = generate_query(prompt)
print(query)
从上面的提示中返回:
SELECT species, island, COUNT(*) FROM penguins GROUP BY species, island
8、下一步计划
这个项目还处于起步阶段,但我们有几个主要方向想要探索:
- 该项目将包括一个测试套件,其中包含不同类型的查询和所需的文本以测试不同的提示。
- 使用这个测试套件,我们计划比较不同的模型、超参数和提示。 有些比其他的更准确吗? 我们能否通过更短的提示达到相同的准确性? 我们能否在不牺牲准确性的情况下使用更快或更高效的模型?
- 我们计划记录模型滥用的任何途径,以及缓解策略。
- 从长远来看,我们还将微调大量 SQL 查询和翻译的模型。
原文链接:Making a Production LLM Prompt for Text-to-SQL Translation
BimAnt翻译整理,转载请标明出处