【AI】如何更好地写Prompt engineering(译)

137 阅读26分钟

获得更好的结果的六种策略

写清楚指令

1、策略:在你的查询中包含详细信息,以获得更多相关的答案

WroseBetter
如何在Excel中添加数字?如何在Excel中将一行美元金额相加?我想对一整行自动执行此操作,所有总数都位于名为“总计”的列的右侧。
谁是总统?谁是 2021 年墨西哥总统,选举多久举行一次?
编写代码来计算斐波那契数列编写一个 TypeScript 函数来有效地计算斐波那契数列。对代码进行大量注释,以解释每篇文章的作用以及为什么这样编写。
总结会议记录。在单个段落中总结会议记录。然后写一个演讲者的markdown列表和他们的每个关键点。最后,列出演讲者建议的后续步骤或行动项目(如果有)。

2、策略:要求model采用角色

系统消息可用指定模型在回复中使用的角色

角色描述
系统当我请求帮助写一些东西时,你会回复一份文件,每个段落中至少包含一个笑话或俏皮的评论
用户给我的钢螺栓供应商写一封感谢信,感谢他们在短时间内按时交货。这使我们能够交付一个重要的订单。

体验地址

3、策略:使用分隔符清楚地指示输入的不同部分

三引号、XML标记、章节标题等分隔符可以帮助划分要区别对待的文本部分

用户用俳句总结三引号分割的文本. """在此处插入文本"""
体验地址
系统您将获得两篇关于同一主题的文章(用 XML 标记分隔)。首先总结每篇文章的论点。然后指出他们中哪一个提出了更好的论点并解释原因。
用户<article> 在此处插入第一篇文章 </article> <article> 在此处插入第二篇文章 </article>
体验地址
系统您将获得论文摘要和建议的标题。论文标题应该让读者对论文的主题有一个很好的了解,但也应该引人注目。如果标题不符合这些标准,请建议 5 个备选方案。
用户摘要:在此处插入摘要 标题:在此处插入标题
体验地址

对于简单明了的任务,使用分隔符可能不会对输出质量产生影响。但是,任务越复杂,对任务细节消除其实就越重要。不让模型费力地理解您在要求什么

4、策略:明确完成任务所有的步骤

某些任务最好指定一系列步骤。清楚地列出步骤可以让模型更容易遵循

系统使用以下分步说明来响应用户输入。 第 1 步 - 用户将为您提供三引号的文本。用一句话总结这段文字,前缀是“摘要:”。第 2 步 - 将第 1 步中的摘要翻译成西班牙语,前缀为“翻译:”。
用户"""在此处插入文本"""
体验地址

5、策略:举例说明

提供适用于所有示例的一般说明通常比通过演示任务的所有排列组合更有效率,但在某些情况下,提供示例可能更容易。例如,如果你打算让模型复制一种难以描述的响应用户查询的特定样式,这就是所谓的"少量"提示

系统以一致的风格回答
用户教我忍耐
助手雕刻最深谷的河流从朴素的泉水流出;最宏伟的交响乐起源于一个音符;最复杂的挂毯始于一根孤独的线。
用户教我关于海洋的知识
体验地址

6、策略:指定所需的输出长度

您可以要求模型生成给定目标长度的输出。目标长度可以根据单词、句子、段落、项目符号的数量来制定。但是请注意,指定模型生成特定数量的单词不能高精度地工作。该模型可以更可靠生成特定段落数或者要点数的输出结果。

用户用大约 50 个单词总结用三引号分隔的文本。"""在此插入文本"""
体验地址
用户在 2 段中总结用三引号分隔的文本。"""在此插入文本"""
体验地址
用户在 3 个要点中总结用三引号分隔的文本"""在此插入文本"""
体验地址

提供参考文本

1、策略:指示模型使用参考文本进行回答

如果我们可以为模型提供与当前查询相关的可信信息,那么我们可以指示模型使用提供的信息来编写其答案

系统使用提供的以三引号分隔的文章来回答问题。如果在文章中找不到答案,请写下“我找不到答案”
用户<插入文章,每篇文章用三引号分隔> 问题:<在此处插入问题>
体验地址

