DLAI-你自己的数据库智能体构建笔记-全-

DLAI 你自己的数据库智能体构建笔记(全)

001:课程介绍 🚀

在本课程中,我们将学习如何让大型语言模型与表格数据或SQL数据库等结构化数据进行交互。这对于构建一个能利用数据源(而非依赖分析师将问题翻译成SQL查询)来回答问题的系统非常有用。我们将了解数据库智能体如何自动接收问题,并生成一系列动作(即函数调用)来检索相关数据。

具体来说,在本课程中,你将学习如何构建自己的AI智能体来与表格数据和SQL数据库交互。在此过程中,你将了解构建智能体的一些关键模块,并使用LangChain智能体框架。

课程讲师与内容概览 👨‍🏫

本课程由微软数据与AI专家、大学讲师、《Azure OpenAI O‘Reilly》书籍作者Ad Gonzalez Sanchez担任讲师。

课程将涵盖以下核心内容:

  • 学习如何部署LLM来构建你的AI智能体。
  • 实现针对表格数据的检索增强生成。
  • 开发你自己的数据库智能体。
  • 构建一个函数调用系统。
  • 集成Azure OpenAI助手API。

我们将使用Azure OpenAI服务和LangChain来实践这些概念。虽然课程以数据库智能体为例,但这些组件对于构建任何其他类型的智能体同样有用。

数据库智能体的意义与前景 💡

数据库智能体是我们分析数据方式的一次激动人心的突破。它让人们无需学习SQL等查询语言,就能与复杂数据交互。这意味着你可以让一个语言模型为你向数据库发出请求,无论数据库提供商、数据模型或类型语言如何。

核心概念:使用LLM作为数据库之上的抽象层,是许多公司内部实现数据民主化的新前沿之一。你可以将这一技术应用于你所在的公司或你正在开发的应用中。

此外,智能体是生成式AI中一个快速增长的类别。在本课程中,你还将学习智能体的关键组件,以及将这些组件组装成更广泛系统的最佳实践。

课程启动 🎬

在接下来的第一课中,你将开始使用Azure OpenAI服务构建你的第一个AI智能体。

上一节我们介绍了课程的整体目标和内容,本节中我们来看看如何开始实践。

让我们进入下一个视频,正式开始学习。

002:你的第一个AI智能体 🚀

在本节课中,我们将学习如何利用Azure OpenAI的不同知识定制层级。我们将主要聚焦于基础技术,特别是检索增强生成,来开始构建你的第一个AI智能体。课程结束时,你将能够部署Azure OpenAI服务实例并测试其API,同时部署一个编排引擎和LangChain来支持这些应用场景。


背景知识:生成式AI简介

在深入实践之前,让我们快速了解一些背景知识,为后续讨论设定上下文。这部分内容会很简短,我们很快会进入代码环节。

生成式AI,尤其是在2020年代,指的是人工智能创造新文本、图像、视频等内容的能力。这是通过与AI系统使用自然语言提示进行交互来实现的。虽然这项技术并非全新,但该领域有许多新兴技术值得你关注。

你将接触到包括仍在开发中的新模型在内的前沿技术。因此,我们需要依赖不同供应商的官方文档。此外,请记住,生成式AI建立在机器学习和深度学习的基础之上。这些都是强大的技术,但我们在此的主要焦点是生成式AI。

在我看来,生成式AI的关键区别点非常显著。如果要解释什么是生成式AI,我会强调基础模型的概念。

为什么?因为一个基础模型可以通过单一设置执行多项任务。这意味着,当你构建AI智能体时,你可以将其连接到数据库、处理文档或创建各种应用程序,所有这些都使用同一个模型。这种简单性对公司来说是一个显著优势,因为部署一个模型来处理不同任务非常高效。

此外,基础模型可以处理各种数据格式,包括文本、图像、视频和音频。这种多功能性非常适合多模态应用。另一个关键方面是使用自然语言的能力。作为开发者,我们只是写代码,但对大多数人来说,使用自然语言与系统交互要直观得多。无论是英语、西班牙语还是其他语言,人们现在都可以自然地与这些系统交流。

在本课程结束时,你将构建一个数据库智能体。这很令人兴奋,因为它意味着用户可以用自然语言与应用程序交互,而不是使用SQL查询。这为更广泛的受众(包括技术和业务用户)打开了这些解决方案的大门。这些是本节课以及你将创建的任何其他生成式AI应用需要牢记的基本特性。


知识定制:检索增强生成 vs. 模型微调

现在,让我们讨论如何定制大型语言模型的知识。这里的“定制”指的是将你的额外知识集成到LLM中。想象一下,你的公司拥有数据库、数据湖或私有信息,你如何将这些数据结合起来以增强模型(例如GPT-4)的知识呢?

我们有两个主要选项。

第一个选项是检索增强生成。这种方法利用编排工具将模型与你的数据源(如数据库)连接起来,而无需进行模型训练。例如,Azure OpenAI GPT-4可以直接用于查询你的数据库,而无需更改模型本身。这种方法更高效、更实用,并且避免了与模型训练相关的开销。

第二个选项是模型微调。这个过程涉及在特定数据上重新训练模型,然后重新部署更新后的模型。虽然这允许定制,但它资源密集,并且由于复杂性和运营成本,较少被采用。

