diff --git a/content/Prompt Engineering/2. 提示原则 Guidelines.ipynb b/content/Prompt Engineering/2. 提示原则 Guidelines.ipynb index b0941c6..791da98 100644 --- a/content/Prompt Engineering/2. 提示原则 Guidelines.ipynb +++ b/content/Prompt Engineering/2. 提示原则 Guidelines.ipynb @@ -7,7 +7,7 @@ "source": [ "# 第二章 编写 Prompt 的原则\n", "\n", - " 本章的主要内容为编写 Prompt 的原则,在本章中,我们将给出两个编写 Prompt 的原则与一些相关的策略,你可以练习编写高效的 Prompt,从而便捷而有效地使用 LLM。" + " 本章的主要内容为编写 Prompt 的原则,在本章中,我们将给出两个编写 Prompt 的原则与一些相关的策略,您可以练习编写高效的 Prompt,从而便捷而有效地使用 LLM。" ] }, { @@ -16,15 +16,15 @@ "source": [ "
\n", " \n", "
" @@ -43,7 +43,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "本教程使用 OpenAI 所开放的 ChatGPT API,因此你需要首先拥有一个 ChatGPT 的 API_KEY(也可以直接访问官方网址在线测试),然后需要安装 openai 的第三方库" + "本教程使用 OpenAI 所开放的 ChatGPT API,因此您需要首先拥有一个 ChatGPT 的 API_KEY(也可以直接访问官方网址在线测试),然后需要安装 openai 的第三方库" ] }, { @@ -99,7 +99,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "整个课程将以 gpt-3.5-turbo 模型为例。我们将在后续课程中深入探究 OpenAI 提供的 [Chat Completions API](https://platform.openai.com/docs/guides/gpt/chat-completions-api) 的使用方法,在此处,我们先将它封装成一个函数,你无需知道其内部机理,仅需知道调用该函数输入 Prompt 其将会给出对应的 Completion 即可。" + "整个课程将以 gpt-3.5-turbo 模型为例。我们将在后续课程中深入探究 OpenAI 提供的 [Chat Completions API](https://platform.openai.com/docs/guides/gpt/chat-completions-api) 的使用方法,在此处,我们先将它封装成一个函数,您无需知道其内部机理,仅需知道调用该函数输入 Prompt 其将会给出对应的 Completion 即可。" ] }, { @@ -111,7 +111,7 @@ "# 一个封装 OpenAI 接口的函数,参数为 Prompt,返回对应结果\n", "def get_completion(prompt, model=\"gpt-3.5-turbo\"):\n", " '''\n", - " prompt: 对应的 Prompt \n", + " prompt: 对应的提示词\n", " model: 调用的模型,默认为 gpt-3.5-turbo(ChatGPT),有内测资格的用户可以选择 gpt-4\n", " '''\n", " messages = [{\"role\": \"user\", \"content\": prompt}]\n", @@ -139,7 +139,7 @@ "source": [ "### 2.1 原则一:编写清晰、具体的指令\n", "\n", - "你应该通过提供尽可能清晰和具体的指令来表达您希望模型执行的操作。这将引导模型给出正确的输出,并降低你得到无关或不正确响应的可能性。清晰的指令不意味着必须简短,因为在许多情况下,更长的 Prompt 实际上更清晰,且提供了更多上下文,也就可能产生更详细更相关的输出。" + "您应该通过提供尽可能清晰和具体的指令来表达您希望模型执行的操作。这将引导模型给出正确的输出,并降低您得到无关或不正确响应的可能性。清晰的指令不意味着必须简短,在许多情况下,更长的 Prompt 实际上更清晰,且提供了更多上下文,也就可能产生更详细更相关的输出。" ] }, { @@ -147,9 +147,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**2.1.1 使用分隔符清晰地表示输入的不同部分**,分隔符可以是:```,\"\",:,<>,\\ \\等\n", + "**2.1.1 使用分隔符清晰地表示输入的不同部分**,分隔符可以是:```,\"\",<>,:,\\ \\等\n", "\n", - "你可以使用任何明显的标点符号将特定的文本部分与 Prompt 的其余部分分开。标记的形式不限,只需要让模型明确知道这是一个单独部分。使用分隔符可以有效避免提示词注入(Prompt injection)。 Prompt 注入是指如果允许用户将某些输入添加到(开发者预定义的) Prompt 中,则所提供的指令可能会与开发者想要执行的操作相冲突,从而使 LLM 遵循用户输入的指令,而非执行开发者预期的操作。即,输入里面可能包含其他指令,会覆盖掉你的指令。对此,使用分隔符是一个不错的策略。\n", + "您可以使用任何明显的标点符号将特定的文本部分与 Prompt 的其余部分分开。标记的形式不限,只需要让模型明确知道这是一个单独部分。使用分隔符可以有效避免提示词注入( Prompt injection )。提示词注入是指如果允许用户将某些输入添加到(开发者预定义的) Prompt 中,则所提供的指令可能会与开发者想要执行的操作相冲突,从而使 LLM 遵循用户输入的指令,而非执行开发者预期的操作。即,输入里面可能包含其他指令,会覆盖掉您的指令。对此,使用分隔符是一个不错的策略。\n", "\n", "在以下的例子中,我们给出一段话并要求 GPT 进行总结,在该示例中我们使用 ``` 来作为分隔符。\n" ] @@ -197,10 +197,10 @@ "outputs": [], "source": [ "text = f\"\"\"\n", - "你应该提供尽可能清晰、具体的指示,以表达你希望模型执行的任务。\\\n", + "您应该提供尽可能清晰、具体的指示,以表达您希望模型执行的任务。\\\n", "这将引导模型朝向所需的输出,并降低收到无关或不正确响应的可能性。\\\n", - "不要将写清晰的 Prompt 与写简短的 Prompt 混淆。\\\n", - "在许多情况下,更长的 Prompt 可以为模型提供更多的清晰度和上下文信息,从而导致更详细和相关的输出。\n", + "不要将写清晰的提示词与写简短的提示词混淆。\\\n", + "在许多情况下,更长的提示词可以为模型提供更多的清晰度和上下文信息,从而导致更详细和相关的输出。\n", "\"\"\"\n", "# 需要总结的文本内容\n", "prompt = f\"\"\"\n", @@ -225,11 +225,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**2.1.2 寻求结构化的输出**,可以是 JSON、HTML 等格式\n", + "**2.1.2 寻求结构化的输出**,可以是 Json、HTML 等格式\n", "\n", - "第二个策略是要求生成一个结构化的输出,这可以使模型的输出更容易被我们解析。例如,你可以在 Python 中将其读入字典或列表中。\n", + "第二个策略是要求生成一个结构化的输出,这可以使模型的输出更容易被我们解析,例如,您可以在 Python 中将其读入字典或列表中。\n", "\n", - "在以下示例中,我们要求 GPT 生成三本书的标题、作者和类别,并要求 GPT 以 JSON 的格式返回给我们,为便于解析,我们指定了 JSON 的键。" + "在以下示例中,我们要求 GPT 生成三本书的标题、作者和类别,并要求 GPT 以 Json 的格式返回给我们,为便于解析,我们指定了 Json 的键。" ] }, { @@ -325,9 +325,9 @@ "source": [ "**2.1.3 要求模型检查是否满足条件**\n", "\n", - "如果任务包含不一定能满足的假设,我们可以告诉模型先检查这些假设,如果不满足,则指出并停止执行后续的完整流程。你还可以考虑可能出现的边缘情况及模型的应对,以避免意外的结果或错误发生。\n", + "如果任务包含不一定能满足的假设(条件),我们可以告诉模型先检查这些假设,如果不满足,则会指出并停止执行后续的完整流程。您还可以考虑可能出现的边缘情况及模型的应对,以避免意外的结果或错误发生。\n", "\n", - "在如下示例中,我们将分别给模型两段文本,分别是制作茶的步骤以及一段没有明确步骤的文本。我们将要求模型判断其是否包含一系列指令,如果包含则按照给定格式重新编写指令,不包含则回答未提供步骤。" + "在如下示例中,我们将分别给模型两段文本,分别是制作茶的步骤以及一段没有明确步骤的文本。我们将要求模型判断其是否包含一系列指令,如果包含则按照给定格式重新编写指令,不包含则回答“未提供步骤”。" ] }, { @@ -455,8 +455,8 @@ "在等待期间,拿一个杯子并把茶包放进去。\\\n", "一旦水足够热,就把它倒在茶包上。\\\n", "等待一会儿,让茶叶浸泡。几分钟后,取出茶包。\\\n", - "如果你愿意,可以加一些糖或牛奶调味。\\\n", - "就这样,你可以享受一杯美味的茶了。\n", + "如果您愿意,可以加一些糖或牛奶调味。\\\n", + "就这样,您可以享受一杯美味的茶了。\n", "\"\"\"\n", "prompt = f\"\"\"\n", "您将获得由三个引号括起来的文本。\\\n", @@ -490,7 +490,7 @@ } ], "source": [ - "# 不满足条件的输入(text中未提供步骤)\n", + "# 不满足条件的输入(text中未提供预期指令)\n", "text_2 = f\"\"\"\n", "今天阳光明媚,鸟儿在歌唱。\\\n", "这是一个去公园散步的美好日子。\\\n", @@ -520,19 +520,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**2.1.4 提供少量示例**(少样本 Prompt ,Few-shot prompting)\n", + "**2.1.4 提供少量示例**(少样本提示词,Few-shot prompting)\n", "\n", "即在要求模型执行实际任务之前,提供给它少量成功执行任务的示例。\n", "\n", - "例如,在以下的示例中,我们告诉模型其任务是以一致的风格回答问题,并先给它一个孩子和祖父之间的对话的例子。孩子说,“请教我何为耐心”,祖父用下述风格的隐喻来回答。由于我们已经告诉模型要以一致的语气回答,因此现在我们问“请教我何为韧性”,由于模型已经有了这个少样本示例(few-shot example),它将以类似的语气回答下一个任务。" + "例如,在以下的示例中,我们告诉模型其任务是以一致的风格回答问题,并先给它一个孩子和祖父之间的对话的例子。孩子说,“请教我何为耐心”,祖父用下述风格的隐喻来回答。由于我们已经告诉模型要以一致的语气回答,因此现在我们问“请教我何为韧性”,由于模型已经有了这个少样本示例( few-shot example ),它将以类似的语气回答下一个任务。" ] }, { @@ -580,7 +572,7 @@ ], "source": [ "prompt = f\"\"\"\n", - "你的任务是以一致的风格回答问题。\n", + "您的任务是以一致的风格回答问题。\n", "\n", "<孩子>: 教我耐心。\n", "\n", @@ -597,13 +589,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 2.2 原则二:给模型时间去思考\n", + "### 2.2 给模型时间去思考\n", "\n", -<<<<<<< Updated upstream - "如果模型匆忙地得出了错误的结论,您应该尝试重新构思查询,请求模型在提供最终答案之前进行一系列相关的推理。换句话说,如果您给模型一个在短时间或用少量文字无法完成的任务,它可能会猜测错误。这种情况对人来说也是一样的。如果您让某人在没有时间计算出答案的情况下完成复杂的数学问题,他们也可能会犯错误。因此,在这些情况下,您可以指示模型花更多时间思考问题,这意味着它在任务上花费了更多的计算资源。" -======= "如果您发现模型推理过程过于匆忙,导致得出了错误的结论,那么您应该尝试重新构思 Prompt ,要求模型在提供最终答案之前开展思维链,或进行一系列相关推理(a chain or series of relevant reasoning)。换句话说,如果您给模型一个在短时间内或用少量文字无法完成的复杂任务,它的输出结果就容易出错。这种情况对人来说也是类似:如果您要求某人完成复杂的数学问题,又不给足够时间计算出答案,他们也可能会犯错误。因此,在这些情况下,您应该指示模型花更多时间思考问题,让它在任务上花费更多计算资源。" ->>>>>>> Stashed changes ] }, { @@ -621,11 +609,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "首先我们描述了杰克和吉尔的故事,并给出一个指令。该指令是执行以下操作。首先,用一句话概括三个反引号限定的文本。第二,将摘要翻译成法语。第三,在法语摘要中列出每个名称。第四,输出包含以下键的 JSON 对象:法语摘要和名称数。然后我们要用换行符分隔答案。" -======= - "首先我们描述了杰克和吉尔的故事,并给出 Prompt 执行以下操作:首先,用一句话概括三个反引号限定的文本。第二,将摘要翻译成法语。第三,在法语摘要中列出每个名称。第四,输出包含以下键的 JSON 对象:法语摘要和人名个数。要求输出以换行符分隔。" ->>>>>>> Stashed changes + "首先我们描述了杰克和吉尔的故事,并给出提示词执行以下操作:首先,用一句话概括三个反引号限定的文本。第二,将摘要翻译成法语。第三,在法语摘要中列出每个名称。第四,输出包含以下键的 JSON 对象:法语摘要和人名个数。要求输出以换行符分隔。" ] }, { @@ -728,17 +712,14 @@ "print(response)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "上述输出仍然存在一定问题,例如,键“姓名”会被替换为法语,因此,我们给出一个更好的 Prompt,该 Prompt 指定了输出的格式" + "上述输出仍然存在一定问题,例如,键“姓名”会被替换为法语(译注:在英文原版中,对应指令第三步的输出为 'Noms:',为Name的法语,这种行为难以预测,并可能为导出带来困难)\n", + "\n", + "因此,我们将Prompt加以改进,该 Prompt 前半部分不变,同时**确切指定了输出的格式**。" ] }, { @@ -821,6 +802,14 @@ "print(response)" ] }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + " " + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -828,9 +817,9 @@ "source": [ "**2.2.2 指导模型在下结论之前找出一个自己的解法**\n", "\n", - "有时候,在明确指导模型在做决策之前要思考解决方案时,我们会得到更好的结果。\n", + "明确地指引模型在匆匆做决策之前,要自己思考出一份解决方案。有时这样会得到更好的结果。这与之前所述思想类似,即给模型时间思考。\n", "\n", - "接下来我们会给出一个问题和一个学生的解答,要求模型判断解答是否正确" + "接下来我们会给出一个问题和一份来自学生的解答,要求模型判断解答是否正确:" ] }, { @@ -921,11 +910,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "但是注意,学生的解决方案实际上是错误的。\n", + "但是注意,学生的解决方案实际上是错误的。(*维护费用项100x应为10x,总费用450x应为360x*)\n", "\n", - "我们可以通过**指导模型先自行找出一个解法**来解决这个问题。\n", + "我们可以通过指导模型先自行找出一个解法来解决这个问题。\n", "\n", - "在接下来这个 Prompt 中,我们要求模型先自行解决这个问题,再根据自己的解法与学生的解法进行对比,从而判断学生的解法是否正确。同时,我们给定了输出的格式要求。通过明确步骤,让模型有更多时间思考,有时可以获得更准确的结果。在这个例子中,学生的答案是错误的,但如果我们没有先让模型自己计算,那么可能会被误导以为学生是正确的。" + "在接下来这个 Prompt 中,我们要求模型先自行解决这个问题,再根据自己的解法与学生的解法进行对比,从而判断学生的解法是否正确。同时,我们给定了输出的格式要求。通过拆分任务、明确步骤,让模型有更多时间思考,有时可以获得更准确的结果。在这个例子中,学生的答案是错误的,但如果我们没有先让模型自己计算,那么可能会被误导以为学生是正确的。" ] }, { @@ -1043,7 +1032,8 @@ "步骤:\n", "\n", " 首先,自己解决问题。\n", - " 然后将你的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。在自己完成问题之前,请勿决定学生的解决方案是否正确。\n", + " 然后将您的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。\n", + " 在自己完成问题之前,请勿决定学生的解决方案是否正确。\n", "\n", "使用以下格式:\n", "\n", @@ -1089,15 +1079,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "**开发大模型相关应用时请务必铭记:**\n", + "\n", + "\n", "**虚假知识**:模型偶尔会生成一些看似真实实则编造的知识\n", "\n", - "如果模型在训练过程中接触了大量的知识,它并没有完全记住所见的信息,因此它并不很清楚自己知识的边界。这意味着它可能会尝试回答有关晦涩主题的问题,并编造听起来合理但实际上并不正确的答案。我们称这些编造的想法为幻觉。\n", + "如果模型在训练过程中接触了大量的知识,它并没有完全记住所见的信息,因此它并不很清楚自己知识的边界。这意味着它可能会尝试回答主题晦涩难懂的问题,并编造听起来合理但实际上并不正确的答案。我们称这些编造的想法为幻觉(Hallucination)。\n", "\n", -<<<<<<< Updated upstream - "例如在如下示例中,我们要求告诉我们 Boie 公司生产的 AeroGlide UltraSlim Smart Toothbrush 产品的信息,事实上,这个公司是真实存在的,但产品是编造的,模型则会一本正经地告诉我们编造的知识。\n", -======= "如下示例展示了大模型的幻觉。我们要求告诉我们 Boie 公司生产的 *AeroGlide UltraSlim Smart Toothbrush* 产品的信息,事实上,这个公司是真实存在的,但产品是编造的,而模型一本正经地提供了它编造的知识,而且迷惑性很强。\n", ->>>>>>> Stashed changes "\n" ] }, @@ -1161,23 +1150,14 @@ "print(response)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "模型会输出看上去非常真实的编造知识,这有时会很危险。因此,请确保使用我们在本节中介绍的一些技巧,以尝试在构建自己的应用程序时避免这种情况。这是模型已知的一个弱点,也是我们正在积极努力解决的问题。在你希望模型根据文本生成答案的情况下,另一种减少幻觉的策略是先要求模型找到文本中的任何相关引用,然后要求它使用这些引用来回答问题,这种追溯源文档的方法通常对减少幻觉非常有帮助。" -======= - "由于很容易以假乱真,请读者根据在本系列教程中所学知识,在构建自己的应用程序时尽量避免幻觉情况。幻觉是大模型的一个已知缺陷(译注:截至2023年7月),OpenAI也在努力解决该问题。\n", + "由于很容易以假乱真,请读者根据在本系列教程中所学知识,在构建自己的应用程序时尽量避免幻觉情况。幻觉是大模型的一个已知缺陷(注:截至2023年7月),OpenAI也在努力解决该问题。\n", "\n", - "在你希望模型根据文本生成回答时,另一种减少幻觉的策略是先要求模型获取来源于该文本的所有引用信息(任何相关引用,any relevant quotes),然后要求它基于所引用的信息来回答问题,这使得我们能根据答案追溯源文档,通常对减少幻觉非常有帮助。" ->>>>>>> Stashed changes + "在您希望模型根据文本生成回答时,另一种减少幻觉的策略是先要求模型获取来源于该文本的所有引用信息(任何相关引用,any relevant quotes),然后要求它基于所引用的信息来回答问题,这使得我们能根据答案追溯源文档,通常对减少幻觉非常有帮助。" ] }, { @@ -1186,7 +1166,8 @@ "metadata": {}, "source": [ "**关于反斜杠使用的说明:**\n", - "在本教程中,我们使用反斜杠 \\ 来使文本适应屏幕大小以提高阅读体验,而没有用换行符\"\\n\"。GPT-3 并不受换行符(newline characters)的影响,但在你调用其他大模型时,需额外考虑换行符是否会影响模型性能" + "\n", + "在本教程中,我们使用反斜杠 \\ 来使文本适应屏幕大小以提高阅读体验,而没有用换行符 \\n 。GPT-3 并不受换行符(newline characters)的影响,但在您调用其他大模型时,需额外考虑换行符是否会影响模型性能。" ] } ], diff --git a/content/Prompt Engineering/3. 迭代优化 Iterative.ipynb b/content/Prompt Engineering/3. 迭代优化 Iterative.ipynb index fb3d94c..f802249 100644 --- a/content/Prompt Engineering/3. 迭代优化 Iterative.ipynb +++ b/content/Prompt Engineering/3. 迭代优化 Iterative.ipynb @@ -1,30 +1,19 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "# 迭代式提示开发\n", + "# 第三章 迭代式开发\n", "\n", - "当使用 LLM 构建应用程序时,我从来没有在第一次尝试中就成功使用最终应用程序中所需的 Prompt。但这并不重要,只要您有一个好的迭代过程来不断改进您的 Prompt,那么你就能够得到一个适合任务的 Prompt。我认为在提示方面,第一次成功的几率可能会高一些,但正如上所说,第一个提示是否有效并不重要。最重要的是为您的应用程序找到有效提示的过程。\n", - "\n", - "因此,在本章中,我们将以从产品说明书中生成营销文案这一示例,展示一些框架,以提示你思考如何迭代地分析和完善你的 Prompt。\n", - "\n", - "如果您之前与我一起上过机器学习课程,您可能见过我使用的一张图表,说明了机器学习开发的流程。通常是先有一个想法,然后再实现它:编写代码,获取数据,训练模型,这会给您一个实验结果。然后您可以查看输出结果,进行错误分析,找出它在哪里起作用或不起作用,甚至可以更改您想要解决的问题的确切思路或方法,然后更改实现并运行另一个实验等等,反复迭代,以获得有效的机器学习模型。在编写 Prompt 以使用 LLM 开发应用程序时,这个过程可能非常相似,您有一个关于要完成的任务的想法,可以尝试编写第一个 Prompt,满足上一章说过的两个原则:清晰明确,并且给系统足够的时间思考。然后您可以运行它并查看结果。如果第一次效果不好,那么迭代的过程就是找出为什么指令不够清晰或为什么没有给算法足够的时间思考,以便改进想法、改进提示等等,循环多次,直到找到适合您的应用程序的 Prompt。\n" - ] - }, - { -======= - "# 第三章 迭代式提示词开发\n", - "\n", - "当使用 LLM 构建应用程序时,实践层面上很难第一次尝试就成功获得适合最终应用的 Prompt。但这并不重要,只要您有一个好的迭代过程来不断改进您的 Prompt,那么您就能够得到一个适合任务的 Prompt。虽然相比训练机器学习模型,在提示词方面一次成功的几率可能会高一些,但正如上所说,第一版提示词是否有效并不重要。最重要的是**层层迭代**为您的应用程序找到有效提示词的过程。\n", + "当使用 LLM 构建应用程序时,实践层面上很难*第一次尝试*就成功获得适合最终应用的 Prompt。但这并不重要,只要您有一个好的迭代过程来不断改进您的 Prompt,那么您就能够得到一个适合任务的 Prompt。虽然相比训练机器学习模型,在 Prompt 方面一次成功的几率可能会高一些,但正如上所说, Prompt 是否一次完善并不重要。最重要的是**层层迭代**为您的应用程序找到有效 Prompt 的过程。\n", "\n", "因此在本章中,我们将以产品说明书中生成营销文案为例,来展示一些流程框架,并提示您思考如何层层迭代地分析和完善您的 Prompt。\n", "\n", - "在吴恩达(Andrew Ng,原教程作者)的机器学习课程中展示过一张图表,说明了机器学习开发的流程。通常是先有一个想法,然后再用以下流程实现:编写代码,获取数据,训练模型,获得实验结果。然后您可以查看结果,分析误差与错误,找出适用领域,甚至可以更改您对具体问题的具体思路或解决方法。此后再次更改实现,并运行另一个实验等,反复迭代,最终获得有效的机器学习模型。在编写基于 LLM 的应用程序的 Prompt 时,流程可能非常相似。您产生了关于要完成的任务的想法后,可以尝试编写第一个 Prompt ,注意要满足上一章说过的两个原则:**清晰明确,并且给系统足够的时间思考**。然后您可以运行并查看结果。如果第一次效果不好,那么迭代的过程就是找出为什么指令不够清晰或为什么没有给算法足够的时间思考,以便改进想法、改进提示词等等,循环多次,直到找到适合您的应用程序的 Prompt。\n", + "在吴恩达(Andrew Ng,原教程作者)的机器学习课程中展示过一张图表,说明了机器学习开发的流程。通常是先有一个想法,然后再用以下流程实现:编写代码,获取数据,训练模型,获得实验结果。然后您可以查看结果,分析误差与错误,找出适用领域,甚至可以更改您对具体问题的具体思路或解决方法。此后再次更改实现,并运行另一个实验等,反复迭代,最终获得有效的机器学习模型。在编写基于 LLM 的应用程序的 Prompt 时,流程可能非常相似。您产生了关于要完成的任务的想法后,可以尝试编写第一个 Prompt ,注意要满足上一章说过的两个原则:**清晰明确,并且给系统足够的时间思考**。然后您可以运行并查看结果。如果第一次效果不好,那么迭代的过程就是找出为什么指令不够清晰或为什么没有给算法足够的时间思考,以便改进想法、改进 Prompt 等等,循环多次,直到找到适合您的应用程序的 Prompt。\n", "\n", - "很难有适用于世间万物的所谓“最佳提示词”,更好的方法是找到有效的迭代过程,以便您可以快速地找到一个适合您的应用程序的提示词。\n" + "很难有适用于世间万物的所谓“最佳 Prompt ”,更好的方法是找到有效的迭代过程,以便您可以快速地找到一个适合您的应用程序的 Prompt 。\n" ] }, { @@ -33,13 +22,13 @@ "source": [ "
\n", " \n", @@ -48,7 +37,6 @@ }, { "attachments": {}, ->>>>>>> Stashed changes "cell_type": "markdown", "metadata": {}, "source": [ @@ -84,7 +72,7 @@ "# 一个封装 OpenAI 接口的函数,参数为 Prompt,返回对应结果\n", "def get_completion(prompt, model=\"gpt-3.5-turbo\"):\n", " '''\n", - " prompt: 对应的提示\n", + " prompt: 对应的提示词\n", " model: 调用的模型,默认为 gpt-3.5-turbo(ChatGPT),有内测资格的用户可以选择 gpt-4\n", " '''\n", " messages = [{\"role\": \"user\", \"content\": prompt}]\n", @@ -98,6 +86,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -105,14 +94,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "这里有一个椅子的产品说明书,描述说它是一个中世纪灵感家族的一部分,讨论了构造、尺寸、椅子选项、材料等等,产地是意大利。假设您想要使用这份说明书帮助营销团队为在线零售网站撰写营销式描述" -======= "给定一份椅子的资料页。描述说它属于*中世纪灵感*系列,产自意大利,并介绍了材料、构造、尺寸、可选配件等参数。假设您想要使用这份说明书帮助营销团队为电商平台撰写营销描述稿:" ->>>>>>> Stashed changes ] }, { @@ -186,7 +172,7 @@ } ], "source": [ - "# 提示:基于说明书生成营销描述\n", + "# Prompt :基于说明书生成营销描述\n", "prompt = f\"\"\"\n", "Your task is to help a marketing team create a \n", "description for a retail website of a product based \n", @@ -277,7 +263,7 @@ } ], "source": [ - "# 提示:基于说明书创建营销描述\n", + "# Prompt :基于说明书创建营销描述\n", "prompt = f\"\"\"\n", "您的任务是帮助营销团队基于技术说明书创建一个产品的营销描述。\n", "\n", @@ -290,16 +276,15 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## 2.1 问题一:生成文本太长\n", "\n", - "它似乎很好地写了一个描述,介绍了一个惊人的中世纪灵感办公椅,很好地完成了要求,即从技术说明书开始编写产品描述。但是当我看到这个时,我会觉得这个太长了。\n", + "它似乎很好地完成了要求,即从技术说明书开始编写产品描述,介绍了一个精致的中世纪风格办公椅。但是当我看到这个时,我会觉得这个太长了。\n", "\n", - "所以我有了一个想法。我写了一个提示,得到了结果。但是我对它不是很满意,因为它太长了,所以我会澄清我的提示,并说最多使用50个字。\n", - "\n", - "因此,我通过要求它限制生成文本长度来解决这一问题" + "所以在上述过程中,我产生想法后写了一个 Prompt ,并得到了结果,但是我对它不是很满意,因为它太长了。所以我澄清我的 Prompt ,要求它限制生成文本长度,要求最多使用50个字。\n" ] }, { @@ -335,10 +320,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "取出回答并根据空格拆分,答案为54个字,较好地完成了我的要求" + "提取回答并根据空格拆分,答案为54个字,较好地完成了设计要求。" ] }, { @@ -411,27 +397,24 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ -<<<<<<< Updated upstream - "LLM在遵循非常精确的字数限制方面表现得还可以,但并不那么出色。有时它会输出60或65个单词的内容,但这还算是合理的。这原因是 LLM 解释文本使用一种叫做分词器的东西,但它们往往在计算字符方面表现一般般。有很多不同的方法来尝试控制你得到的输出的长度。" -======= - "LLM在遵循非常精确的字数限制方面表现得还可以,但并不那么出色。有时它会输出60或65个单词的内容,但这也还算合理。这原因是 LLM 使用分词器(tokenizer)解释文本,但它们往往在计算字符方面表现一般般。有很多不同的方法来尝试控制您得到的输出的长度(如xx句话/词/个汉字/个字母 (characters) 等)。" ->>>>>>> Stashed changes - ] + "source": [] }, { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "LLM在能堪堪胜任严格的字数限制,但实现得并不精确。此例中,英文输出要求控制在50个词,但有时会输出60或65个单词的内容,但这也还算合理。原因是 LLM 使用分词器(tokenizer)解释文本,但它们往往在计算字符方面表现一般般。有很多不同的方法来尝试控制您得到的输出的长度(如若干句话/词/个汉字/个字母 (characters) 等)。" + ] + }, + { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "## 问题二:文本关注在错误的细节上\n", - "\n", - "我们会发现的第二个问题是,这个网站并不是直接向消费者销售,它实际上旨在向家具零售商销售家具,他们会更关心椅子的技术细节和材料。在这种情况下,你可以修改这个提示,让它更精确地描述椅子的技术细节。\n", -======= "## 2.2 问题二:抓错文本细节\n", "\n", - "我们继续完善这段推广词,会发现的第二个问题是,这个网站并不是直接向消费者销售,它实际上面向的是家具零售商,他们会更关心椅子的技术细节和材料。在这种情况下,您可以继续修改这个提示词,让它更精确地描述椅子的技术细节。\n", ->>>>>>> Stashed changes + "我们继续完善这段推广词,会发现的第二个问题是,这个网站并不是直接向消费者销售,它实际上面向的是家具零售商,他们会更关心椅子的技术细节和材料。在这种情况下,您可以继续修改这个 Prompt ,让它更精确地描述椅子的技术细节。\n", "\n", "解决方法:要求它专注于与目标受众相关的方面。" ] @@ -503,10 +486,18 @@ ] }, { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "我可能进一步想要在描述的结尾包括产品ID。因此,我可以进一步改进这个提示,要求在描述的结尾,包括在技术说明中的每个7个字符产品ID。" + "可见,通过修改 Prompt ,模型的关注点倾向了具体特征与技术细节。\n", + "\n", + "我可能进一步想要在描述的结尾展示出产品ID。因此,我可以进一步改进这个 Prompt ,要求在描述的结尾,展示出说明书中的7位产品ID。" ] }, { @@ -583,16 +574,6 @@ ] }, { -<<<<<<< Updated upstream - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 问题三:需要一个表格形式的描述\n", - "\n", - "以上是许多开发人员通常会经历的迭代提示开发的简短示例。我的建议是,像上一章中所演示的那样,Prompt 应该保持清晰和明确,并在必要时给模型一些思考时间。在这些要求的基础上,通常值得首先尝试编写 Prompt ,看看会发生什么,然后从那里开始迭代地完善 Prompt,以逐渐接近所需的结果。因此,许多成功的Prompt都是通过这种迭代过程得出的。我将向您展示一个更复杂的提示示例,可能会让您对ChatGPT的能力有更深入的了解。\n", - "\n", - "这里我添加了一些额外的说明,要求它抽取信息并组织成表格,并指定表格的列、表名和格式,还要求它将所有内容格式化为可以在网页使用的 HTML。" -======= "cell_type": "markdown", "metadata": {}, "source": [] @@ -601,7 +582,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "以上是许多开发人员通常会经历的提示词开发的迭代过程简短示例。我的建议是,像上一章中所演示的那样,Prompt 应该保持清晰和明确,并在必要时给模型一些思考时间。在这些要求的基础上,通常值得首先尝试编写一版 Prompt ,看看会发生什么,然后继续迭代完善 Prompt,以逐渐接近所需的结果。许多成功的 Prompt 都是通过这种迭代过程得出的。我将向您展示一个更复杂的提示词示例,可能会让您对 ChatGPT 的能力有更深入的了解。" + "以上是许多开发人员通常会经历的 Prompt 开发的迭代过程简短示例。我的建议是,像上一章中所演示的那样,Prompt 应该保持清晰和明确,并在必要时给模型一些思考时间。在这些要求的基础上,常见流程是首先尝试编写一版 Prompt ,看看会发生什么,然后继续迭代完善 Prompt,以逐渐接近所需的结果。许多成功的 Prompt 都是通过这种迭代过程得出的。我将向您展示一个更复杂的 Prompt 示例,可能会让您对 ChatGPT 的能力有更深入的了解。" ] }, { @@ -610,9 +591,7 @@ "metadata": {}, "source": [ "## 2.3 问题三:添加表格描述\n", - "\n", - "继续添加指引,要求提取产品尺寸信息,组织成表格,并指定表格的列、表名和格式;将所有内容格式化为可以在网页使用的 HTML。" ->>>>>>> Stashed changes + "继续添加指引,要求提取产品尺寸信息并组织成表格,并指定表格的列、表名和格式;再将所有内容格式化为可以在网页使用的 HTML。" ] }, { @@ -877,18 +856,20 @@ ] }, { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "本章的主要内容是 LLM 在开发应用程序中的迭代式提示开发过程。开发者需要先尝试编写提示,然后通过迭代逐步完善它,直至得到需要的结果。关键在于拥有一种有效的开发Prompt的过程,而不是知道完美的Prompt。对于一些更复杂的应用程序,可以对多个样本进行迭代开发提示并进行评估。最后,可以在更成熟的应用程序中测试多个Prompt在多个样本上的平均或最差性能。在使用 Jupyter 代码笔记本示例时,请尝试不同的变化并查看结果。" -======= - "本章的主要内容是在开发基于 LLM 的应用程序中的**迭代式**提示词开发过程。开发者需要先尝试编写提示词,然后通过迭代逐步完善它,直至得到需要的结果。作为一名高效的提示词工程师(Prompt Engineer),关键在于掌握有效的开发Prompt的过程,而不是去寻求得到“完美的” Prompt 。对于一些更复杂的应用程序,可以对多个样本(如数百张说明书)进行提示词的迭代开发,并在样本集上进行评估。\n", + "本章的主要内容是 LLM 在开发应用程序中的迭代式 Prompt 开发过程。开发者需要先尝试编写 Prompt ,然后通过迭代逐步完善它,直至得到需要的结果。作为一名高效的提示词工程师(Prompt Engineer),关键在于掌握有效的开发Prompt的过程,而不是去寻求得到“完美的”Prompt。对于一些更复杂的应用程序,可以对多个样本(如数百张说明书)进行 Prompt 的迭代开发,并在样本集上进行评估。\n", "\n", "最后,在更成熟的应用程序中,可以观察多个Prompt在多个样本集上的表现,测试平均或最差性能。但通常,**仅当**应用较成型之后,才推荐您通过这种评估方式,来精益求精。\n", "\n", "请使用 Jupyter Notebook,动手实践本节给出的示例,并尝试不同的变化,查看结果。" ->>>>>>> Stashed changes ] } ], diff --git a/content/Prompt Engineering/4. 文本概括 Summarizing.ipynb b/content/Prompt Engineering/4. 文本概括 Summarizing.ipynb index 8c390e5..74f9173 100644 --- a/content/Prompt Engineering/4. 文本概括 Summarizing.ipynb +++ b/content/Prompt Engineering/4. 文本概括 Summarizing.ipynb @@ -1,6 +1,7 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "id": "b58204ea", "metadata": {}, @@ -10,54 +11,52 @@ }, { "cell_type": "markdown", - "id": "c3182141", + "id": "a190d6a1", "metadata": {}, "source": [ "
\n", - " \n", + " \n", "
" ] }, { + "attachments": {}, "cell_type": "markdown", "id": "b70ad003", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "## 1 引言" + "## 一、引言" ] }, { + "attachments": {}, "cell_type": "markdown", "id": "12fa9ea4", "metadata": {}, "source": [ - "当今世界上有太多的文本信息,几乎没有人能够拥有足够的时间去阅读所有我们想了解的东西。但令人感到欣喜的是,目前LLM在文本概括任务上展现了强大的水准,也已经有不少团队将这项功能插入了自己的软件应用中。\n", -======= - "## 一、引言\n", "当今世界上文本信息浩如烟海,我们很难拥有足够的时间去阅读所有想了解的东西。但欣喜的是,目前LLM在文本概括任务上展现了强大的水准,也已经有不少团队将概括功能实现在多种应用中。\n", ->>>>>>> Stashed changes "\n", "本章节将介绍如何使用编程的方式,调用API接口来实现“文本概括”功能。" ] }, { + "attachments": {}, "cell_type": "markdown", "id": "1de4fd1e", "metadata": {}, "source": [ - "首先,我们需要 OpenAI 包,加载 API 密钥,定义 getCompletion 函数。" + "首先,我们需要引入 OpenAI 包,加载 API 密钥,定义 getCompletion 函数。" ] }, { @@ -83,22 +82,25 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "9cca835b", "metadata": {}, "source": [ - "## 二、单一文本概括实验" + "## 二、单一文本概括" ] }, { + "attachments": {}, "cell_type": "markdown", "id": "0c1e1b92", "metadata": {}, "source": [ - "这里我们举了个商品评论的例子。对于电商平台来说,网站上往往存在着海量的商品评论,这些评论反映了所有客户的想法。如果我们拥有一个工具去概括这些海量、冗长的评论,便能够快速地浏览更多评论,洞悉客户的偏好,从而指导平台与商家提供更优质的服务。" + "以商品评论的总结任务为例:对于电商平台来说,网站上往往存在着海量的商品评论,这些评论反映了所有客户的想法。如果我们拥有一个工具去概括这些海量、冗长的评论,便能够快速地浏览更多评论,洞悉客户的偏好,从而指导平台与商家提供更优质的服务。" ] }, { + "attachments": {}, "cell_type": "markdown", "id": "9dc2e2bc", "metadata": {}, @@ -126,6 +128,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "aad5bd2a", "metadata": {}, @@ -149,6 +152,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "662c9cd2", "metadata": {}, @@ -157,6 +161,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "a6d10814", "metadata": {}, @@ -194,6 +199,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "0df0eb90", "metadata": {}, @@ -217,7 +223,7 @@ ], "source": [ "prompt = f\"\"\"\n", - "你的任务是从电子商务网站上生成一个产品评论的简短摘要。\n", + "您的任务是从电子商务网站上生成一个产品评论的简短摘要。\n", "\n", "请对三个反引号之间的评论文本进行概括,最多30个词汇。\n", "\n", @@ -229,6 +235,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "e9ab145e", "metadata": {}, @@ -237,6 +244,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "f84d0123", "metadata": {}, @@ -247,11 +255,12 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "d6f8509a", "metadata": {}, "source": [ - "**侧重于运输**" + "**侧重于快递服务**" ] }, { @@ -286,6 +295,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "0bd4243a", "metadata": {}, @@ -309,7 +319,7 @@ ], "source": [ "prompt = f\"\"\"\n", - "你的任务是从电子商务网站上生成一个产品评论的简短摘要。\n", + "您的任务是从电子商务网站上生成一个产品评论的简短摘要。\n", "\n", "请对三个反引号之间的评论文本进行概括,最多30个词汇,并且聚焦在产品运输上。\n", "\n", @@ -321,6 +331,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "76c97fea", "metadata": {}, @@ -329,6 +340,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "83275907", "metadata": {}, @@ -369,6 +381,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "cf54fac4", "metadata": {}, @@ -392,7 +405,7 @@ ], "source": [ "prompt = f\"\"\"\n", - "你的任务是从电子商务网站上生成一个产品评论的简短摘要。\n", + "您的任务是从电子商务网站上生成一个产品评论的简短摘要。\n", "\n", "请对三个反引号之间的评论文本进行概括,最多30个词汇,并且聚焦在产品价格和质量上。\n", "\n", @@ -404,16 +417,7 @@ ] }, { -<<<<<<< Updated upstream -======= - "cell_type": "markdown", - "id": "6a5fe085", - "metadata": {}, - "source": [] - }, - { "attachments": {}, ->>>>>>> Stashed changes "cell_type": "markdown", "id": "972dbb1b", "metadata": {}, @@ -422,6 +426,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "b3ed53d2", "metadata": {}, @@ -430,11 +435,12 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "ba6f5c25", "metadata": {}, "source": [ - "在2.2节中,虽然我们通过添加关键角度侧重的Prompt,使得文本摘要更侧重于某一特定方面,但是可以发现,结果中也会保留一些其他信息,如价格与质量角度的概括中仍保留了“快递提前到货”的信息。如果我们只想要提取某一角度的信息,并过滤掉其他所有信息,则可以要求LLM进行“文本提取(Extract)”而非“概括(Summarize)”。" + "在2.2节中,虽然我们通过添加关键角度侧重的 Prompt ,使得文本摘要更侧重于某一特定方面,但是可以发现,结果中也会保留一些其他信息,如偏重价格与质量角度的概括中仍保留了“快递提前到货”的信息。如果我们只想要提取某一角度的信息,并过滤掉其他所有信息,则可以要求 LLM 进行“文本提取( Extract )”而非“概括( Summarize )”" ] }, { @@ -469,6 +475,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "0339b877", "metadata": {}, @@ -492,7 +499,7 @@ ], "source": [ "prompt = f\"\"\"\n", - "你的任务是从电子商务网站上的产品评论中提取相关信息。\n", + "您的任务是从电子商务网站上的产品评论中提取相关信息。\n", "\n", "请从以下三个反引号之间的评论文本中提取产品运输相关的信息,最多30个词汇。\n", "\n", @@ -504,27 +511,21 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "50498a2b", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "## 3 多条文本概括Prompt实验" -======= "## 三、同时概括多条文本" ->>>>>>> Stashed changes ] }, { + "attachments": {}, "cell_type": "markdown", "id": "a291541a", "metadata": {}, "source": [ -<<<<<<< Updated upstream - "在实际的工作流中,我们往往有许许多多的评论文本,以下展示了一个基于for循环调用“文本概括”工具并依次打印的示例。当然,在实际生产中,对于上百万甚至上千万的评论文本,使用for循环也是不现实的,可能需要考虑整合评论、分布式等方法提升运算效率。" -======= - "在实际的工作流中,我们往往有许许多多的评论文本,以下示例将多条用户评价放进列表,并利用 for 循环,使用文本概括(Summarize)提示词,将评价概括至小于20词,并按顺序打印。当然,在实际生产中,对于不同规模的评论文本,除了使用 for 循环以外,还可能需要考虑整合评论、分布式等方法提升运算效率。您可以搭建主控面板,来总结大量用户评论,来方便您或他人快速浏览,还可以点击查看原评论。这样您能高效掌握顾客的所有想法。" ->>>>>>> Stashed changes + "在实际的工作流中,我们往往有许许多多的评论文本,以下示例将多条用户评价放进列表,并利用 ```for``` 循环,使用文本概括(Summarize)提示词,将评价概括至小于 20 词,并按顺序打印。当然,在实际生产中,对于不同规模的评论文本,除了使用 ```for``` 循环以外,还可能需要考虑整合评论、分布式等方法提升运算效率。您可以搭建主控面板,来总结大量用户评论,来方便您或他人快速浏览,还可以点击查看原评论。这样您能高效掌握顾客的所有想法。" ] }, { @@ -631,7 +632,7 @@ "source": [ "for i in range(len(reviews)):\n", " prompt = f\"\"\"\n", - " Your task is to generate a short summary of a product \\ \n", + " Your task is to generate a short summary of a product \\\n", " review from an ecommerce site. \n", "\n", " Summarize the review below, delimited by triple \\\n", @@ -646,7 +647,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ccf14427", + "id": "eb878522", "metadata": {}, "outputs": [], "source": [ @@ -656,7 +657,7 @@ "\n", " 请对三个反引号之间的评论文本进行概括,最多20个词汇。\n", "\n", - " 评论: ```{reviews[i]}```\n", + " 评论文本: ```{reviews[i]}```\n", " \"\"\"\n", " response = get_completion(prompt)\n", " print(i, response, \"\\n\")\n" @@ -664,7 +665,7 @@ }, { "cell_type": "markdown", - "id": "c1616fdb", + "id": "d757b389", "metadata": {}, "source": [ "**回答暂缺**"