鉴于所有模型的上下文窗口都有限,我们需要某种方法来动态查找与所提出问题相关的信息。嵌入可用于实现高效的知识检索。有关如何实现此操作的更多详细信息,请参阅策略“使用基于嵌入的搜索实现高效的知识检索”

2、策略:指示模型使用参考文本的引用来回答

如果输入已补充了相关知识,则直接要求模型通过引用所提供文档中的段落来在其答案中添加引用。请注意,输出中的引文可以通过所提供文档中的字符串匹配以编程方式进行验证。

系统您将获得一份以三引号分隔的文档和一个问题。您的任务是仅使用提供的文档回答问题,并引用用于回答问题的文档的段落。如果文档不包含回答此问题所需的信息,则只需写:“信息不足”。如果提供了问题的答案,则必须用引文进行注释。使用以下格式引用相关段落 ({“citation”: ...})。
用户“”“<在此处插入文件>”“” 问题:<在此处插入问题>
体验地址

将复杂的任务拆分成更简单的子任务

1、 策略:使用意图分类来识别与用户查询最相关的指令

对于需要大量独立指令集来处理不同情况的任务,首先对查询类型进行分类并使用该分类来确定需要哪些指令可能是有益的。这可以通过定义与处理给定类别中的任务相关的固定类别和硬编码指令来实现。此过程也可以递归地应用,以将任务分解为一系列阶段。此方法的优点是,每个查询将仅包含执行任务下一阶段所需的指令,与使用单个查询执行整个任务相比,这可能会导致更低的错误率。这还可以降低成本,因为较大的提示运行成本更高(请参阅定价信息)。

例如,假设对于客户服务应用程序,查询可以按以下方式进行有用的分类:

系统: 您将获得客户服务查询。将每个查询分为主要类别和次要类别。以 json 格式提供输出,其中包含以下键:primary 和 secondary。

  • 主要类别:计费、技术支持、帐户管理或一般查询。
  • 计费次要类别
    • 取消订阅或升级
    • 添加付款方式
    • 收费说明
    • 对指控提出异议
  • 技术支持二级类别
    • 故障排除
    • 设备兼容性
    • 软件更新
  • 账户管理二级类别:
    • 密码重置
    • 更新个人信息
    • 关闭账户
    • 账户安全
  • 一般查询二级类别:
    • 产品信息
    • 定价
    • 反馈
    • 与人交谈

用户: 我需要让我的互联网再次工作。

根据客户查询的分类,可以向模型提供一组更具体的指令,以便其处理后续步骤。例如,假设客户需要“故障排除”方面的帮助。

系统

您将获得需要在技术支持上下文中进行故障排除的客户服务查询。通过以下方式帮助用户:

  • 要求他们检查与路由器之间的所有电缆是否已连接。请注意,电缆会随着时间的推移而松动。
  • 如果所有电缆都已连接,但问题仍然存在,请询问他们使用的路由器型号
    • 现在,您将建议他们如何重新启动设备:
    • 如果型号为 MTD-327J,建议他们按下红色按钮并按住 5 秒钟,然后等待 5 分钟再测试连接。
    • 如果型号为 MTD-327S,建议他们拔下并重新插入,然后等待 5 分钟再测试连接。
  • 如果客户的问题在重新启动设备并等待 5 分钟后仍然存在,请通过输出 {“IT support requested”} 将他们连接到 IT 支持。
  • 如果用户开始提出与此主题无关的问题,请确认他们是否要结束有关故障排除的当前聊天,并根据以下方案对其请求进行分类:

<在此处插入上面的一级/二级分类方案>

用户

我需要让我的互联网再次工作。

体验地址

请注意,已指示模型发出特殊字符串,以指示会话状态何时更改。这使我们能够将我们的系统变成一个状态机,其中状态决定了注入哪些指令。通过跟踪状态、在该状态下相关的指令,以及可选地允许从该状态转换哪些状态,我们可以在用户体验周围设置护栏,而这些护栏是用结构化程度较低的方法难以实现的。

2、策略:对于需要很长对话的对话应用程序,总结或过滤之前的对话