RAG的主要优势在于其灵活性。未来的模型更新或替换可以无缝集成到现有设置中,使用相同的连接机制来访问你的数据。本课程将采用这种方法。请思考它如何简化新模型的集成并优化你现有数据基础设施的使用。


环境设置与资源部署

我们将从在环境中设置必要的包开始,例如 pandas

如果你在本地运行,需要使用 requirements.txt 文件安装所需的包,该文件包含了本课程的所有依赖项。你可以在本节课的当前目录中找到这个文件。详细的类型化说明将在课程的Notebook中提供。

接下来,你需要设置实际的资源,例如Azure OpenAI。

首先,提供配置Azure OpenAI环境所需的信息。如果你以前使用过OpenAI API,这会很熟悉。虽然有一些差异,但你会很快掌握。以下是需要的变量:API端点API密钥。这是一个预创建的云资源,将为你提供对Azure OpenAI GPT模型的访问权限。

注意:此处提供的API密钥和端点仅用于教学目的。使用深度学习AI平台的Notebook环境已设置好所需的密钥。

现在,让我们考虑下一步。我将在这里添加信息,然后运行它。我们会看到我们正在运行非常小的代码片段。在这种情况下,我们说的是:我们从 langchain.schema 导入一个叫做 HumanMessage 的东西,然后从 langchain 导入 AzureChatOpenAI。这很有趣,因为我们将使用 HumanMessage 的角色,这是一种你将发送到系统的提示。所以我们需要LangChain编排系统来识别你正在发送一条消息,然后我们需要建立一些东西来从LangChain连接到Azure OpenAI,这与连接到OpenAI略有不同。

在这里,我们说的是:我们拥有关于Azure OpenAI的信息,我们有API版本(我相信在此时是最新的稳定版本,不是预览版。这显然会改变,你可以尝试不同的版本,只需更改日期,参考不同的API版本)。然后你有了部署名称和端点。同样,这是因为我的配置包含一个名为“Adrian Sua”的端点,而我为此单一目的将部署名称称为“test-address”。但通常你会放一个更具体的部署名称,与你正在创建的内容相关。

到目前为止,我们已经有了通用环境,添加了端点,并准备好了连接。LangChain的三个步骤非常简单直接。现在下一步是什么?


创建并发送你的第一个提示

还记得我告诉过你关于 HumanMessage 的部分吗?在这里你可以看到它:HumanMessage,这是为了让系统识别你正在以“人类”身份发送消息。让我们尝试类似这样的操作:我们创建一个消息,在这个消息内部,内容是:“translate this sentence from English to French and Spanish: I like red cars and blue houses but my dog is yellow”。我测试这个是因为它是一个任意的句子,但看看系统如何回答也很有趣。记住,我们刚刚创建了实例,还没有发送消息,但你已经把它放在那里了。

为了发送它,非常简单:我们将在这里使用 model.invokeinvoke 函数是现在起作用的函数。记住,model 与我们创建的、作为 AzureChatOpenAI 对象的这个模型相关。让我们看看发生了什么。

好的,我们开始看到结果了。检查这个:我们在这里讨论了 HumanMessage,我们得到了 AIMessage。当你考虑与这些模型的交互时,我们有不同种类的角色:人类、智能体、管理员。在这种情况下,我们专注于人类和AI的交互。我们发送了一条人类消息,得到了AI消息,内容是你要求的法语和西班牙语翻译。法语我可以告诉你(我讲法语),我可以告诉你这行得通。西班牙语甚至更好,因为我讲西班牙语:“Me gustan los coches rojos y las casas azules, pero mi perro es amarillo.” 完美!

我们在这里得到了完整的内容。这行得通。我们告诉系统“将这个句子翻译成法语和西班牙语”,它给了我两种语言的翻译。花几分钟回顾代码,尝试一下,改变你的提示,进行一些实验。


总结 🎉

恭喜你,你已经完成了第一课!在本节课中,我们一起学习了:

  1. 生成式AI与基础模型:了解了生成式AI创造内容的能力,以及基础模型如何通过单一设置执行多任务,并处理多种数据格式。
  2. 知识定制方法:对比了检索增强生成模型微调两种方法,明确了RAG在灵活性、效率和成本上的优势,并确定本课程将采用RAG方案。
  3. 环境搭建:学习了如何设置Python环境、安装依赖,并配置连接Azure OpenAI服务所需的关键参数(API端点、密钥、版本和部署名称)。
  4. 第一个AI交互:使用LangChain框架,通过创建 HumanMessage 并调用 model.invoke,成功向Azure OpenAI模型发送了第一个自然语言提示(翻译任务),并收到了正确的多语言回复。

你现在已经成功部署了Azure OpenAI服务,并通过LangChain编排引擎与之进行了首次交互,迈出了构建AI智能体的第一步。在接下来的课程中,我们将在此基础上,深入探索如何将智能体连接到数据库,实现更复杂的问答和操作功能。

003:与CSV数据交互 📊

在本节课中,我们将学习如何从CSV文件加载表格数据,并通过Azure OpenAI执行自然语言查询来快速提取信息。课程结束时,你将能够运用这个智能体来分析你自己的CSV文件。

概述

