diff --git a/docs/content/C2 Building Systems with the ChatGPT API/6.处理输入-链式 Prompt Chaining Prompts.ipynb b/docs/content/C2 Building Systems with the ChatGPT API/6.处理输入-链式 Prompt Chaining Prompts.ipynb index e0368a1..3a2e5a8 100644 --- a/docs/content/C2 Building Systems with the ChatGPT API/6.处理输入-链式 Prompt Chaining Prompts.ipynb +++ b/docs/content/C2 Building Systems with the ChatGPT API/6.处理输入-链式 Prompt Chaining Prompts.ipynb @@ -11,22 +11,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "在本章中,我们将学习如何通过使用链式 Prompt 将复杂任务拆分为一系列简单的子任务。\n", + "链式提示是将复杂任务分解为多个简单Prompt的策略。在本章中,我们将学习如何通过使用链式 Prompt 将复杂任务拆分为一系列简单的子任务。你可能会想,如果我们可以通过思维链推理一次性完成,那为什么要将任务拆分为多个 Prompt 呢?\n", "\n", - "你可能会想,如果我们可以通过思维链推理一次性完成,那为什么要将任务拆分为多个 Prompt 呢?让我们用以下两个比喻来比较思维链推理和链式Prompt,从而来解释链式Prompt的必要性。 \n", + "主要是因为链式提示它具有以下优点:\n", "\n", - "- 将任务拆分为多个 Prompt 就像是一次性烹饪复杂菜肴与分阶段烹饪的区别。使用一个长而复杂的 Prompt 可能就像一次性烹饪复杂的菜肴,您必须同时管理多个成分、烹饪技巧和时间。这可能很具有挑战性,难以跟踪每个部分并确保每个组成部分都烹饪得恰到好处。另一方面,链式 Prompt 就像分阶段烹饪餐点,你专注于一个组成部分,确保每个部分都正确烹饪后再进行下一个。这种方法可以分解任务的复杂性,使其更易于管理,并减少错误的可能性。但是,对于非常简单的食谱,这种方法则可能因为过于复杂而不适用。\n", + "1. 分解复杂度,每个 Prompt 仅处理一个具体子任务,避免过于宽泛的要求,提高成功率。这类似于分阶段烹饪,而不是试图一次完成全部。\n", "\n", - "- 思维链推理和链式Prompt的区别就像一长串袋馍和简单的模块化程序。相比使用简单的模块化程序,一长串代码之前复杂的依赖关系会导致代码变得混乱且难以调试。\n", + "2. 降低计算成本。过长的 Prompt 使用更多 tokens ,增加成本。拆分 Prompt 可以避免不必要的计算。\n", "\n", - "当你的工作流程包含多个步骤和多个状态,在不同状态下需要采取不同操作的时,链式 Prompt 就成为一种强大的策略。比如在对客户的查询进行分类后,获得查询的类别:是账户问题还是产品问题。然后可以根据不同的类别采取不同的行动。\n", + "3. 更容易测试和调试。可以逐步分析每个环节的性能。\n", "\n", - "在链式Prompt中,复杂任务被拆分为子任务,每个子任务仅包含执行对应任务所需的指令,这使得系统更易于管理,确保模型具备执行任务所需的所有信息,并降低了出错的可能性。此外,链式Prompt还有有以下好处\n", - "- 降低成本。因为更长的 Prompt 和更多的 tokens 会导致更高的运行成本,并且在某些情况下可能不需要概述所有步骤。\n", - "- 更容易测试哪些步骤可能更容易出错,或者在特定步骤中需要人工干预。\n", - "- 使用外部工具。例如,在其中的某一步,你可以去产品目录中查找某些内容,调用外部 API 或搜索知识库,这些使用单个 Prompt 无法实现的。\n", + "4. 融入外部工具。不同 Prompt 可以调用 API 、数据库等外部资源。\n", "\n", - "随着您与这些模型的构建和交互不断深入,您将逐渐培养出何时运用链式 Prompt策略的直觉。\n" + "5. 更灵活的工作流程。根据不同情况可以进行不同操作。\n", + "\n", + "综上,链式提示通过将复杂任务进行科学拆分,实现了更高效、可靠的提示设计。它使语言模型集中处理单一子任务,减少认知负荷,同时保留了多步骤任务的能力。随着经验增长,开发者可以逐渐掌握运用链式提示的精髓。\n" ] }, { @@ -130,7 +129,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "可以看到,输出是一个对象列表,每个对象都有一个类别和一些产品。如\"SmartX ProPhone\" 和 \"Fotosnap DSLR Camera\"、\"CineView 4K TV\"。\n", + "可以看到,输出是一个对象列表,每个对象都有一个类别和一些产品。如 \"SmartX ProPhone\" 和 \"Fotosnap DSLR Camera\" 、\"CineView 4K TV\"。\n", "\n", "我们再来看一个例子。" ] @@ -167,11 +166,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "我们提供大量的产品信息作为示例,要求模型提取产品和对应的详细信息。限于篇幅,我们产品信息存储在 products.json 中,通过 Python 代码读取该信息。\n", + "我们提供大量的产品信息作为示例,要求模型提取产品和对应的详细信息。限于篇幅,我们产品信息存储在 products.json 中。\n", "\n", - "如下是产品信息的少量展示:\n", - "\n", - "![](../../../figures/docs/C2/ch6-products.png)" + "首先,让我们通过 Python 代码读取产品信息。" ] }, { @@ -186,6 +183,13 @@ " products = json.load(file)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "接下来,定义 get_product_by_name 函数,是我们能够根据产品名称获取产品:" + ] + }, { "cell_type": "code", "execution_count": 5, @@ -211,6 +215,13 @@ " return [product for product in products.values() if product[\"类别\"] == category]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "调用 get_product_by_name 函数,输入产品名称 “TechPro Ultrabook”: " + ] + }, { "cell_type": "code", "execution_count": 7, @@ -239,6 +250,13 @@ "get_product_by_name(\"TechPro Ultrabook\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "接下来,我们再看一个例子,调用 get_product_by_name 函数,输入产品名称 “电脑和笔记本”: " + ] + }, { "cell_type": "code", "execution_count": 8, @@ -323,6 +341,13 @@ "### 3.1 解析输入字符串" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "定义一个 read_string_to_list 函数,将输入的字符串转换为 Python 列表" + ] + }, { "cell_type": "code", "execution_count": 6, @@ -377,6 +402,13 @@ "### 3.2 进行检索" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "定义函数 generate_output_string 函数,根据输入的数据列表生成包含产品或类别信息的字符串:" + ] + }, { "cell_type": "code", "execution_count": 10, @@ -632,6 +664,15 @@ "print(final_response)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "在这个例子中,我们只添加了一个特定函数或函数的调用,以通过产品名称获取产品描述或通过类别名称获取类别产品。但是,模型实际上擅长决定何时使用各种不同的工具,并可以正确地使用它们。这就是 ChatGPT 插件背后的思想。我们告诉模型它可以访问哪些工具以及它们的作用,它会在需要从特定来源获取信息或想要采取其他适当的操作时选择使用它们。在这个例子中,我们只能通过精确的产品和类别名称匹配查找信息,但还有更高级的信息检索技术。检索信息的最有效方法之一是使用自然语言处理技术,例如命名实体识别和关系提取。\n", + "\n", + "另一方法是使用文本嵌入(Embedding)来获取信息。嵌入可以用于实现对大型语料库的高效知识检索,以查找与给定查询相关的信息。使用文本嵌入的一个关键优势是它们可以实现模糊或语义搜索,这使您能够在不使用精确关键字的情况下找到相关信息。因此,在此例子中,我们不一定需要产品的确切名称,而可以使用更一般的查询如 **“手机”** 进行搜索。" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -643,29 +684,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "我们讨论了如何通过一系列步骤加载与用户查询相关的信息,为模型提供所需的上下文,以有效回答问题。\n", + "在设计提示链时,我们并不需要也不建议将所有可能相关信息一次性全加载到模型中,而是采取动态、按需提供信息的策略,原因如下:\n", "\n", - "您可能会想,为什么我们选择性地将产品描述加载到提示中,而不是包含所有产品描述,让模型使用它所需的信息呢?\n", + "1. 过多无关信息会使模型处理上下文时更加困惑。尤其是低级模型,处理大量数据会表现衰减。\n", "\n", - "这其中有几个原因。\n", + "2. 模型本身对上下文长度有限制,无法一次加载过多信息。\n", "\n", - "首先,包含过多的产品描述可能会使模型在处理上下文时感到困惑,就像对于试图一次处理大量信息的人一样。当然,对于像 GPT-4 这样更高级的模型来说,这个原因就不太重要了。尤其是当上下文像这个例子一样具有良好的结构时,模型足够聪明,能够巧妙地忽略那些明显不相关的信息。\n", + "3. 包含过多信息容易导致模型过拟合,处理新查询时效果较差。\n", "\n", - "接下来的原因更加具有说服力。\n", + "4. 动态加载信息可以降低计算成本。\n", "\n", - "首先,包含所有产品描述可能会使模型对上下文更加混乱,就像对于试图一次处理大量信息的人一样。当然,对于像 GPT-4 这样更高级的模型来说,这个问题不太相关,特别是当上下文像这个例子一样结构良好时,模型足够聪明,只会忽略明显不相关的信息。接下来的原因更有说服力。\n", + "5. 允许模型主动决定何时需要更多信息,可以增强其推理能力。\n", "\n", - "第二个原因是,语言模型有上下文限制,即固定数量的 token 允许作为输入和输出。如果您有一个巨大的产品目录,您甚至无法将所有描述都放入上下文窗口中。\n", + "6. 我们可以使用更智能的检索机制,而不仅是精确匹配,例如文本 Embedding 实现语义搜索。\n", "\n", - "最后一个原因是,包含所有产品描述可能会使模型过拟合,因为它会记住所有的产品描述,而不是只记住与查询相关的信息。这可能会导致模型在处理新的查询时表现不佳。\n", - "\n", - "使用语言模型时,由于按 token 付费,可能会很昂贵。因此,通过有选择地加载信息,可以减少生成响应的成本。一般来说,确定何时动态加载信息到模型的上下文中,并允许模型决定何时需要更多信息,是增强这些模型能力的最佳方法之一。\n", - "\n", - "并且要再次强调,您应该将语言模型视为需要必要上下文才能得出有用结论和执行有用任务的推理代理。因此,在这种情况下,我们必须向模型提供产品信息,然后它才能根据该产品信息进行推理,为用户创建有用的答案。\n", - "\n", - "在这个例子中,我们只添加了一个特定函数或函数的调用,以通过产品名称获取产品描述或通过类别名称获取类别产品。但是,模型实际上擅长决定何时使用各种不同的工具,并可以正确地使用它们。这就是 ChatGPT 插件背后的思想。我们告诉模型它可以访问哪些工具以及它们的作用,它会在需要从特定来源获取信息或想要采取其他适当的操作时选择使用它们。在这个例子中,我们只能通过精确的产品和类别名称匹配查找信息,但还有更高级的信息检索技术。检索信息的最有效方法之一是使用自然语言处理技术,例如命名实体识别和关系提取。\n", - "\n", - "另一方法是使用文本嵌入(Embedding)来获取信息。嵌入可以用于实现对大型语料库的高效知识检索,以查找与给定查询相关的信息。使用文本嵌入的一个关键优势是它们可以实现模糊或语义搜索,这使您能够在不使用精确关键字的情况下找到相关信息。因此,在此例子中,我们不一定需要产品的确切名称,而可以使用更一般的查询如 **“手机”** 进行搜索。我们计划很快推出一门全面的课程,介绍如何在各种应用中使用嵌入,敬请关注。\n", + "因此,合理设计提示链的信息提供策略,既考虑模型的能力限制,也兼顾提升其主动学习能力,是提示工程中需要着重考虑的点。希望这些经验可以帮助大家设计出运行高效且智能的提示链系统。\n", "\n", "在下一章中我们将讨论如何评估语言模型的输出。" ]