由于模型具有固定的上下文长度,因此用户和助手之间的对话(其中整个对话都包含在上下文窗口中)不能无限期地继续。

这个问题有多种解决方法,其中之一是总结对话中的前几轮。一旦输入的大小达到预定的阈值长度,这可能会触发一个查询,该查询汇总了部分对话,并且可以将先前对话的摘要作为系统消息的一部分包含在内。或者,可以在整个对话过程中在后台异步总结先前的对话。

另一种解决方案是动态选择与当前查询最相关的对话的先前部分。请参阅策略“使用基于嵌入的搜索实现高效的知识检索”。

3、策略:分段总结长文档,并递归地构建完整的摘要

由于模型具有固定的上下文长度,因此它们不能用于汇总文本,其长度超过上下文长度减去单个查询中生成的摘要的长度。

要总结一个很长的文档,比如一本书,我们可以使用一系列查询来总结文档的每个部分。章节摘要可以串联和汇总,从而生成摘要的摘要。此过程可以递归进行,直到汇总整个文档。如果有必要使用有关前面部分的信息来理解后面的部分,那么另一个有用的技巧是包括书中任何给定点之前的文本的运行摘要,同时总结该点的内容。OpenAI 在之前使用 GPT-3 变体的研究中研究了此程序总结书籍的有效性。

给模型时间"思考"

1、策略:在匆忙得出结论之前,指示模型制定自己的解决方案

有时,当我们明确指示模型在得出结论之前从第一性原理进行推理时,我们会得到更好的结果。例如,假设我们想要一个模型来评估学生对数学问题的解决方案。解决这个问题的最明显方法是简单地询问模型学生的解决方案是否正确。

**系统**: 确定学生的解决方案是否正确。

**用户**:问题陈述
我正在建造太阳能发电装置,需要帮助计算财务。
- 土地每平方英尺100美元
- 太阳能板每平方英尺250美元
- 我已经谈好的维护合同每年固定费用10万美元,另外每平方英尺额外费用10美元
第一年运营的总成本如何,取决于安装面积。

学生的解决方案:
设 x 为装置的面积(平方英尺)。
费用:
1. 土地费用:100x
2. 太阳能板费用:250x
3. 维护费用:100,000 + 100x
总成本:100x + 250x + 100,000 + 100x = 450x + 100,000

**助手**:学生的答案是正确的

体验地址

但学生的解法其实是不对的!我们可以通过提示模型首先生成自己的解决方案来让模型成功注意到这一点。

**系统**
 首先制定自己的问题解决方案。然后将您的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。在你自己解决问题之前,不要决定学生的解决方案是否正确。
 
**用户**
 
 问题陈述:我正在建造一个太阳能装置,我需要帮助解决财务问题。 
 - 土地成本 $100 / 平方英尺
 - 我可以以 $250/平方英尺的价格购买太阳能电池板 
 - 我协商了一份维护合同,每年将花费我 $100k 美元,以及额外的 $10/平方英尺 
 
 第一年运营的总成本与平方英尺数的函数是多少。
 
 学生的解决方案:设 x 为安装的大小(以平方英尺为单位)。
 1.土地成本:100倍
 2.太阳能电池板成本:250x
 3.维护成本:100,000+100x 
 总成本:100x + 250x + 100,000 + 100x = 450x + 100,000
  
**助手**

设 x 是安装的大小(以平方英尺为单位)。
1.土地成本:100x
2.太阳能电池板成本:250x  
3、维护成本:10万+10x
总成本:100x + 250x + 100000 + 10x = 360x + 100000 

学生的答案不正确。他们在维护成本计算中犯了一个错误,使用了 100x而不是 10x。运营第一年的正确总成本是 360x + 100,000。

体验地址

2、 策略:使用内心独白或一系列查询来隐藏模型的推理过程

前面的策略表明,模型在回答特定问题之前详细推理问题有时很重要。对于某些应用程序,模型用于得出最终答案的推理过程不适合与用户共享。例如,在辅导应用程序中,我们可能希望鼓励学生找出自己的答案,但模型对学生解决方案的推理过程可能会向学生揭示答案。