上一节我们连接了Azure OpenAI并实现了一个基础的LLM智能体。本节中,我们将扩展活动范围,目标是构建一个数据库智能体。我们无法一次性实现所有功能,因此需要逐步添加新组件。既然要构建数据库智能体,我们需要思考如何连接数据。例如,在Python中,你可以从CSV文件加载数据,然后通过提问与数据交互。这类似于数据库智能体,但本节课我们尚未连接到实际数据库,而是与CSV数据集交互。

在深入细节之前,我们先了解一些基本概念。我希望你理解构建数据库智能体时的考虑因素和可用选项。想象你在公司工作,他们问:“我们如何构建一个连接到数据库的智能体?”许多公司希望使用SQL来探索数据库,但并非所有人都熟悉它。作为软件开发工程师,你需要决定一个好的方法。

我们拥有基线模型GPT-4,其强大的元编程能力在语言上能很好地处理SQL任务。你可以使用微调方法来定制模型,一些公司正在尝试这种方法。为特定SQL任务微调模型可以创造有价值的智力资产,但对于本课程的目的来说可能过于复杂。相反,我们将使用检索增强生成模式,将数据库或数据集作为来源。

我们将重点使用CSV文件作为数据源,并使用LangChain智能体连接到该CSV文件。这个方法简单直接,是我们的起点。下一课将把相同的方法应用到SQL数据库。如果你的SQL数据库有API接口,你可以使用RAG连接到它。我们这里不涉及这一点,但请记住以供未来项目参考。

另一个选项是Azure OpenAI的函数调用功能,它允许你根据描述创建特定函数来执行任务。这对于SQL任务非常有用,它让你可以在后端执行SQL查询,而无需直接在代码中暴露它们。此外,还有助手API,这是Azure OpenAI和OpenAI API中的一个功能,它增加了状态管理,为讨论提供短期记忆和上下文。我们将使用函数调用和代码解释器功能,我将在本课后面解释。本节课我们专注于使用CSV文件,但在本课程中,我们将逐步探索所有这些选项。

让我们继续到Notebook。

环境准备

现在,我们像在第一课中那样进行。对于每一课,我们都会准备环境。请记住,你在Deep Learning AI平台上的Jupyter Notebook已经为你设置好了所有需要的环境。我们将重复上一课中的一些步骤,例如导入必要的库、为LLM设置Azure OpenAI以及定义端点和版本。

现在,进入有趣的部分:与CSV数据集交互。请记住,你可以使用自己的数据集。例如,你可以从开放数据门户下载CSV文件并将其放在项目文件夹中,或者你可以远程连接到数据集。你可以在Notebook中找到一些关于如何远程访问我们在此使用的数据的说明。为简单起见,数据可在你的课程和数据文件夹中找到,名为all_states_history.csv。该数据包含2020年和2021年美国各州的COVID-19统计数据。

让我们继续这个设置并探索数据。

创建Pandas DataFrame智能体

基本上,我们正在导入或创建与LangChain相关的所有信息,并连接到Pandas DataFrame。这样,你不仅可以连接到我们之前完成的Azure OpenAI,还可以连接到DataFrame。重要的是,我们正在创建一个所谓的LangChain智能体,具体来说是一个Pandas DataFrame智能体。这意味着我们将使用之前创建的LLM模型,并利用已经包含CSV文件表示的DataFrame。

那么,我们如何对此执行任何操作呢?我们使用提示词。你可以看到,invoke函数与我们之前使用的相同,非常简单。但在这里,我们会输入诸如“有多少行”这样的问题。请记住大局:如果你在数据科学、人工智能或数据分析的背景下与CSV文件交互,通常从探索性数据分析开始,对吧?你向数据提问:最大值、最小值、平均值是多少,有多少行,有多少空值?这就是我们使用像pandas profiling这样的工具所做的事情。在这里,我希望你只是向数据提问,任何你想问的问题,以理解统计维度和自然数据。

让我们从这个开始,看看它是如何工作的。我已经为DataFrame执行了这部分代码。查看跟踪信息非常有趣,可以看到这种交互:进入新的智能体执行链,进行观察,检查信息,添加思考,现在知道最终答案,最终答案是:有20780行。“完成链”是你需要检查与智能体任何交互的跟踪信息。这里我们有输入(记住我们之前问的问题)和输出:有X行。就这么简单。

这是初始测试,我们创建了一个非常基础的东西,只是询问行数。但显然,当我们与这些模型交互时,我们会做一些更完整的事情。让我给你一个例子。

使用前缀和后缀增强交互

我将向你展示如何创建我们称之为前缀和后缀的东西。基本上,在前缀中,我们设置一些初始指令,例如“首先显示所有列”,以便获取列名,然后回答问题。在后缀中,我们解释与模型交互的逻辑,例如“在给出最终答案之前,尝试另一种方法,反思答案,引用来源”。你可以自定义这一点,其魔力在于,你可以根据你希望模型如何交互以及应用程序的类型准备不同类型的前缀和后缀,其中包含不同的文本。这只是纯语言文本,你只是希望模型理解事物。

如果我在这里执行,我们会重新加载它。让我问另一个问题。现在记住,我们有前缀、后缀和问题。我会做一些更复杂的事情,比如“2020年7月德克萨斯州有多少患者住院?全国所有州的总数是多少?”我们可以执行它,我们有三个文本片段:前缀、问题和后缀。之前我们发送的指令非常直接,只是这个指令。但现在我们正在构建更复杂的东西,但遵循相同的程序,我们只是将它们批量组合在一起,所以模型将获得指令、消息,然后是我们希望它如何行为的确认。

