最好的提示词工程指南
最好的提示词工程指南
ChatGPT已经发布了一年之久了,但你真的会使用ChatGPT吗?同一个问题,不同的问法得到的答案可能千差万别,你可以把ChatGPT当作一个知识面很广的专家,他上知天文下知地理,但他无法直接知道你的意图,因此你需要对它进行引导,即使用提示词来引导它进行思考,从而获取到你真正想要的答案。因此正确掌握写prompt的技巧至关重要,而最好的Prompt教程莫过于OpenAI在官方文档上线的Prompt engineering,也就是提示词工程指南。
0. 导入
在文中,OpenAI提到6条大的原则,分别是:
Write clear instructions(写出清晰的指令)
Provide reference text(提供参考文本)
Split complex tasks into simpler subtasks(将复杂的任务拆分为更简单的子任务)
Give the model time to "think"(给模型思考的时间)
Use external tools(使用外部工具)
Test changes systematically(系统地测试变更)
1. 写出清晰的指令
模型无法直接读懂你的想法。如果ChatGPT输出太长,请要求简短答复。如果输出太简单,请要求专家级别的写作。如果你不喜欢它输出的格式,请可以告诉它你希望看到的格式。模型猜测你想要什么的次数越少,你得到它的可能性就越大。如何写出清晰的指令,OpenAI给出了6条小技巧:
1.1 在查询中包含详细信息以获得更相关的答案
为了获得高度相关的响应,请确保请求提供任何重要的详细信息或上下文。否则,你将让模型来猜测你的意思。例子:
一般的提示词 | 好的提示词 |
---|---|
如何在 Excel 中添加数字? | 如何在 Excel 中添加一行美元金额?我想对整张行自动执行此操作,所有总计都在右侧名为“总计”的列中结束。 |
谁是总统? | 谁是 2023 年美国总统?选举频率如何? |
编写代码来计算斐波那契数列 | 编写一个 TypeScript 函数来高效计算斐波那契数列。并对代码进行注释以解释每部分的作用以及为什么这样编写。 |
总结会议记录 | 用一个段落总结会议记录。然后写下演讲者的 Markdown 列表以及他们的每个要点。最后,列出发言人建议的后续步骤或行动项目(如果有) |
1.2 让模型充当某个角色
你可以让模型扮演一个角色,这样它就会站在这个角色的角度去进行回答问题,得到的答案也会更专业和准确。
比如:充当一个喜欢讲笑话的喜剧演员,每当我当我请求帮助写一些东西时,你会回复一份文档,其中每个段落至少包含一个笑话或有趣的评论。
1.3 使用分隔符清楚地指示输入的不同部分
使用三引号("""""")、XML 标签、节标题等分隔符可以帮助划分要区别对待的文本节。例子:
角色 | 提示词 |
---|---|
系统 | 您将获得两篇关于同一主题的文章(用 XML 标签分隔)。首先总结每篇文章的论点。然后指出哪一个提出了更好的论点并解释原因。 |
用户 | <article> 在此插入第一篇文章 </article> <article> 在此插入第二篇文章 </article> |
对于这些简单任务,使用分隔符可能不会对输出质量产生影响。然而,任务越复杂,消除任务细节的歧义就越重要。
1.4 指定完成任务所需的步骤
有些任务最好指定为一系列步骤。明确地写出这些步骤可以使模型更容易遵循它们。
角色 | 提示词 |
---|---|
系统 | 使用以下分步说明来响应用户输入。步骤1 - 用户将为您提供三引号中的文本。用一个句子总结这段文字,并加上前缀“Summary:”。步骤2 - 将步骤 1 中的摘要翻译成西班牙语,并添加前缀“翻译:”。 |
用户 | """在此插入文字""" |
1.5 提供例子
few-shot prompt,即经典的少样本提示,把例子扔给大模型学习,让大模型按你的例子来进行输出。 比如:请帮我生成类似这样的土味情话:“我最近有点! 忙忙什么? 忙着喜欢你”
1.6 指定输出长度
您可以要求模型生成给定目标长度的输出。目标输出长度可以根据单词、句子、段落、要点等的计数来指定。但如果想惊喜到单词数的话还是比较困难的,但如果是段落个数的话效果还是不错的
2. 提供参考文本
2.1 让模型使用参考文本作答
如果我们可以为模型提供与当前查询相关的可信信息,那么我们可以指示模型使用提供的信息来组成其答案。
角色 | 提示词 |
---|---|
系统 | 使用提供的由三重引号引起来的文章来回答问题。如果在文章中找不到答案,请写“我找不到答案”。 |
用户 | <插入文章,每篇文章均由三引号分隔> 问题:<在此处插入问题> |
2.2 让模型使用参考文本回答
如果输入已补充相关知识,则可以直接要求模型通过引用所提供文档中的段落来为其答案添加引用。请注意,输出中的引用可以通过所提供文档中的字符串匹配以编程方式进行验证。
角色 | 提示词 |
---|---|
系统 | 您将获得一份由三重引号和一个问题分隔的文档。您的任务是仅使用提供的文档回答问题,并引用用于回答问题的文档段落。如果文档不包含回答此问题所需的信息,则只需写:“信息不足”。如果提供了问题的答案,则必须附有引文注释。使用以下格式引用相关段落({“引用”:…})。 |
用户 | <插入文章,每篇文章均由三引号分隔> 问题:<在此处插入问题> |
3. 将复杂的任务拆分为更简单的子任务
原理跟我们自己去解决一个棘手的问题一样,如果一上来就让你解决一个大的问题,你肯定也会手足无措,但如果将复杂的任务拆解成若干个简单的子任务后,大模型就更容易上手,回答得效果也会更好
3.1 使用意图分类来识别与用户查询最相关的指令
3.2 对于需要很长对话的对话应用,总结或过滤之前的对话
由于模型具有固定的上下文长度,因此用户和助手之间的对话(其中整个对话都包含在上下文窗口中)无法无限期地继续。
解决此问题有多种解决方法,其中之一是总结对话中的先前回合。一旦输入的大小达到预定的阈值长度,这可能会触发总结部分对话的查询,并且先前对话的摘要可以作为系统消息的一部分包括在内。或者,可以在整个对话过程中在后台异步总结之前的对话。
另一种解决方案是把过去的所有聊天记录存成向量库,后续跟用户对话的时候动态查询嵌入,大模型动态选择与当前查询最相关的对话的先前部分。
3.3 分段总结长文档并递归构建完整摘要
如果要大模型总结一本书的内容(上百页),肯定是会超过token上限的,所以可以使用一系列查询来总结文档的每个部分。章节摘要可以连接和总结,生成摘要的摘要。这个过程可以递归地进行,直到总结整个文档。
4. 给模型时间“思考”
如果你让模型直接返回答案的话,结果往往会具有随机性,但如果你让它一步步来进行思考的话(即链式思考),大模型返回的结果准确性往往会更高。
4.1 让模型在急于得出结论之前找出自己的解决方案
当我们明确指示模型在得出结论之前从第一原理进行推理时,我们会得到更好的结果。假设我们想要一个模型来评估学生对数学问题的解决方案。解决这个问题最明显的方法是简单地询问模型学生的解决方案是否正确。
角色 | 提示词 |
---|---|
系统 | 确定学生的解决方案是否正确。 |
用户 | 问题陈述:我正在建造一个太阳能发电装置,我需要帮助解决财务问题。- 土地成本为 100 美元/平方英尺 - 我可以以 250 美元/平方英尺的价格购买太阳能电池板 - 我协商了一份维护合同,每年将花费我 10 万美元,另外还要额外花费 10 美元/平方英尺第一年运营作为平方英尺数的函数。学生的解决方案:设 x 为装置的尺寸(以平方英尺为单位)。1. 土地成本:100x 2. 太阳能电池板成本:250x 3. 维护成本:100,000 + 100x 总成本:100x + 250x + 100,000 + 100x = 450x + 100,000 |
助手 | 该学生的解决方案是正确的。 |
但这位同学的解法其实并不正确!我们可以通过提示模型首先生成自己的解决方案来让模型成功注意到这一点。
角色 | 提示词 |
---|---|
系统 | 首先制定自己的问题解决方案。然后将你的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。在你自己完成问题之前,不要决定学生的解决方案是否正确。 |
用户 | 问题陈述:我正在建造一个太阳能发电装置,我需要帮助解决财务问题。- 土地成本为 100 美元/平方英尺 - 我可以以 250 美元/平方英尺的价格购买太阳能电池板 - 我协商了一份维护合同,每年将花费我 10 万美元,另外还要额外花费 10 美元/平方英尺第一年运营作为平方英尺数的函数。学生的解决方案:设 x 为装置的尺寸(以平方英尺为单位)。1. 土地成本:100x 2. 太阳能电池板成本:250x 3. 维护成本:100,000 + 100x 总成本:100x + 250x + 100,000 + 100x = 450x + 100,000 |
助手 | 设 x 为安装尺寸(以平方英尺为单位)。1. 土地成本:100x 2. 太阳能电池板成本:250x 3. 维护成本:100,000 + 10x 总成本:100x + 250x + 100,000 + 10x = 360x + 100,000 学生的解决方案不正确。他们在维护成本计算中犯了一个错误,使用了 100x 而不是 10x。第一年运营的正确总成本是 360x + 100,000。 |
4.2 使用内心独白或一系列查询来隐藏模型的推理过程
前面的策略表明,模型有时在回答特定问题之前详细推理问题很重要。对于某些应用程序,模型用于得出最终答案的推理过程不适合与用户共享。例如,在辅导应用程序中,我们可能希望鼓励学生得出自己的答案,但模型关于学生解决方案的推理过程可能会向学生揭示答案。
内心独白是一种可以用来缓解这种情况的策略。内心独白的想法是指示模型将原本对用户隐藏的部分输出放入结构化格式中,以便于解析它们。然后,在向用户呈现输出之前,将解析输出并且仅使部分输出可见。
角色 | 提示词 |
---|---|
系统 | 请按照以下步骤回答用户的疑问。步骤 1 - 首先找出你自己的问题解决方案。不要依赖学生的解决方案,因为它可能是不正确的。将您此步骤的所有工作用三引号 (""") 括起来。第 2 步 - 将您的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。将您此步骤的所有工作用三引号 ("") 括起来”)。第 3 步 - 如果学生犯了错误,请确定在不泄露答案的情况下可以给学生什么提示。将这一步的所有工作用三引号 (""") 括起来。步骤 4 - 如果学生犯了错误,请向学生提供上一步的提示(在三引号之外)。而不是写“步骤 4 - ...”写“提示:”。 |
用户 | 问题陈述:<插入问题陈述> 学生解决方案:<插入学生解决方案> |
或者这可以通过一系列查询来实现,其中除了最后一个查询之外,所有查询的输出都对最终用户隐藏。
首先,我们可以要求模型自己解决问题。由于这个初始查询不需要学生的解决方案,因此可以省略。这提供了额外的优势,即模型的解决方案不会因学生尝试的解决方案而产生偏差。
角色 | 提示词 |
---|---|
用户 | <插入问题陈述> |
接下来,我们可以让模型使用所有可用信息来评估学生解决方案的正确性。 |
角色 | 提示词 |
---|---|
系统 | 将您的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。 |
用户 | 问题陈述:"""<插入问题陈述>""" 您的解决方案:"""<插入模型生成的解决方案>""" 学生的解决方案:"""<插入学生的解决方案>""" |
最后,我们可以让模型使用自己的分析来以乐于助人的导师的角色构建回复。
角色 | 提示词 |
---|---|
系统 | 你是一名数学导师。如果学生犯了错误,请以不透露答案的方式向学生提供提示。如果学生没有犯错,只需给他们一个鼓励性的评论。 |
用户 | 问题陈述:"""<插入问题陈述>""" 您的解决方案:"""<插入模型生成的解决方案>""" 学生的解决方案:"""<插入学生的解决方案>""" 分析:"""<插入模型从上一步生成的分析>""" |
4.3 询问模型在之前的过程中是否遗漏了任何内容
这个技巧在长文本问答中很实用,比如我们给了一个文档,要让大模型列出与一个特定问题相关的信息。如果源文档很大,模型通常会过早停止并且无法列出所有相关摘录。在这种情况下,通过使用后续查询提示模型查找之前传递中错过的任何摘录,通常可以获得更好的性能。
角色 | 提示词 |
---|---|
系统 | 您将获得一份由三重引号分隔的文档。你的任务是选择与以下问题相关的摘录:“人工智能历史上发生了哪些重大的范式转变。” 确保摘录包含解释它们所需的所有相关上下文 - 换句话说,不要提取缺少重要上下文的小片段。提供 JSON 格式的输出,如下所示: [{"excerpt": "..."}, ... {"excerpt": "..."}] |
用户 | """<在此插入文档>""" |
助手 | [{"excerpt": "模型在这里写一个摘录"}, ... {"excerpt": "模型在这里写另一个摘录"}] |
用户 | 还有更多相关摘录吗?注意不要重复摘录。还要确保摘录包含解释它们所需的所有相关上下文 - 换句话说,不要提取缺少重要上下文的小片段。 |
5. 使用外部工具
大模型有着局限性,比如无法获取实时数据等,所以需要借助一些外部工具来帮助处理🔧
5.1 使用基于嵌入的搜索实现高效的知识检索
如果作为输入的一部分提供,模型可以利用外部信息源。这可以帮助模型生成更明智和最新的响应。例如,如果用户询问有关特定电影的问题,则将有关电影的高质量信息(例如演员、导演等)添加到模型的输入中可能会很有用。嵌入可用于实现高效的知识检索,从而可以在运行时动态地将相关信息添加到模型输入中。这也是大多数知识库等原理:检索增强生成(RAG)。
5.2 使用代码执行来进行更准确的计算或调用外部API
不能依赖语言模型自行准确地执行算术或长时间计算。在需要的情况下,可以指示模型编写和运行代码,而不是进行自己的计算。特别是,可以指示模型将要运行的代码放入指定的格式,例如三重反引号。产生输出后,可以提取代码并运行。最后,如果有必要,可以将代码执行引擎(即Python解释器)的输出作为下一个查询的模型的输入。
角色 | 提示词 |
---|---|
系统 | 您可以通过将Python 代码括在三个反引号中来编写和执行Python 代码,例如“此处代码为”。用它来执行计算。 |
用户 | 求以下多项式的所有实值根:3x**5 - 5x**4 - 3x**4 - 7x - 10。 |
代码执行的另一个很好的用例是调用外部 API。如果模型接受了如何正确使用 API 的指导,它就可以编写使用该 API 的代码。通过向模型提供展示如何使用 API 的文档和/或代码示例,可以指导模型如何使用 API。
角色 | 提示词 |
---|---|
系统 | 您可以通过将 Python 代码括在三个反引号中来编写和执行它。另请注意,您可以访问以下模块来帮助用户向朋友发送消息: ```python import message message.write(to="John", message="Hey,想在下班后见面吗?")`` ` |
5.3 给模型提供特定的功能
通过 API 请求,传递一系列特定的函数描述,告诉模型哪些函数是可以进行实用的。这使得模型能够根据提供的模式生成函数参数。生成的函数参数由 API 以 JSON 格式返回,可用于执行函数调用。然后,可以将函数调用提供的输出反馈到以下请求中的模型中以关闭循环。这是使用OpenAI模型调用外部函数的推荐方式。
6. 系统地测试变更
有时很难判断更改(例如新指令或新设计)是否使您的系统变得更好或更差。看几个例子可能会暗示哪个更好,但由于样本量较小,很难区分真正的改进或随机运气。也许这种变化有助于某些输入的性能,但会损害其他输入的性能。
评估程序(或“evals”)对于优化系统设计非常有用。好的评估是:
代表现实世界的使用情况(或至少是多样化的) 包含许多测试用例以获得更大的统计能力(有关指南,请参阅下表) 易于自动化或重复
检测差异 | 95% 置信度所需的样本量 |
---|---|
30% | 〜10 |
3% | 〜1,000 |
1% | 〜10,000 |
输出的评估可以由计算机、人类或两者混合来完成。计算机可以使用客观标准(例如,具有单个正确答案的问题)以及一些主观或模糊标准自动进行评估,其中模型输出由其他模型查询进行评估。OpenAI Evals是一个开源软件框架,提供用于创建自动化评估的工具。
当存在一系列可能的输出被认为质量同样高时(例如,对于答案很长的问题),基于模型的评估会很有用。通过基于模型的评估可以实际评估的内容与需要人类评估的内容之间的界限是模糊的,并且随着模型变得更加强大而不断变化。我们鼓励进行实验,以确定基于模型的评估对您的用例的效果如何。