SQL 的演变
原文towardsdatascience.com/the-evolution-of-sql-8d017ce566ff在这篇文章中我将探讨大型语言模型LLM如何将自然语言转换为 SQL使查询编写对非技术用户更加容易。讨论将包括展示开发 LLM 解决方案简便性的实际示例。我们还将涵盖各种用例并通过创建一个简单的 Slack 应用程序来展示这个过程。构建一个由 AI 驱动的数据库查询系统涉及几个关键考虑因素包括保持安全性、确保数据相关性、管理错误以及正确训练 AI。在这个故事中我探讨了应对这些挑战的最快方法并分享了一些设置稳固和高效文本到 SQL 查询系统的技巧。最近很难想到有任何技术比大型语言模型更具影响力和更广泛讨论。基于 LLM 的应用现在是最新趋势就像曾经充斥市场的苹果或安卓应用激增一样。它在 BI 领域无处不在我之前在这里写过关于它[1]的内容。分析中的人工智能创建一个 AI 驱动的数据库查询系统是一项复杂的任务。你需要处理许多重要因素如保持安全、确保数据的相关性、处理错误以及正确训练 AI。在这个故事中我探讨了应对这些挑战的最快方法。例如我用了 15 分钟在我的旧仓库模板和 AWS Lambda 函数的基础上构建了这个 AI 聊天机器人https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/de0443ef8e777cf1ca536ce29235662e.png图像由作者提供文本到 SQL可靠性及 RAGs一般而言简单的文本到 SQL 模型绝对不可靠这是我在过去看到的 AI 开发者最常见的抱怨它看起来是对的但在现实生活中这个 SQL 是完全无意义的。如果我们与一个生成 SQL 查询的 LLM 一起工作如果它能够访问你的数据库的数据定义语言DDL、元数据和一系列精心制作、优化的查询那么它可以显著提高。通过整合这些数据LLM 可以生成不仅更可靠、更安全而且针对特定数据库进行了优化的 SQL 查询。为了提高 SQL 生成的可靠性一个有效的方法是使用检索增强生成RAG。简而言之RAG 允许 LLM 通过引入额外的相关数据来增强其响应。这意味着模型不仅依赖于其预存知识还可以访问额外信息以便更准确地调整其输出以满足你的需求。这种方法有助于确保生成的查询与数据库的实际结构和要求相一致使它们更有效并降低错误的风险。文本到 SQL 模型痛点与局限性为 LLM 提供书面指令和上下文是情境学习的基本示例其中模型根据推理过程中提供的输入推导其输出。然而这种方法有固有的局限性提示敏感性由于 LLM 根据给定的输入预测下一个标记措辞的微小变化可能导致显著不同的响应。LLM 的输出高度依赖于输入的确切措辞。对措辞的敏感性而不是对意义的敏感性可能导致输出不一致。可靠性简单的基于提示的 SQL 生成器通常不适合企业使用因为它们不可靠。LLM 易于生成听起来合理但实际上是虚构的信息。在 SQL 生成中这可能导致看似正确但实际上存在根本缺陷的查询通常创建虚构的表、列或值。它可能看起来正确但在现实生活中它将是完全无意义的。上下文窗口LLM 对输入文本或标记的容量有限受其架构限制。例如ChatGPT 3.5 的标记限制为 4096这可能不足以全面理解包含数百张表和列的大型 SQL 数据库。如何构建 RAG有几个专为基于语言模型的通用应用设计的健壮的 Python 库例如LangChain和LlamaIndex。这些库很棒但还有一些库是专门针对 Text-to-SQL 需求定制的例如 WrenAI 和 Vanna。例如Vanna.ai 提供了一种针对性的方法旨在简化将 LLM 与您的数据库集成的过程提供安全连接和自托管选项。这个工具消除了许多复杂性使得在没有更多通用库开销的情况下更容易利用 LLM 为您的特定应用提供支持。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/cd3083179b3aea8cec5ad7ce3946f455.pngRAG 开发流程。来源Vanna.ai它分为两个步骤使用任何 LLM如下所示在您的数据上训练一个 RAG “模型”。您需要的只是 API 密钥开始提问。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5b91c7e382af62ab2e1fd3a89c72fd09.pngLLM 模型。图片由作者提供https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/50884fe893207abf99e3d90926b7b3e7.png模型训练。图片由作者提供。或者您可以使用预训练的chinookVanna 模型如下所示# create a Python environmentpython3-m venv env source env/bin/activate pip3 install--upgrade pip pip3 install vanna# Run get_sql.pyimportvannaasvnfromvanna.remoteimportVannaDefault# Get your api key from vanna.ai nad replace here:vnVannaDefault(modelchinook,api_keyyour-api-key)vn.connect_to_sqlite(https://vanna.ai/Chinook.sqlite)vn.ask(What are the top 10 artists by sales?)终端输出将是以下内容...LLM Response:SELECT a.ArtistId,a.Name,SUM(il.Quantity)AS TotalSales FROM Artist a JOIN Album al ON a.ArtistIdal.ArtistId JOIN Track t ON al.AlbumIdt.AlbumId JOIN InvoiceLine il ON t.TrackIdil.TrackId GROUP BY a.ArtistId,a.Name ORDER BY TotalSales DESC LIMIT10;Extracted SQL:SELECT a.ArtistId,a.Name,SUM(il.Quantity)AS TotalSales FROM Artist a JOIN Album al ON a.ArtistIdal.ArtistId JOIN Track t ON al.AlbumIdt.AlbumId JOIN InvoiceLine il ON t.TrackIdil.TrackId GROUP BY a.ArtistId,a.Name ORDER BY TotalSales DESC LIMIT10;SELECT a.ArtistId,a.Name,SUM(il.Quantity)AS TotalSales FROM Artist a JOIN Album al ON a.ArtistIdal.ArtistId JOIN Track t ON al.AlbumIdt.AlbumId JOIN InvoiceLine il ON t.TrackIdil.TrackId GROUP BY a.ArtistId,a.Name ORDER BY TotalSales DESC LIMIT10;ArtistId Name TotalSales090Iron Maiden1401150U2107250Metallica91322Led Zeppelin874113Os Paralamas Do Sucesso45558Deep Purple44682Faith No More427149Lost41881Eric Clapton409124R.E.M.39https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7fe2a2ebc3f8e84ae45046e74abdbbed.png图片由作者提供。WrenAI是另一个做类似事情的出色开源工具。它旨在通过将自然语言转换为 SQL 来简化查询数据的过程。WrenAI 与各种数据源兼容包括 DuckDB、MySQL、Microsoft SQL Server 和 BigQuery。此外它支持开放和本地 LLM 推理端点如 OpenAI 的 GPT-3-turbo、GPT-4 以及通过 Ollama 的本地 LLM 服务器。我们可以使用实体关系来训练模型。在这种情况下我们提供更多关于数据库的数据我们的模型变得更加准确https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3cfc3b7a58bb36f644dee5e44d461901.png作者图片这种拖放式 UI 极大地简化并改进了模型训练。在每个关系中您可以编辑、添加或删除模型之间的语义连接使 LLM 能够理解关系是一对一、一对多还是多对多。事实上一旦定义了我们就不必担心我们的SQL 语义。语义层和模型训练在开发一个由 AI 驱动的数据库查询系统时另一个关键的考虑因素是确定 AI 应被授予访问权限的适当表和列。选择这些数据源至关重要因为它直接影响生成的查询的准确性和性能以及整个系统的效率。如我之前提到的提供更多关于您数据库的详细信息对于准确性和可靠性至关重要。数据定义语言DDL捕获数据库的结构方面详细说明如表、列及其相互关系等元素。与标准基于提示的 SQL 引擎相比Vanna 在这个领域表现出色。以下代码演示了如何检索 SQLite 的 DDL 语句。考虑下面的代码片段。它解释了如何连接到您的数据库并训练您的 RAG 模型。在我的情况下它将是 BigQuery# train.py# Connect to BigQueryvn.connect_to_bigquery(project_idmy-project)# The information schema query may need some tweaking depending on your database. This is a good starting point.df_information_schemavn.run_sql(SELECT * FROM INFORMATION_SCHEMA.COLUMNS)# This will break up the information schema into bite-sized chunks that can be referenced by the LLMplanvn.get_training_plan_generic(df_information_schema)plan# If you like the plan, then uncomment this and run it to train# vn.train(planplan)# Training on SQL queries:questionHow many albums did each customer buy?sqlvn.generate_sql(question)display(sql)#Optional if the response by Vanna is exactly as you intend, you can add in the training datavn.train(questionquestion,sqlsql)通过使用上面的代码您可以迭代地输入查询并评估其输出。然后您可以选择让 Vanna 从结果中学习或者指定它需要适应的查询。过度加载系统以包含过多的表和列可能会导致标记计数增加、成本上升以及由于语言模型混淆或关键细节丢失的风险从而可能降低准确性。相反数据访问不足限制了 AI 生成精确和有效查询的能力。这就是为什么这种方法非常有用的原因。需要考虑以下几点数据质量和一致性选择维护良好、持续更新的数据。不一致或不完整的数据可能导致结果不准确并损害用户信任。安全和 PII确保敏感数据得到保护。实施数据掩码或标记化等措施在允许 AI 访问相关数据的同时保护机密信息。与用户的关联性选择与用户可能提出的问题最相关的表和列。这确保 AI 拥有生成准确和有用查询所需的数据。SQL 查询性能大型或复杂的表可能会降低 AI 的查询性能。选择已索引和优化的表和列以保持高效的查询生成和执行。维护交互历史这是在 LLM大型语言模型开发中另一个常见的痛点。与常见的误解不同LLM 不会从单个查询中记住或学习你的特定数据或系统除非它们明确地用这些信息进行训练。对未经过训练的 LLM 的每一次请求都是基于其最新的训练数据进行处理的而不是基于之前的用户交互。为了生成准确的查询向 LLM 提供每次请求的聊天历史是必不可少的。这应该包括有关你的模式和示例查询的相关细节确保 LLM 可以生成针对你的数据的精确查询。训练一个由 AI 驱动的查询系统涉及一个迭代的过程不断进行精炼和增强。文本到 SQL 开发最佳实践在 AI 驱动的数据库查询中文本到 SQL 的一个主要担忧是数据库意外修改的风险。为了解决这个问题实施确保 AI 不会更改底层数据的措施至关重要。确保你的生成的 SQL 经过验证在执行之前引入一个查询验证层该层会审查 AI 生成的查询。这一层应该过滤掉任何可能修改数据库的命令如 INSERT、UPDATE、DROP 等。在处理之前验证查询可以防止对数据库进行意外的更改。AI 服务访问权限确保 AI 系统只被授予对数据库的只读访问权限。这种限制可以防止对数据进行任何意外或恶意的更改同时仍然允许 AI 生成用于数据检索的查询从而保持数据库的完整性。监控 SQL 查询性能关注使用情况和查询性能指标总是一个好主意。关注洞察AI 生成的 SQL 查询在数据检索方面非常出色但它们的真正潜力在于与高级数据分析相结合。通过将这些查询与分析工具和工作流程集成你可以发现更深入的见解并做出更明智、基于数据的决策。自定义错误处理即使经过细致的模型训练和你的文本到 SQL 系统的优化仍然可能存在生成的查询包含解析错误或没有结果的情况。因此在这些情况下实施一个机制来重试查询生成并向用户提供建设性反馈至关重要。这将增强你的文本到 SQL 模型的有效性和弹性并改善用户体验。通过整合这些验证机制你可以确保 AI 生成的查询既安全又可靠降低意外修改数据库的风险并避免常见的查询相关问题。这种方法不仅节省了时间和资源还促进了以数据为驱动的文化其中决策基于准确和最新的洞察。制定这些政策后您的组织可以有效地利用其数据的全部潜力让非技术用户能够自行访问和分析信息。构建一个基于 AI 的 Slack 机器人助手为了做到这一点我们需要我们的 OpenAI API 密钥、Slack 账户和 AWS 账户来部署带有 Lambda 函数的无服务器 API。高级应用程序逻辑Slack 应用程序将向我们的 API 发送文本消息我们在 AWS 部署的无服务器 API 将向 AWS Lambda 发送 Slack 消息AWS Lambda 将向 OpenAI API 请求响应并将其发送回 Slack前往Slack 应用并创建一个新的应用程序api.slack.com/appshttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6fba22201be19fd3ae0ad28857dcabd3.png图片由作者提供点击“从头开始”并给它起个名字https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/96176e9a168dc3f9bfacda3e0ad4eb23.png图片由作者提供接下来让我们添加一个命令行来触发我们的机器人https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3b1afe4716e8eee8e8a8b9093805288e.png图片由作者提供在编辑命令部分提供我们的无服务器 API 端点请求 URLhttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b7c68093259fa9d84fe083b8c9fdc0a7.png图片由作者提供最后让我们将其安装到我们的 Slack 工作空间中https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e16cc01b7bddd9762bd3ae2952052d25.png图片由作者提供让我们创建一个微服务来处理我们的机器人接收到的 Slack 消息。如果用 Node.js 编写我们的 AWS Lambda 应用程序代码可能看起来像这样# app.jsconst AWSrequire(aws-sdk);AWS.config.update({region:eu-west-1});const axiosrequire(axios);const OPENAI_API_KEYprocess.env.openApiKey||OpenAI API key;exports.handlerasync(event,context){console.log(app.handler invoked with event JSON.stringify(event,null,2));try{context.succeed(awaitprocessEvent(event));}catch(e){console.log(Error: JSON.stringify(e));context.done(e)}};let processEventasync(event){/***Adding command parser fro Slack commands*/function commandParser(slashCommand){lethash;let myJson{};let hashesslashCommand.slice(slashCommand.indexOf(?)1).split(amp;);for(let i0;ihashes.length;i){hashhashes[i].split();myJson[hash[0]]hash[1];}myJson.timestampDate.now();returnmyJson;};try{let channel_idcommandParser(event.body).channel_id;let user_namecommandParser(event.body).user_name;let txtcommandParser(event.body).text;//Get response:let messageawaitprocessMessageText(txt,user_name,channel_id);return{statusCode:200,headers:{},body:JSON.stringify(message),isBase64Encoded:false};}catch(err){console.log(Error handling event,err);return{statusCode:500,headers:{},body:{},isBase64Encoded:false};}};const processMessageTextasync(txt,user_name,channel_id){let ResponseawaitfetchAi(txt);let message{response_type:in_channel,text:${user_name},${Response}};returnmessage;};const fetchAiasync(prompt){try{const responseawaitaxios.post(https://api.openai.com/v1/chat/completions,{model:gpt-3.5-turbo,messages:[{role:user,content:prompt}],max_tokens:150,temperature:0.7,},{headers:{Authorization:Bearer ${OPENAI_API_KEY},Content-Type:application/json,},});const generatedTextresponse.data.choices[0].message.content;returngeneratedText;}catch(e){return[{NOW:You are unable to get a response atm.}];}};使用 AWS Cloudformation 或 Terraform 部署我们的 API 和无服务器应用程序我们即可随时出发https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a669d00d1a256e36747c8524f1e8add6.pngAI Slack 机器人。图片由作者提供。在我之前的一篇文章中我讨论了使用基础设施即代码部署应用程序的好处[2]。基础设施即代码入门结论最近很难想到有任何技术比大型语言模型更具影响力和更广泛讨论的。基于 LLM 的应用现在是最新趋势就像曾经充斥市场的苹果或安卓应用激增一样。使用 DDL 语句、自定义查询、元数据或文档来细化定义简化了 LLM 开发的过程。例如如果你的业务使用自定义指标提供这些额外的上下文将有助于它生成更准确和相关的输出。构建一个由人工智能驱动的数据库查询系统并非易事。你需要处理许多重要因素如确保安全性、确保数据的相关性、处理错误以及正确训练人工智能。训练一个由人工智能驱动的查询系统涉及一个反复的优化和改进过程。通过开发一个全面的参考指南、提供多样化的示例查询以及有效地管理上下文窗口你可以构建一个强大的系统使用户能够快速准确地检索数据。在这个故事中我探讨了应对这些挑战的最快方法并分享了一些设置稳固高效的人工智能查询系统的技巧。推荐阅读[1]medium.com/towards-data-science/artificial-intelligence-in-analytics-f11d2deafdf0[2]medium.com/gitconnected/infrastructure-as-code-for-beginners-a4e36c805316[3]platform.openai.com/docs/quickstart?contextnode[4]github.com/openai/openai-node/raw/master/examples[5]api.slack.com/legacy/enabling-bot-users