你可以根据需要添加任何你认为合适的内容到后缀中,这只是一个说明性的例子。让我运行它,别忘了运行它。再次,我们得到了相同类型的性能表现。我们正在进入智能体执行链,这很酷。智能体正在思考:“嘿,我需要为2020年7月过滤DataFrame,然后汇总所有住院增加的信息。”看,我需要导入pandas,或者我可以继续。智能体正在做所有这些事情。所以基本上,即使你看到很多信息,它也在说:“好的,我们正在查找日期,因为记住是2020年7月。我们需要找到与德克萨斯州相关的信息。”你会得到所有信息,并开始看到一些细节,需要花些时间分析信息。

但这里重要的是,思考过程是:根据此信息,似乎2020年7月德克萨斯州没有住院报告。从跟踪信息中我们可以看到,德克萨斯州是0,但其他州的总数是63,000。为什么?从数据分析的角度来看,你可能会问一个问题:我们是否在那一年在德克萨斯州或其他州跟踪了结果?也许这就是我们没有任何记录的原因。但我可以告诉你,从CSV文件来看,这是正确的信息。所以基本上,如果我们进入最终部分,那是有趣的部分,因为它包含了所有信息。我们确认CSV文件中没有跟踪到住院情况。显然,我假设有一些住院情况,但在2020年7月,这似乎不寻常,但必须根据给定的数据来判断。

看,智能体已经在思考或分析我给出的一些上下文信息。它说:“好的,对于德克萨斯州是0,但总数是63,000。”然后你得到了解释,因为记住在顶部,我们要求了一些推理和解释。所以在这里,我们得到了解释,说:“我通过转换数据得出了这个答案”,它解释了查询的逻辑。这太棒了。再次,花时间探索这些步骤,因为它包含大量信息,但非常好。

现在,你看到了最终答案。基本上,你拥有所有相同的信息,你拥有这里的一切,你可以使用它。它给了我很好的可解释性,很酷。根据你给出的指令,你得到了所有需要的信息。你可以用不同的前缀、后缀和问题再试一次。显然,你可以修改问题。我建议你更改并输入纽约、加利福尼亚或阿拉巴马州,然后开始看到根据州的不同结果,你也可以更改日期,这非常酷。

总结

本节课中,我们一起学习了如何加载CSV数据并创建一个Pandas DataFrame智能体。我们通过自然语言与数据进行交互,执行了从简单的行数查询到复杂的、涉及特定时间和地点数据筛选的提问。我们还探讨了如何使用前缀和后缀来引导智能体的行为,使其在回答时提供推理和解释。这种方法为你分析自己的CSV文件提供了一个强大而灵活的工具。在下一课中,我们将把相同的概念应用到SQL数据库上。

004:连接SQL数据库

概述

在本节课中,我们将学习如何构建一个能够连接并查询SQL数据库的智能体。这是对上一节课内容的自然演进。你将实现一个LangChain智能体,连接到提供的SQLite数据库,并对其执行RAG(检索增强生成)模式。最终结果是一个数据库智能体,其中生成式AI将帮助你将自然语言翻译成SQL代码

架构与准备工作

上一节我们介绍了如何连接CSV文件,本节中我们来看看如何连接SQL数据库。

构建AI智能体时,我们将依赖Azure OpenAI的基线GPT-4模型,并使用LangChain系统进行编排。LangChain将帮助查找信息并解释获取信息的每一步。与第二课类似,你将看到包含详细信息的跟踪记录,这种方法功能强大且实用,因此我们将继续沿用。这次我们将使用SQL数据库,它是一个开源关系数据库的本地实例。你可以在notebook中找到所有必要信息。当然,我们通过API访问一切。虽然本课程使用notebook,但在实际应用中,你可以将结果集成到Web应用、移动应用或其他任何平台,过程是相同的。

我们将用SQL数据库替换CSV文件。你可以组合不同的数据源,如图像、数据湖和数据库。RAG机制将有效地从这些数据源中定位信息。

让我们进入notebook并开始操作。我们再次启动环境,这次将加入一个SQL数据库。主要区别在于我们现在需要与SQL数据库通信。因此,你将看到这是与之前相比的主要变化,而其余部分则非常相似。

加载数据到SQL数据库

我们将从恢复之前使用的CSV数据开始。目的是将CSV文件加载到SQL数据库中,然后与数据库通信。如果你的信息已经存在于SQL数据库中,则无需加载该CSV文件,此步骤仅为本课程演示。

数据位于你的课程目录中,文件名为all-states-history.csv。我们将创建一个SQLAlchemy引擎来促进与SQL数据库的通信,并使用pandas处理数据框。

以下是连接SQL数据库并加载数据的步骤:

  1. 创建数据库连接:我们有一个名为db的本地文件夹,其中包含test.db文件。这是你将使用的SQLite数据库文件模板。你可以将其放在那里,然后你就拥有了该SQL数据库的本地实例。
  2. 创建引擎:我们创建引擎来连接到数据库。
  3. 读取CSV文件:从你的数据文件夹中恢复CSV文件,并使用pandas创建数据框df
  4. 加载到数据库:这是与第二课的关键区别。我们获取数据框,并使用to_sql函数。这意味着我们将all_states_history数据加载到之前提到的SQL引擎中。如果表已存在,我们将替换它(非增量更新)。

