Merge pull request #82 from Weihong-Liu/PDF
Update 8.搭建一个带评估的端到端问答系统 Evaluation.ipynb
This commit is contained in:
@ -12,19 +12,15 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"在本章中,我们将搭建一个带评估的端到端问答系统,这个系统综合了之前多节课的内容,并加入了评估过程。\n",
|
"在这一章节中,我们将会构建一个集成评估环节的完整问答系统。这个系统将会融合我们在前几节课中所学到的知识,并且加入了评估步骤。以下是该系统的核心操作流程:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"1. 检查输入,确认其是否能通过审核 API 的审核。\n",
|
"1. 对用户的输入进行检验,验证其是否可以通过审核 API 的标准。\n",
|
||||||
|
"2. 若输入顺利通过审核,我们将进一步对产品目录进行搜索。\n",
|
||||||
|
"3. 若产品搜索成功,我们将继续寻找相关的产品信息。\n",
|
||||||
|
"4. 我们使用模型针对用户的问题进行回答。\n",
|
||||||
|
"5. 最后,我们会使用审核 API 对生成的回答进行再次的检验。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"2. 如果通过了审核,我们将查找产品列表。\n",
|
"如果最终答案没有被标记为有害,那么我们将毫无保留地将其呈现给用户。"
|
||||||
"\n",
|
|
||||||
"3. 如果找到了产品,我们将尝试查找它们的相关信息。\n",
|
|
||||||
"\n",
|
|
||||||
"4. 我们使用模型回答用户提出的问题。\n",
|
|
||||||
"\n",
|
|
||||||
"5. 我们将通过审核 API 对生成的答案进行审核。\n",
|
|
||||||
"\n",
|
|
||||||
"如果没有被标记为有害的,我们将把答案返回给用户。"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -34,6 +30,22 @@
|
|||||||
"## 二、端到端实现问答系统"
|
"## 二、端到端实现问答系统"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"在我们的探索之旅中,我们将实现一个完整的问答系统,一种能理解并回应人类语言的人工智能。在这个过程中,我们将使用 OpenAI 的相关API并引用相关函数,来帮助我们快速搭建一个高效且精准的模型。然而,我们需要注意到,在中文的理解和处理方面,由于模型的特性,我们可能会偶尔遇到不理想的结果。在这种情况下,你可以多尝试几次,或者进行深入的研究,以找到更稳定的方法。\n",
|
||||||
|
"\n",
|
||||||
|
"让我们先从一个函数开始,它的名称是 `process_user_message_ch`,该函数主要负责处理用户输入的信息。这个函数接收三个参数,用户的输入、所有的历史信息,以及一个表示是否需要调试的标志。\n",
|
||||||
|
"在函数的内部,我们首先使用 OpenAI 的 Moderation API 来检查用户输入的合规性。如果输入被标记为不合规,我们将返回一个信息,告知用户请求不合规。在调试模式下,我们将打印出当前的进度。\n",
|
||||||
|
"\n",
|
||||||
|
"接下来,我们利用 `utils_zh.find_category_and_product_only` 函数(详细请见附录代码)抽取出用户输入中的商品和对应的目录。然后,我们将抽取的信息转化为一个列表。\n",
|
||||||
|
"在获取到商品列表后,我们将查询这些商品的具体信息。之后,我们生成一个系统消息,设定一些约束,以确保我们的回应符合期望的标准。我们将生成的消息和历史信息一起送入 `get_completion_from_messages` 函数,得到模型的回应。之后,我们再次使用 Moderation API 检查模型的输出是否合规。如果输出不合规,我们将返回一个信息,告知无法提供该信息。\n",
|
||||||
|
"\n",
|
||||||
|
"最后,我们让模型自我评估是否很好地回答了用户的问题。如果模型认为回答是满足要求的,我们则返回模型的回答;否则,我们会告知用户,他们将会被转接到人工客服进行进一步的帮助。"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 6,
|
"execution_count": 6,
|
||||||
@ -230,7 +242,7 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"实现一个可视化界面"
|
"为了持续优化用户和助手的问答体验,我们打造了一个友好的可视化界面,以促进用户与助手之间的便捷互动。"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -307,11 +319,11 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"通过监控系统在更多输入上的质量,您可以修改步骤,提高系统的整体性能。\n",
|
"通过监控该问答系统在更多输入上的回答效果,您可以修改步骤,提高系统的整体性能。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"也许我们会发现,对于某些步骤,我们的提示可能更好,也许有些步骤甚至不必要,也许我们会找到更好的检索方法等等。\n",
|
"我们可能会察觉,在某些环节,我们的 Prompt 可能更好,有些环节可能完全可以省略,甚至,我们可能会找到更好的检索方法等等。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"我们将在下一章中进一步讨论这个问题。 "
|
"对于这个问题,我们将在接下来的章节中进行更深入的探讨。"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,42 +13,28 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"id": "c768620b",
|
"id": "c9ea000a",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"在之前的章节中,我们展示了如何使用 LLM 构建应用程序,包括评估输入、处理输入以及在向用户显示输出之前进行最终输出检查。\n",
|
"在过去的章节里,我们向你展示了如何借助 LLM 构建应用程序,包括评估输入,处理输入,以及在呈现结果给用户之前进行最后的结果检查。然而,在构建出这样的系统后,我们应如何确知其运行状况呢?更甚者,当我们将其部署并让用户开始使用之后,我们又该如何追踪其表现,发现可能存在的问题,并持续优化它的回答质量呢?在本章里,我们将向你分享一些评估LLM输出的最佳实践。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"构建这样的系统后,如何知道它的工作情况?甚至在部署后并让用户使用它时,如何跟踪它的运行情况,发现任何缺陷,并持续改进系统的答案质量?\n",
|
"构建基于LLM的应用程序与构建传统的监督学习应用程序有所不同。因为你可以快速地构建出基于LLM的应用程序,所以评估通常不从测试集开始。相反,你会逐渐地建立起一个测试样例的集合。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"在本章中,我们想与您分享一些最佳实践,用于评估 LLM 的输出。\n",
|
"在传统的监督学习环境下,你需要收集训练集、开发集,或者留出交叉验证集,在整个开发过程中都会用到它们。然而,如果你能够在几分钟内定义一个 Prompt ,并在几小时内得到反馈结果,那么停下来收集一千个测试样本就会显得极为繁琐。因为现在,你可以在没有任何训练样本的情况下得到结果。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"构建基于 LLM 的应用程序与传统的监督学习应用程序有所不同。由于可以快速构建基于 LLM 的应用程序,因此评估方法通常不从测试集开始。相反,通常会逐渐建立一组测试示例。\n",
|
"因此,在使用LLM构建应用程序时,你可能会经历以下流程:首先,你会在一到三个样本的小样本中调整 Prompt ,尝试使其在这些样本上起效。随后,当你对系统进行进一步测试时,可能会遇到一些棘手的例子,这些例子无法通过 Prompt 或者算法解决。这就是使用 ChatGPT API 构建应用程序的开发者所面临的挑战。在这种情况下,你可以将这些额外的几个例子添加到你正在测试的集合中,有机地添加其他难以处理的例子。最终,你会将足够多的这些例子添加到你逐步扩大的开发集中,以至于手动运行每一个例子以测试 Prompt 变得有些不便。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"在传统的监督学习环境中,需要收集训练集、开发集或保留交叉验证集,然后在整个开发过程中使用它们。\n",
|
"然后,你开始开发一些用于衡量这些小样本集性能的指标,例如平均准确度。这个过程的有趣之处在于,如果你觉得你的系统已经足够好了,你可以随时停止,不再进行改进。实际上,很多已经部署的应用程序就在第一步或第二步就停下来了,而且它们运行得非常好。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"然而,如果能够在几分钟内指定 Prompt,并在几个小时内得到相应结果,那么暂停很长时间去收集一千个测试样本将是一件极其痛苦的事情。因为现在,可以在零个训练样本的情况下获得这个成果。\n",
|
"值得注意的是,很多大型模型的应用程序没有实质性的风险,即使它没有给出完全正确的答案。但是,对于一些高风险的应用,如若存在偏见或不适当的输出可能对某人造成伤害,那么收集测试集、严格评估系统的性能,以及确保它在使用前能做对事情,就显得尤为重要。然而,如果你仅仅是用它来总结文章供自己阅读,而不是给其他人看,那么可能带来的风险就会较小,你可以在这个过程中早早地停止,而不必付出收集大规模数据集的巨大代价。"
|
||||||
"\n",
|
]
|
||||||
"因此,在使用 LLM 构建应用程序时,您将体会到如下的过程:\n",
|
},
|
||||||
"\n",
|
{
|
||||||
"首先,您会在只有一到三个样本的小样本中调整 Prompt,并尝试让 Prompt 在它们身上起作用。\n",
|
"cell_type": "markdown",
|
||||||
"\n",
|
"id": "f0c89bda",
|
||||||
"然后,当系统进行进一步的测试时,您可能会遇到一些棘手的例子。Prompt 在它们身上不起作用,或者算法在它们身上不起作用。\n",
|
"metadata": {},
|
||||||
"\n",
|
"source": [
|
||||||
"这就是使用 ChatGPT API 构建应用程序的开发者所经历的挑战。\n",
|
"现在让我们进入更实际的应用阶段,将刚才所学的理论知识转化为实践。让我们一起研究一些真实的数据,理解其结构并使用我们的工具来分析它们。在我们的案例中,我们获取一组分类信息及其产品名称。让我们执行以下代码,以查看这些分类信息及其产品名称"
|
||||||
"\n",
|
|
||||||
"在这种情况下,您可以将这些额外的几个示例添加到您正在测试的集合中,以机会主义地添加其他棘手的示例。\n",
|
|
||||||
"\n",
|
|
||||||
"最终,您已经添加了足够的这些示例到您缓慢增长的开发集中,以至于通过手动运行每个示例来测试 Prompt 变得有些不方便。\n",
|
|
||||||
"\n",
|
|
||||||
"然后,您开始开发在这些小示例集上用于衡量性能的指标,例如平均准确性。\n",
|
|
||||||
"\n",
|
|
||||||
"这个过程的一个有趣方面是,如果您觉得您的系统已经足够好了,您可以随时停在那里,不再改进它。事实上,许多已部署的应用程序停在第一或第二个步骤,并且运行得非常好。\n",
|
|
||||||
"\n",
|
|
||||||
"需要注意的是,有很多大模型的应用程序没有实质性的风险,即使它没有给出完全正确的答案。\n",
|
|
||||||
"\n",
|
|
||||||
"但是,对于部分高风险应用,如果存在偏见或不适当的输出可能对某人造成伤害,那么收集测试集、严格评估系统的性能、确保在使用之前它能够做正确的事情,就变得更加重要。\n",
|
|
||||||
"\n",
|
|
||||||
"但是,如果您只是使用它来总结文章供自己阅读,而不是给别人看,那么可能造成的危害风险更小,您可以在这个过程中早早停止,而不必去花费更大的代价去收集更大的数据集。"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -116,6 +102,22 @@
|
|||||||
"## 一、找出相关产品和类别名称"
|
"## 一、找出相关产品和类别名称"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "59867e0e",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"在我们进行开发时,通常需要处理和解析用户的输入。特别是在电商领域,可能会有各种各样的用户查询,例如:\"我想要最贵的电脑\"。我们需要一个能理解这种语境,并能给出相关产品和类别的工具。下面这段代码实现的功能就是这样。\n",
|
||||||
|
"\n",
|
||||||
|
"首先我们定义了一个函数`find_category_and_product_v1`,这个函数的主要目的是从用户的输入中解析出产品和类别。这个函数需要两个参数:`user_input`代表用户的查询,`products_and_category`是一个字典,其中包含了产品类型和对应产品的信息。\n",
|
||||||
|
"\n",
|
||||||
|
"在函数的开始,我们定义了一个分隔符`delimiter`,用来在客户服务查询中分隔内容。随后,我们创建了一条系统消息。这条消息主要解释了系统的运作方式:用户会提供客户服务查询,查询会被分隔符`delimiter`分隔。系统会输出一个Python列表,列表中的每个对象都是Json对象。每个对象会包含'类别'和'名称'两个字段,分别对应产品的类别和名称。\n",
|
||||||
|
"\n",
|
||||||
|
"我们创建了一个名为`messages`的列表,用来存储这些示例对话以及用户的查询。最后,我们使用`get_completion_from_messages`函数处理这些消息,返回处理结果。\n",
|
||||||
|
"\n",
|
||||||
|
"通过这段代码,我们可以看到如何通过对话的方式理解和处理用户的查询,以提供更好的用户体验。"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 4,
|
"execution_count": 4,
|
||||||
@ -499,7 +501,9 @@
|
|||||||
"id": "2af63218",
|
"id": "2af63218",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"当您要调整的开发集不仅仅是一小部分示例时,开始自动化测试过程就变得有用了。"
|
"当我们的应用程序逐渐成熟,测试的重要性也随之增加。通常,当我们仅处理少量样本,手动运行测试并对结果进行评估是可行的。然而,随着开发集的增大,这种方法变得既繁琐又低效。此时,就需要引入自动化测试来提高我们的工作效率。下面将开始编写代码来自动化测试流程,可以帮助您提升效率并确保测试的准确率。\n",
|
||||||
|
"\n",
|
||||||
|
"以下是一些用户问题的标准答案,用于评估 LLM 回答的准确度,与机器学习中的验证集的作用相当。"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -616,6 +620,14 @@
|
|||||||
"## 八、通过与理想答案比较来评估测试用例"
|
"## 八、通过与理想答案比较来评估测试用例"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "b5aba12b",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"我们通过以下函数`eval_response_with_ideal`来评估 LLM 回答的准确度"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 17,
|
"execution_count": 17,
|
||||||
@ -767,9 +779,18 @@
|
|||||||
"height": 30
|
"height": 30
|
||||||
},
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"## 九、在所有测试用例上运行评估,并计算正确的用例比例\n",
|
"## 九、在所有测试用例上运行评估,并计算正确的用例比例\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "4fa148ce",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"下面我们来对测试用例中的全部问题进行验证,并计算 LLM 回答正确的准确率\n",
|
||||||
"\n",
|
"\n",
|
||||||
"注意:如果任何 API 调用超时,将无法运行"
|
"\n",
|
||||||
|
"> 注意:如果任何 API 调用超时,将无法运行"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -863,17 +884,11 @@
|
|||||||
"id": "5d885db6",
|
"id": "5d885db6",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"使用 Prompt 构建应用程序的工作流程与使用监督学习构建应用程序的工作流程非常不同。\n",
|
"使用 Prompt 构建应用程序的工作流程与使用监督学习构建应用程序的工作流程非常不同。因此,我们认为这是需要记住的一件好事,当您正在构建监督学习模型时,会感觉到迭代速度快了很多。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"因此,我们认为这是需要记住的一件好事,当您正在构建监督学习模型时,会感觉到迭代速度快了很多。\n",
|
"如果您并未亲身体验,可能会惊叹于仅有手动构建的极少样本,就可以产生高效的评估方法。您可能会认为,仅有 10 个样本是不具备统计意义的。但当您真正运用这种方式时,您可能会对向开发集中添加一些复杂样本所带来的效果提升感到惊讶。这对于帮助您和您的团队找到有效的 Prompt 和有效的系统非常有帮助。\n",
|
||||||
"\n",
|
"\n",
|
||||||
"如果您并未亲身体验,可能会惊叹于仅有手动构建的极少样本,就可以产生高效的评估方法。您可能会认为,仅有 10 个样本是不具备统计意义的。但当您真正运用这种方式时,您可能会对向开发集中添加一些复杂样本所带来的效果提升感到惊讶。\n",
|
"在本章中,输出可以被定量评估,就像有一个期望的输出一样,您可以判断它是否给出了这个期望的输出。在下一章中,我们将探讨如何在更加模糊的情况下评估我们的输出。即正确答案可能不那么明确的情况。"
|
||||||
"\n",
|
|
||||||
"这对于帮助您和您的团队找到有效的 Prompt 和有效的系统非常有帮助。\n",
|
|
||||||
"\n",
|
|
||||||
"在本章中,输出可以被定量评估,就像有一个期望的输出一样,您可以判断它是否给出了这个期望的输出。\n",
|
|
||||||
"\n",
|
|
||||||
"在下一章中,我们将探讨如何在更加模糊的情况下评估我们的输出。即正确答案可能不那么明确的情况。"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user