内心独白是一种可以用来缓解这种情况的策略。内心独白的思想是指示模型将输出中对用户隐藏的部分放入结构化格式中,以便于解析它们。然后,在向用户呈现输出之前,将解析输出,并且仅显示部分输出。

**系统**
  按照以下步骤回答用户查询。
  第 1 步 - 首先制定自己的问题解决方案。不要依赖学生的解决方案,因为它可能是不正确的。将此步骤的所有工作括在三引号 (“”“) 中。 
  第 2 步 - 将您的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。将此步骤的所有工作括在三引号 (“”“) 中。 
  第 3 步 - 如果学生犯了错误,请确定您可以在不泄露答案的情况下给学生什么提示。将此步骤的所有工作括在三引号 (“”“) 中。 
  第 4 步 - 如果学生犯了错误,请向学生提供上一步的提示(三引号之外)。而不是写“第 4 步 - ......”写“提示:”。
  
**用户**
 问题陈述:<插入问题陈述> 
 学生解决方案:<插入学生解决方案>

体验地址

或者,这可以通过一系列查询来实现,其中除最后一个查询外的所有查询都对最终用户隐藏其输出。

首先,我们可以要求模型自行解决问题。由于此初始查询不需要学生的解决方案,因此可以省略。这提供了额外的优势,即模型的解决方案不会因学生尝试的解决方案而产生偏差。

**用户**  
  <插入问题陈述>

体验地址

接下来,我们可以让模型使用所有可用信息来评估学生解决方案的正确性。

**系统**
  将您的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。
  
**用户**
  问题陈述:“”“<插入问题陈述>”“” 
  您的解决方案:“”“<插入模型生成的解决方案>”“” 
  学生的解决方案:“”“<插入学生的解决方案>”“”

体验地址

最后,我们可以让模型使用自己的分析来构建一个乐于助人的导师的角色的回复。

**系统**
  你是一名数学导师。如果学生犯了错误,请以不透露答案的方式向学生提供提示。如果学生没有犯错误,只需给他们一个鼓励性的评论。
  
**用户**  
  问题陈述:“”“<插入问题陈述>”“” 
  您的解决方案:“”“<插入模型生成的解决方案>”“”
  学生的解决方案:“”“<插入学生的解决方案>”“”
  分析:“”“<插入上一步生成的模型分析>”“”

体验地址

3、 策略:询问模型在之前的传递中是否遗漏了任何内容

假设我们正在使用一个模型来列出与特定问题相关的来源摘录。在列出每个摘录后,模型需要确定是否应该开始编写另一个摘录,或者是否应该停止编写另一个摘录。如果源文档很大,则模型通常会过早停止并且无法列出所有相关摘录。在这种情况下,通常可以通过提示模型进行后续查询来查找它在先前传递中遗漏的任何摘录来获得更好的性能。

**系统**
您将获得一份以三引号分隔的文档。您的任务是选择与以下问题相关的摘录:“人工智能历史上发生了哪些重大的范式转变。 

确保摘录包含解释它们所需的所有相关上下文 - 换句话说,不要提取缺少重要上下文的小片段。以 JSON 格式提供输出,如下所示: 
[{“摘录”: “...”},
... 
{“摘录”: “...”}]

**用户**  
“”“<在此处插入文件>”“”

**助手**
[{“excerpt”: “模型在这里写了一个摘录”},
... 
{“excerpt”: “模型在这里写了另一个摘录”}]

**用户**
还有更多相关的摘录吗?注意不要重复摘录。还要确保摘录包含解释它们所需的所有相关上下文 - 换句话说,不要提取缺少重要上下文的小片段。

体验地址

使用外部工具

1、策略:使用基于嵌入的搜索实现高效的知识检索

如果模型作为其输入的一部分提供,则可以利用外部信息源。这可以帮助模型生成更明智和最新的响应。例如,如果用户询问有关特定电影的问题,则将有关电影的高质量信息(例如演员、导演等)添加到模型的输入中可能很有用。嵌入可用于实现高效的知识检索,以便在运行时将相关信息动态添加到模型输入中。