运行这些步骤后,系统会告诉你已加载了多少条记录到SQL数据库中。

构建SQL智能体

现在,我们来构建第一个SQL智能体。这类智能体将在后续课程中逐步演进,但这是你第一次真正与SQL数据库交互。

我们需要设置一些信息,这些信息在你的notebook中已提供。主要包括两部分:

  1. SQL智能体前缀:我们创建了一个称为SQL智能体前缀的内容,用于解释我们想要做什么。你是一个决定与SQL数据库交互的智能体,因此需要提供一些上下文。与之前的CSV文件不同,现在我们说:你正在连接SQL,并将运行SQL查询。你可以更改此内容,但这是一个可以借鉴的良好初始模板。
  2. 格式说明:你拥有希望引擎如何回答的格式说明,例如包含ActionInputObservationThoughtFinal Answer。你之前见过这种格式。这里你提供的是一个示例,目的是让模型理解你作为用户期望得到何种答案、格式以及信息,同时还包括SQL查询的跟踪记录。这非常强大,我们将能够用自然语言与SQL数据库通信,同时还能获得关于查询的信息。这对于公司内部的学习案例很有好处,例如人们不仅想使用数据,还想学习如何执行SQL查询。

接下来是第二部分,它与我们之前遵循的步骤序列非常相似。基本上,我们在这里创建LLM(Azure Chat OpenAI实例)、数据库工具包,以便将LLM和数据库结合起来。然后我们提出问题,例如:“2020年10月,纽约州和全国有多少患者住院?” 我们正在创建agent_executor_sql,基本上就是那个智能体,一个具有特定格式的LangChain智能体,它期望接收我们发送的前缀和格式说明。当然,我们需要知道正在使用哪个LLM(即具有该端点的Azure OpenAI版本)以及正在使用哪个工具包(SQL数据库工具包)。我们将执行此操作并观察结果。

执行查询与查看结果

即使我不告诉你需要向系统发送什么函数来发送提示,你也应该记得第一课和第二课的内容。没错,就是invoke函数。我们拥有agent_executor_sql(与上一课不同),然后我们发送问题。

执行后,这将需要一些时间。你将获得大量信息,所有的跟踪记录。你可以花时间分析相同之处。有趣的部分从这里开始,因为它解释了结果。这里的查询不同,我们谈论的是2020年10月纽约州的住院情况。引擎正在查找信息的位置、哪些列、哪些值。你已经可以看到SELECTFROMLIKEWHERE等所有需要执行的查询,但现在这些都由智能体自动完成。

让我们看看答案。Final Answer是问题的简洁版本。这里你有“有多少患者住院”,然后在输出中:“2020年10月,纽约州没有新的住院病例,全国约有53例新的住院病例”。你可以根据之前的CSV文件去探索并确认引擎提供了正确的答案。我可以确认这是正确答案,因为我之前已经检查过信息。

总结

本节课中,我们一起学习了如何构建一个连接SQL数据库的智能体。我们了解了如何将CSV数据加载到SQLite数据库,如何设置SQL智能体的前缀和响应格式,以及如何通过自然语言提问并自动生成和执行SQL查询。你看到了智能体如何提供详细的查询跟踪和最终答案。这为在实际工作中利用生成式AI与结构化数据库交互奠定了坚实基础。

005:Azure OpenAI 函数调用功能 🛠️

在本节课中,我们将学习 Azure OpenAI 的函数调用功能。我们将了解如何利用此功能来改进 SQL 智能体的设计,使其能够更精确、更可控地执行数据库查询,而无需在翻译过程中暴露 SQL 语句。

概述

上一节我们介绍了使用 LangChain 连接 CSV 文件和 SQL 数据库。本节中,我们来看看 Azure OpenAI 模型的一项新能力:函数调用功能。你可能会想,如果我们的智能体已经运行良好并能正确获取信息,为什么还需要这个功能?函数调用的主要价值在于,它能让我们为系统或智能体提供明确的指令,以从特定主题中查找信息。这包括建议要生成的查询类型,并以你需要的格式获取搜索结果。这种方法为智能体增加了一层确定性行为,允许你更精确地控制整个过程。

函数调用的核心概念

与之前基于 LangChain 的智能体方法不同,函数调用将查询封装在函数内部,提供了更多的结构和可预测性。其核心思想是利用预定义的函数将查询发送到数据库,而无需将 SQL 查询暴露在翻译过程中。

以下是其工作原理的简化流程:

  1. 定义工具(函数):创建一系列函数,每个函数对应一种特定的查询意图(例如,获取某州的住院人数)。
  2. 描述工具:将这些函数的描述(名称、用途、所需参数)提供给 AI 模型。
  3. 用户提问:用户用自然语言提出问题。
  4. 模型选择工具:AI 模型根据问题意图,自动选择合适的函数并准备调用参数。
  5. 执行函数:系统执行被选中的函数,该函数内部包含执行 SQL 查询的逻辑。
  6. 返回结果:函数执行结果返回给 AI 模型,由模型整理成自然语言答案回复给用户。

从简单示例开始

为了理解函数调用的机制,我们先从一个与天气相关的简单函数开始。以下是创建和测试一个简单天气查询函数的步骤。

首先,我们需要设置 Azure OpenAI 端点,使用的预览版模型包含了我们将要使用的函数调用功能。

# 示例:设置 Azure OpenAI(关键信息已用占位符替代)
openai.api_type = "azure"
openai.api_base = "你的 Azure OpenAI 端点"
openai.api_version = "预览版 API 版本"
openai.api_key = "你的 API 密钥"

接下来,我们定义一个简单的函数。这个函数模拟获取指定城市的当前天气。

def get_current_weather(location: str):
    """
    获取指定城市的当前天气。
    参数:
        location (str): 城市名称,例如 "San Francisco"。
    返回:
        str: 该城市的模拟天气信息。
    """
    # 这是一个模拟函数,实际应用中会调用天气API
    weather_data = {
        "San Francisco": "晴朗,20摄氏度",
        "New York": "多云,15摄氏度",
        "Las Vegas": "晴朗,25摄氏度"
    }
    return f"{location}的天气是:{weather_data.get(location, '信息暂不可用')}"

现在,我们教导 AI 系统如何使用这个函数。我们创建一个包含用户消息和工具描述的消息列表。

messages = [
    {"role": "user", "content": "旧金山、纽约和拉斯维加斯的天气怎么样?"}
]

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "获取指定城市的当前天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "城市名称,例如 San Francisco",
                    }
                },
                "required": ["location"],
            },
        },
    }
]

然后,我们进行第一次 API 调用。这次调用的目的是让模型根据用户问题,决定需要调用哪些函数以及传入什么参数。

response = openai.ChatCompletion.create(
    engine="你的部署名称",
    messages=messages,
    tools=tools,
    tool_choice="auto", # 让模型自动选择工具
)

模型会返回一个响应,其中包含它计划进行的“工具调用”。在这个例子中,由于我们问了三个城市,模型可能会决定调用三次 get_current_weather 函数,每次传入不同的城市参数。但这只是第一步,我们还没有得到实际的天气答案。

为了获得最终答案,我们需要执行模型指定的函数调用,并将结果返回给模型进行总结。以下是第二步:

# 1. 解析模型返回的工具调用请求
tool_calls = response.choices[0].message.get(“tool_calls”)
if tool_calls:
    # 2. 准备一个列表来存放所有函数执行结果
    all_results = []
    for tool_call in tool_calls:
        function_name = tool_call.function.name
        function_args = json.loads(tool_call.function.arguments)
        # 3. 根据函数名找到对应的函数并执行
        if function_name == “get_current_weather”:
            function_response = get_current_weather(**function_args)
            all_results.append(function_response)
    # 4. 将函数执行结果作为新的消息附加到对话历史中
    messages.append(response.choices[0].message) # 添加模型的思考
    for result in all_results:
        messages.append({
            “role”: “tool”,
            “content”: result,
            “tool_call_id”: tool_call.id # 关联对应的工具调用
        })
    # 5. 再次调用模型,让它根据原始问题和函数结果生成最终回答
    second_response = openai.ChatCompletion.create(
        engine=“你的部署名称”,
        messages=messages,
    )
    final_answer = second_response.choices[0].message.content
    print(final_answer)

最终,我们将得到一个如“旧金山天气晴朗,20摄氏度;纽约多云,15摄氏度;拉斯维加斯晴朗,25摄氏度”的自然语言回答。

应用于数据库查询

理解了基础机制后,我们现在将其应用到数据库智能体上。我们将创建与数据库查询相关的函数。

首先,我们像之前课程一样,将数据加载到 SQLite 数据库中。

import pandas as pd
import sqlite3

# 加载 CSV 数据
df = pd.read_csv(“covid_data.csv“)
# 创建内存中的 SQLite 数据库连接
conn = sqlite3.connect(“:memory:“)
# 将 DataFrame 写入数据库
df.to_sql(“covid_stats“, conn, index=False, if_exists=“replace“)

接下来,我们定义两个与数据库交互的函数。一个用于查询住院人数增长,另一个用于查询阳性病例数。

def get_hospitalized_increase(state: str, date: str):
    """
    获取特定州和日期的住院人数增长。
    参数:
        state (str): 州名,例如 ‘Alaska‘。
        date (str): 日期,格式为 ‘YYYY-MM-DD‘,例如 ‘2021-03-05‘。
    返回:
        str: 查询结果。
    """
    query = f“““
        SELECT hospitalized_increase
        FROM covid_stats
        WHERE state = ‘{state}‘ AND date = ‘{date}‘
    “““
    result = pd.read_sql_query(query, conn)
    # 返回格式化的结果
    if not result.empty:
        return f“在{date},{state}州报告的住院人数增长为{result.iloc[0, 0]}人。“
    else:
        return f“未找到{date}在{state}州的住院数据。“

def get_positive_cases(state: str, date: str):
    """
    获取特定州和日期的阳性病例数。
    参数:
        state (str): 州名。
        date (str): 日期,格式为 ‘YYYY-MM-DD‘。
    返回:
        str: 查询结果。
    """
    query = f“““
        SELECT positive_cases
        FROM covid_stats
        WHERE state = ‘{state}‘ AND date = ‘{date}‘
    “““
    result = pd.read_sql_query(query, conn)
    if not result.empty:
        return f“在{date},{state}州报告的阳性病例数为{result.iloc[0, 0]}例。“
    else:
        return f“未找到{date}在{state}州的阳性病例数据。“