文本嵌入是一种向量,可以测量文本字符串之间的相关性。相似或相关的字符串将比不相关的字符串更接近。这一事实,以及快速向量搜索算法的存在,意味着嵌入可用于实现高效的知识检索。特别是,文本语料库可以拆分为块,并且每个块都可以嵌入和存储。然后,可以嵌入给定的查询,并执行向量搜索,以从语料库中找到与查询最相关的嵌入文本块(即在嵌入空间中最接近的文本块)。

可以在 OpenAI Cookbook 中找到示例实现。有关如何使用知识检索来最大程度地减少模型编造错误事实的可能性的示例,请参阅策略“指示模型使用检索到的知识来回答查询”。

2、策略:使用代码执行来执行更准确的计算或调用外部 API

不能依靠语言模型本身准确地执行算术或长计算。在需要的情况下,可以指示模型编写和运行代码,而不是进行自己的计算。特别是,可以指示模型将要运行的代码转换为指定的格式,例如三重反引号。生成输出后,可以提取并运行代码。最后,如有必要,代码执行引擎(即 Python 解释器)的输出可以作为下一个查询的模型输入提供。

**系统**
  您可以通过将 Python 代码括在三反引号中来编写和执行 Python 代码,例如 '''code goes here'''。使用它来执行计算。
  
**用户** 
 求出以下多项式的所有实值根: 3*x**5 - 5*x**4 - 3*x**3 - 7*x - 10.

体验地址

代码执行的另一个很好的用例是调用外部 API。如果指示模型正确使用 API,则可以编写使用它的代码。通过向模型提供演示如何使用 API 的文档和/或代码示例,可以指导模型如何使用 API。

**系统**
  您可以通过将 Python 代码括在三反引号中来编写和执行 Python 代码。另请注意,您可以访问以下模块来帮助用户向他们的朋友发送消息:
  
  python 
  import message 
  message.write(to="John", message="Hey, want to meetup after work?")

体验地址

警告:执行模型生成的代码本身并不安全,在任何试图执行此操作的应用程序中都应采取预防措施。特别是,需要沙盒代码执行环境来限制不受信任的代码可能造成的危害。

3、策略:授予模型对特定函数的访问权限

聊天完成 API 允许在请求中传递函数描述列表。这使模型能够根据提供的架构生成函数参数。生成的函数参数由 API 以 JSON 格式返回,可用于执行函数调用。然后,可以在以下请求中将函数调用提供的输出反馈到模型中以关闭循环。这是使用 OpenAI 模型调用外部函数的推荐方式。要了解更多信息,请参阅我们的介绍性文本生成指南中的函数调用部分,以及 OpenAI Cookbook 中的更多函数调用示例

系统地测试修改

有时很难判断更改(例如,新指令或新设计)是使您的系统变得更好还是更糟。看几个例子可能会暗示哪个更好,但是由于样本量很小,很难区分真正的改进还是随机运气。也许这种变化有助于某些输入的性能,但会损害其他输入的性能。

评估程序(或“评估”)对于优化系统设计非常有用。好的评估是:

  • 代表实际使用(或至少多样化)
  • 包含许多测试用例以获得更高的统计功效(有关指南,请参阅下表)
  • 易于自动化或重复

输出的评估可以由计算机、人类或混合完成。计算机可以使用客观标准(例如,具有单个正确答案的问题)以及一些主观或模糊标准自动进行评估,其中模型输出由其他模型查询评估。OpenAI Evals 是一个开源软件框架,提供用于创建自动评估的工具。

当存在一系列被认为质量同样高的可能输出时,基于模型的评估可能很有用(例如,对于答案较长的问题)。使用基于模型的评估可以实际评估的内容与需要人工评估的内容之间的界限是模糊的,并且随着模型的能力越来越强而不断变化。我们鼓励进行实验,以确定基于模型的评估在您的用例中的效果如何。

策略:参考黄金标准答案评估模型输出

假设已知一个问题的正确答案应该参考一组特定的已知事实。然后,我们可以使用模型查询来计算答案中包含多少所需事实。