现在,我们教导智能体如何根据用户的问题选择正确的函数。我们创建一个用户消息示例和工具描述列表。

# 用户的问题示例
user_message = “2021年3月5日阿拉斯加州的住院人数是多少?“

# 定义可用的工具(函数)
database_tools = [
    {
        “type“: “function“,
        “function“: {
            “name“: “get_hospitalized_increase“,
            “description“: “获取特定州和日期的住院人数增长“,
            “parameters“: {
                “type“: “object“,
                “properties“: {
                    “state“: {“type“: “string“, “description“: “美国的州名,例如 Alaska“},
                    “date“: {“type“: “string“, “description“: “日期,格式为 YYYY-MM-DD“},
                },
                “required“: [“state“, “date“],
            },
        },
    },
    {
        “type“: “function“,
        “function“: {
            “name“: “get_positive_cases“,
            “description“: “获取特定州和日期的阳性病例数“,
            “parameters“: {
                “type“: “object“,
                “properties“: {
                    “state“: {“type“: “string“, “description“: “美国的州名“},
                    “date“: {“type“: “string“, “description“: “日期,格式为 YYYY-MM-DD“},
                },
                “required“: [“state“, “date“],
            },
        },
    }
]

messages = [{“role“: “user“, “content“: user_message}]

然后,我们重复与天气示例相同的两步流程:

  1. 第一次调用,让模型根据问题意图(“住院人数”)选择 get_hospitalized_increase 函数,并提取出 state=“Alaska“date=“2021-03-05“ 参数。
  2. 执行被选中的函数,获取数据库查询结果。
  3. 将结果返回给模型,生成最终的自然语言回答,例如:“在2021年3月5日,阿拉斯加州报告的COVID-19住院人数增长为3人。”

通过这种方式,我们构建了一个更结构化、更可控的数据库智能体。系统不再直接生成不可预测的 SQL,而是通过我们预定义的、安全的函数来访问数据库,大大提高了系统的可靠性和安全性。

总结

本节课中,我们一起学习了 Azure OpenAI 的函数调用功能。我们了解到,该功能通过将查询逻辑封装在预定义的函数中,为数据库智能体带来了更强的结构性和可控性。我们从创建一个简单的天气查询函数开始,理解了函数调用的两步流程:模型决策与函数执行。随后,我们将此模式应用于实际的数据库查询场景,创建了针对住院数据和阳性病例数据的查询函数,并教会了智能体如何根据用户意图自动选择正确的工具。这种方法使得智能体的行为更加确定,输出更加精准,是构建生产级可靠 AI 应用的重要一步。

006:利用Assistants API连接SQL数据库

在本节课中,我们将学习如何利用最新的模型功能,特别是Assistants API。这个API是之前API的有状态演进版本,旨在促进新型AI智能体的创建。

本节课将为你提供使用全新Assistants API的机会,并测试其函数调用和代码解释器功能。这将完善多种实现模式,帮助你连接SQL数据库并创建自己的数据库智能体。

课程概述

在之前的课程中,我们部署了Azure OpenAI和LangChain实例,为CSV和SQL数据库创建了智能体,并在第4课中切换到使用Azure OpenAI的函数调用功能。我们看到函数调用效果良好,允许系统利用多个函数。

现在,让我们看看Azure OpenAI的另一项功能:Assistants API。之前我们使用GPT-4和聊天补全功能。Assistants API的不同之处在于它能动态维护讨论的上下文。与无状态的聊天补全不同,Assistants API是有状态的,这意味着它会跟踪对话。这对于需要在交互间保持上下文的场景(如电子商务)非常重要。

在Assistants API内部,我们也可以使用函数调用,类似于我们在第4课中所做的。此外,我们还将探索代码解释器功能。代码解释器功能允许Assistants API处理Python代码,它可以迭代地运行代码并进行修改,直到执行成功。这对于复杂任务非常有用。代码解释器功能就像当前环境中的一个环境,使智能体能够修改自己的代码以找到解决方案。

本节课将帮助你探索Assistants API的有状态能力和代码解释器功能,以实现动态和复杂的交互。

开始实践

让我们进入最后一个笔记本并开始操作。这次我们将通过结合之前的配置来保持简洁。我们将一起执行所有操作,包括记录端点、加载CSV数据并将其导入SQL数据库,类似于我们之前所做的。

我们将从导入包含第4课中使用的一些变量和函数的辅助函数开始。这主要是为了引入第4课中定义的SQL工具以及住院和阳性病例的函数。

以下是关键步骤的代码和说明。

1. 初始化客户端与助手

首先,我们设置API密钥、端点和API版本。因为我们使用所有新功能,所以采用最新版本。

# 初始化Azure OpenAI客户端
client = AzureOpenAI(
    api_key=your_api_key,
    api_version="2024-02-15-preview", # 使用最新版本
    azure_endpoint=your_endpoint
)

接着,我们创建一个助手。我们提供指令,说明这是一个回答关于COVID数据集的助手,指定模型,并解释该助手可以使用的工具。

# 创建助手
assistant = client.beta.assistants.create(
    instructions="你是一个回答关于COVID数据问题的助手。",
    model="gpt-4", # 指定模型
    tools=[...] # 此处列出之前定义的函数工具
)

2. 创建对话线程

这是第二步。我们创建一个线程,这就像是讨论的轨迹,可以将不同的消息和用户-机器讨论关联起来。

# 创建线程
thread = client.beta.threads.create()

系统会返回一个唯一的线程标识符和一些元数据。这个thread对象是Assistants API特有的。

3. 添加用户消息

现在,我们向线程中添加一条用户消息。

# 向线程添加消息
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="2021年3月,阿拉斯加州有多少人住院?"
)

我们打印消息以查看其结构,可以看到它是一个包含内容、角色和元数据的JSON对象。

4. 运行助手处理线程

我们已经告诉系统有一些消息和讨论正在进行。现在运行系统来处理这个线程。

# 在线程上运行助手
run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)

这就是设置Assistants API的基本四步流程,具体步骤会根据你拥有的函数和问题类型而略有不同。

使用函数调用

现在,我们将复制第4课中函数调用的操作,但这次在Assistants API中使用它。之后我们将使用代码解释器,但让我们先关注函数调用。

使用函数调用的动态过程与之前非常相似。我们已经定义了函数,并在这个案例中说明我们有一个正在进行的讨论线程,因为我们之前已经启动了它。

以下是运行函数调用的代码:

# 使用函数调用运行
run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id,
    tools=[{"type": "function", "function": function_schema}] # function_schema是函数定义
)

运行这段代码后,系统会处理我们之前传递的测试问题(例如“阿拉斯加州有多少人住院?”),并在讨论中获取答案。答案会显示在特定日期阿拉斯加州有多少人住院。你可以打印JSON转储,或者以更好的格式查看它。

使用代码解释器

接下来是全新的部分:使用代码解释器。记住,代码解释器就像你正在使用的这个沙盒环境中的一个代码沙盒,它是OpenAI和Azure OpenAI中可用的一个代码沙盒,允许助手以智能方式运行复杂任务的代码,甚至允许它在代码不完善时找到使其工作的方法,它会迭代并找到解决方案。

这同样是在我们之前所做工作的基础上进行的增量操作。我们已经有了助手,现在我们基本上是用相同的模型创建一个助手,但在这里我们指定工具类型为代码解释器。

# 创建使用代码解释器的助手
assistant_with_interpreter = client.beta.assistants.create(
    instructions="你是一个可以使用代码解释器分析数据的助手。",
    model="gpt-4",
    tools=[{"type": "code_interpreter"}]
)

我们使用我们的问题“2021年阿拉斯加州的住院情况”,像之前一样运行线程进行讨论,但这次集成了代码解释器工具。

# 使用代码解释器运行线程
run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant_with_interpreter.id
)

运行后,你可以查看线程状态。当运行完成后,你可以通过消息参数获取结果。

# 获取消息列表
messages = client.beta.threads.messages.list(thread_id=thread.id)

结果会显示,例如,在2021年3月,阿拉斯加州有多少人因COVID-19住院。同样,我们得到了答案。在这种情况下,我们所做的就是添加代码解释器,但答案的格式非常相似。

总结

在本节课中,我们一起学习了如何利用Azure OpenAI的Assistants API来构建有状态的数据库智能体。我们回顾了初始化助手、创建对话线程、添加消息以及运行助手的基本步骤。我们实践了在Assistants API框架内使用函数调用功能来执行特定任务。最后,我们探索了强大的代码解释器功能,它允许智能体在沙盒环境中运行和迭代Python代码,以解决更复杂的数据查询和分析问题。

通过结合这些功能,你可以创建出能够理解上下文、动态调用工具并自主执行代码以找到解决方案的智能数据库代理,从而大大增强了AI应用处理SQL数据库的能力。

007:总结 🎯

在本节课中,我们将一起回顾整个课程的核心内容,总结所学到的关于构建数据库智能体的关键知识与技能。

感谢您与我一同完成这次关于AI数据库智能体的深度探索。在本课程中,您学习了生成式AI和Azure OpenAI服务的强大能力。

提示工程模式已成为构建高级应用程序的规范。本课程向您展示了如何从构建最佳数据库智能体的角度,连接不同的表格数据源,服务于公民、用户、数据分析师乃至您公司中的业务主管。

我们非常期待看到您在完成本课程后,能够独立构建出怎样的应用。


课程总结 📝

上一节我们探讨了连接数据源的具体方法,现在让我们来回顾整个课程的要点。

在本课程中,我们一起学习了以下核心内容:

  • 生成式AI的力量:了解了如何利用生成式AI技术理解和处理数据。
  • Azure OpenAI服务:掌握了使用该云服务作为构建智能体基础的方法。
  • 提示工程模式:认识到精心设计的提示是开发高级应用的关键规范。
  • 多数据源连接:学会了为构建数据库智能体而连接各种表格数据源的技巧。
  • 服务广泛用户:明确了智能体可以为从普通用户到企业高管的不同角色提供价值。

本节课中我们一起学习了构建自定义数据库智能体的完整理念与技术路径。从理解核心的AI服务与模式,到实践数据连接,最终目标是创造出能够赋能团队与业务的实用工具。希望这些知识能助您开启自己的构建之旅。

posted @ 2026-03-26 08:16  布客飞龙II  阅读(0)  评论(0)    收藏  举报