例如,使用以下系统消息:

 您将获得由三引号分隔的文本,这应该是问题的答案。检查答案中是否直接包含以下信息: 
 - 尼尔·阿姆斯特朗是第一个在月球上行走的人。 
 - 尼尔·阿姆斯特朗首次登上月球的日期是 1969 年 7 月 21 日。 对于其中每个点,请执行以下步骤:
 1 - 重申这一点。 
 2 - 提供最接近这一点的答案的引文。
 3 - 考虑一个不了解主题的人是否可以直接推断出这一点。在下定决心之前解释原因或为什么不。 
 4 - 如果 3 的答案是肯定的,则写“是”,否则写“否”。 最后,提供有多少个“是”答案的计数。将此计数设置为 {“count”: <在此处插入计数>}。

下面是一个同时满足这两点的示例输入:

**系统**
<在上面插入系统消息>

**用户**
 “”尼尔·阿姆斯特朗(Neil Armstrong)是第一个踏上月球的人。这一历史性事件发生在1969年7月21日阿波罗11号任务期间

体验地址

下面是一个仅满足一个点的示例输入:

**系统**
<在上面插入系统消息>

**用户**
“”尼尔·阿姆斯特朗(Neil Armstrong)走下登月舱时创造了历史,成为第一个在月球上行走的人。

体验地址

下面是一个不满足任何条件的示例输入:

**系统**
 <在上面插入系统消息>
 
**用户**
“”“69年夏天,一次盛大的航行, 阿波罗11号,大胆如传奇之手。 阿姆斯特朗迈出了一步,历史展开了, “一小步,”他说,为了一个新世界。

体验地址

这种基于模型的评估有许多可能的变体。考虑以下变体,该变体跟踪候选答案和黄金标准答案之间的重叠类型,并跟踪候选答案是否与黄金标准答案的任何部分相矛盾。

**系统**
使用以下步骤响应用户输入。在继续之前,请完全重述每个步骤。即“第 1 步:原因......”。 
第 1 步:逐步推理提交的答案中的信息与专家答案相比是:不相交、相等、子集、超集还是重叠(即某些交集但不是子集/超集)。
第 2 步:逐步推理提交的答案是否与专家答案的任何方面相矛盾。
第 3 步:输出一个 JSON 对象,结构如下: {“type_of_overlap”: “disjoint” or “equal” or “subset” or “superset” or “overlapping”, “contradiction”: true or false}

下面是一个示例输入,其答案不合格,但与专家答案并不矛盾:

**系统**
  <在上面插入系统消息>
  
**用户**
问题:“”尼尔·阿姆斯特朗(Neil Armstrong)最出名的事件是什么,发生在什么日期?假设 UTC 时间。
提交的答案:“”“他不是在月球上行走吗?”“” 
专家回答:“”尼尔·阿姆斯特朗(Neil Armstrong)最出名的是成为第一个在月球上行走的人。这一历史性事件发生在1969年7月21日。

体验地址

下面是一个示例输入,其答案与专家答案直接矛盾:

 **系统**
 <在上面插入系统消息>
 
 **用户**
 问题:“”尼尔·阿姆斯特朗(Neil Armstrong)最出名的事件是什么,发生在什么日期?假设 UTC 时间。 
 提交的答案:“”“1969年7月21日,尼尔·阿姆斯特朗成为继巴兹·奥尔德林之后第二个在月球上行走的人。 
 专家回答:“”尼尔·阿姆斯特朗(Neil Armstrong)最出名的是成为第一个在月球上行走的人。这一历史性事件发生在1969年7月21日。

体验地址

下面是一个示例输入,其中包含一个正确答案,该输入还提供了比必要更多的详细信息:

 **系统**
  <在上面插入系统消息>
  
 **用户**
 问题:“”尼尔·阿姆斯特朗(Neil Armstrong)最出名的事件是什么,发生在什么日期?假设 UTC 时间。 
 提交的答案: “”“1969 年 7 月 21 日 02:56 UTC 左右,尼尔·阿姆斯特朗成为第一个踏上月球表面的人,标志着人类历史上的不朽成就。 
 专家回答:“”尼尔·阿姆斯特朗(Neil Armstrong)最出名的是成为第一个在月球上行走的人。这一历史性事件发生在1969年7月21日。

体验地址

原文地址