原文:Practical Prompt Engineering
注:本文中,提示和prompt几乎是等效的。
这是一篇非常全面介绍Prompt的文章,包括prompt作用于大模型的一些内在机制,和prompt可以如何对大模型进行“微调”。讲清楚了我们常常听到的一些名词的具体意思,包括zero-shot、few-shot、微调、对齐、指令、角色扮演等等。文章主要目的是为了让大家可以通过prompt工程来提高对大模型的使用能力。
由于LLMs的文本到文本格式,它们能够用单个模型解决各种各样的任务。这种能力最初是通过GPT-2和GPT-3等模型的zero-shot和few-shot学习来证明的。然而,当经过微调以符合人类偏好和指令时,大语言模型变得更加引人注目,使流行的生成应用程序成为可能,例如编码助手,信息搜索对话助理,基于聊天的搜索引擎体验。
由于它们使应用成为可能,大语言模型在研究界和流行文化中都迅速成名。在此过程中,我们也见证了一个新的互补领域的发展:prompt工程。在高层次上,大语言模型的操作方式是 *1)将文本(即prompt)作为输入,2)*生成文本输出,从中我们可以提取有用的东西(例如,分类,摘要,翻译等)。这种方法的灵活性是有益的。然而,与此同时,我们必须确定如何正确地构造我们的输入prompt,使LLM最有可能产生期望的输出。
prompt工程是研究如何使用不同的提示策略来优化LLM绩效的一门实证科学。虽然存在各种各样的方法,但我们将在本文中概述提示的一般机制,以及一些基本的(但非常有效的)提示技术,如zero/few-shot学习和指令提示。一路上,我们将学习实用的技巧和思想启示,可以立即采用,成为一个更有效的prompt工程师和LLM从业者。
了解大语言模型
由于它的重点是提示,这个概述不会解释大语言模型的历史或机制。为了更好地理解语言模型(这是深入理解提示的重要先决条件),我编写了各种可用的概述。这些概述如下(按重要性排序):
- 语言建模基础(GPT和GPT-2)
- 尺度对语言模型的重要性(GPT-3)
- 现代和专业大语言模型
- PaLM, T5(v1和v2), Llama(v1和v2)
Prompting一览
语言模型可以使用其通用的文本到文本格式来解决各种任务。
考虑到目前大语言模型如此火热,我们可能会问自己:*大语言模型的基本优势是什么,使它们如此强大?*虽然这个问题没有一个单一的答案(例如,模型规模,大规模预训练数据,人类反馈等),但大语言模型的一个主要优势是它们通用的文本到文本格式。这些模型是猜测下一个token预测方面的专家,通过微调和对这个能力的延展应用,可以解决许多不同的任务!
为了解决一个任务,我们所需要做的就是 *1)向包含相关信息的模型提供文本输入,2)*从模型返回的文本中提取输出。这种统一的方法可用于翻译、摘要、问答、分类等。然而,事情并没有那么简单。也就是说,提供给LLM的prompt(即输入文本)的措辞和结构会显著影响模型的准确性。换句话说,prompt工程是一件大事,可能会极大程度影响你对LLM的使用效果。
什么是prompt工程?
“prompt工程是一门相对较新的学科,用于开发和优化prompts,以有效地将LMs用于各种应用和研究主题。” — from [2]
考虑到正确地制作我们的提示内容对于在LLM中获得有用的结果非常重要,prompt工程在最近几个月获得了很多兴趣。然而,这是一门经验科学——发现最好的提示通常是基于启发式的,需要实验。我们可以通过跟踪发现更好的提示,并测试不同的想法,看看哪些有效。
用指令提示LLM
prompt的组成部分
有多种选择如何创建prompt的方法。然而,大多数prompts都由相同的几个(可选的)组件组成:
- 输入数据(Input Data): 这是LLM期望处理的实际数据(例如,正在翻译或分类的句子,正在总结的文档等)。
- 范例(Examplars): 向LLM展示正确行为的最好方法之一是在提示符中提供一些具体的输入输出(键值对)示例。
- 指令(Instruction): 我们可以通过文本描述指令做什么,而不是在提示符中显示正确行为的具体示例;见下图。
- 指标(Indicators): 以固定和可预测的结构为LLM提供输入是有帮助的,因此我们可能会使用指标来区分提示的不同部分;见下文。
- 上下文(Context): 除了上述组件之外,我们可能希望以某种方式为LLM提供额外的“上下文”或信息。
指示器可用于以多种方式构建prompts
一般技巧
prompt工程的细节根据所使用的模型和我们试图解决的任务而有很大的不同。然而,对于prompt工程,有一些被普遍接受的原则是有帮助的:
- 从简单提示开始:从一个简单的prompt开始,然后慢慢修改prompt,同时跟踪经验结果。
- 直接:如果我们希望LLM符合特定的风格或格式,我们应该清楚而直接地说明这一点。准确地说出你想要什么可以让你的信息传达出去。
- 专用性:模糊性是每个prompt工程师的敌人。我们应该让prompt变得详细和具体,而不是过分地提供太长的输入(例如,prompt可以有多长有限制)。
- 范例是强大的:如果描述我们想要什么是困难的,它可能是有用的,为几个不同的输入提供正确的输出或行为的具体例子。
可视化语言模型的上下文窗口
上下文窗口(tokens限制)
当我们考虑不同的提示技巧和方法时,我们需要记住,我们只能在prompt符中包含有限的信息。所有大语言模型都有一个预定义的上下文窗口,该窗口对一次可以处理的tokens(即文本序列中的单词或子单词)的总数设置了限制。不同模型的上下文窗口大小不同,但目前有一种强烈的趋势是增加上下文窗口的大小。例如,GPT-4具有32Ktokens的上下文窗口,Claude.ai甚至达到了10万tokens。
常用prompt技巧
zero-shot和few-shot学习的出现
虽然大语言模型最近由于像ChatGPT这样的流行模型而出现了爆炸式增长,但提示已经存在了一段时间。最初,像GPT这样的模型被微调以解决下游任务。随着GPT-2的提出,我们看到研究人员开始使用零射击学习来解决单个基础模型的多个下游任务。最后,GPT-3向我们表明,随着语言模型规模的增长,它们在几次学习方面变得非常出色。在本节中,我们将介绍这些想法,以更好地了解零和少镜头学习的工作原理,并提供一些更复杂的提示技术的详细信息。
Zero-Shot学习
Zero-shot学习背后的想法非常简单。我们只需将正在解决的任务描述和相关输入数据提供给LLM,然后让它生成结果;见下图。由于他们观察到大量的预训练数据,大语言模型通常能够以这种方式解决任务。也就是说,他们可以利用自己的知识库来解决(相对)大量的任务;请参阅下面的示例(使用[GPT-3.5]制作。
使用GPT-3.5做zero-shot学习
像GPT-2这样的模型广泛地探索了zero-shot学习,并且在某些情况下表现良好。然而,如果zero-shot学习不能解决我们的任务,我们该怎么办? 在许多情况下,我们可以通过提供更具体和具体的信息来大幅提高LLM的性能。特别是,我们可以开始向prompt符添加所需输出的示例,从而允许模型从prompt中看到的数据复制模式。
Few-Shot学习
除了任务描述之外,我们还可以使用高质量的输入输出示例来增强prompt。这种技术形成了few-shot学习的基础,它试图通过提供正确行为的明确示例来提高LLM的性能。如果使用得当并应用到正确的模型中,few-shot学习是非常有效的,正如GPT-3等大语言模型的突破性能力所证明的那样;见下文。
然而,学习如何适当地利用大语言模型的少量学习能力可能是复杂的。我们应该在prompt中包括哪些例子?是否有正确的方法来组织prompt?对prompt的更改是否会显著影响LLM?
大多数大语言模型对构建prompt符的方式很敏感,这使得prompt工程既困难又重要。虽然像GPT-4这样的最新模型似乎对prompt中的小扰动不太敏感,但研究界为我们提供了一些正确使用few-shot学习的提示,这些提示仍然有助于理解:
- 范例排序很重要,排列少量示例可以极大地改变LLM的性能。包含更多的少量示例并不能解决这个问题。
- 在少量样本中的标签分布很重要,并且应该与野外数据的实际分布匹配。令人惊讶的是,标签的正确性并不是那么重要。
- 大语言模型倾向于重复少数几个例子中的最后一个(即近因偏差)。
- prompt中包含的示例应该是多样的,并且随机排序。
最优数据采样.
选择不同的、随机排序的、与测试示例相关的示例是最好的。然而,除了这些基本的直觉之外,已经进行了大量的研究来确定如何为prompt选择最佳范例。例如,可以通过多样性选择,基于不确定性的选择,甚至基于与测试样例相似度的选择来选择few-shot的学习样本。
Few-shot学习 vs. fine-tuning.
在继续之前,我想说明一个值得注意的混淆点。few-shot学习不是微调。 Few-shot学习向prompt内的LLM提供示例,然后可以将其用作生成正确输出的相关上下文。这个过程被称为“情境学习”;见上图。模型的参数不需要通过few-shot学习进行修改。相比之下,微调在选定的数据集上显式地训练模型(即通过反向传播更新其权重)。
指令提示
使用指令调优语言模型作为编码助手
Few-shot学习非常强大,但它有一个明显的缺点:范例会消耗大量tokens。考虑到LLM的上下文窗口是有限的,我们可能希望探索不消耗那么多tokens的提示方法。例如,我们能否用文本向LLM解释正确的行为? 简短的回答是肯定的!这种技术只包括一个书面指令作为prompt的一部分,被称为指令提示符,它在特定类型的LLM中表现最好。
指令调整和对齐.
最近语言模型的发展主要集中在提高指令跟随能力上。预先训练过的大语言模型并不擅长遵循开箱即用的指令。然而,教这些模型如何遵循指令可以使它们更好地完成用户想要的东西(即,提高人类一致性)。遵循大语言模型的指令支持各种有用的应用程序,从信息搜索对话代理(例如,ChatGPT)到编码助手(例如,Codex);见下文。
正如在之前的文章中广泛讨论一样,创建LLM的第一步是使用语言建模目标在大型未标记的文本语料库上预训练模型。在此过程中,模型获取信息并学习准确地执行下一个token预测。然而,模型的输出并不总是有趣的、引人注目的或有帮助的,并且模型通常会努力遵守复杂的指令。为了鼓励这种行为,我们需要超越基本的预训练。
创建遵循指令的大语言模型.
教授LLM如何遵循指导有几种不同的方法。例如,我们可以执行指令调优,或者在包含指令的对话示例上微调LLM。几个著名的模型采用了这种方法,如Llama及其变体、所有FLAN模型、OPT-IML等。或者,我们可以使用由有监督微调(SFT)和人类反馈强化学习(RLHF)组成的三步法;见下文。这种方法导致了令人难以置信的模型的创建,如ChatGPT, GPT-4, Sparrow等等。
基于人的反馈调整大语言模型
制作有用的指令.
如果我们有一个LLM,已经训练遵循指令,我们可以完成很多通过提示模型有用的和信息丰富的指令。以下是使用指令提示的一些关键提示和想法:
- 就像我们其他的prompt一样,说明应该是具体和详细的。
- 我们应该避免告诉LLM不要在prompt中做某事。相反,我们应该专注于告诉LLM该怎么做。
- 使用带有指示符的输入结构,在prompt内清楚地识别指令是有帮助的;见下文。
指令提示的不同格式
角色扮演的提示方法.
另一个与指令提示密切相关的有趣提示技术是角色提示,它将“角色”或人物角色分配给模型。这个角色在prompt中通过如下文本片段分配:
- 你是一位著名的杰出数学家。
- 你是个医生。
- 你是个音乐专家。
有趣的是,最近的大语言模型能够在整个对话过程中很好地承担和保持这样的角色。
使用LaMDA进行角色提示
更进一步说,角色提示不仅仅是一个有趣的技巧。为LLM提供一个角色实际上可以提高性能(例如,角色提示GPT-3为“杰出的数学家”可以在基于算术的问题上提高性能)。但是,角色提示仅在某些情况下提高性能。
“当给AI分配角色时,我们会给它一些背景。这种背景有助于AI更好地理解问题。随着对问题的更好理解,人工智能通常会给出更好的答案.” — 来自 learnprompting.org
现实世界中的指令提示
用指令提示大语言模型是一个非常强大的工具,我们可以将其用于各种应用程序。要了解如何利用这种技术,我们可以看看最近发布的ChatGPT插件,其中包括一个开源的信息检索API。在这个API中,有两个特定的模块用于从文档中提取元数据和过滤个人身份信息(PII)。有趣的是,这些服务完全基于llm,并使用如下所示的prompts。
ChatGPT信息检索API中元数据提取和PII检测的prompts
在这些prompts中,为LLM提供了关于如何执行其所需任务的具体和详细的说明。该指令的一些值得注意的方面是:
- 明确声明所需的输出格式(json或true/false)。
- 该指令使用结构化格式(即,项目符号分隔列表)来描述重要信息。
- LLM的任务(即识别PII或提取元数据)在prompt中明确说明。
- 有趣的是,这些prompts会告诉模型在很多情况下不要做什么,这通常是不被建议的。
考虑到其局限性,信任LLM准确执行PII检测等关键任务可能不是最好的主意。尽管如此,这种方法展示了指令提示的不可思议的潜力。不需要编写整个程序或服务,我们可以通过编写prompt来快速解决许多任务。
启示
“为聊天机器人角色编写一个非常棒的prompt符是一项惊人的高杠杆技能,也是用一点自然语言编程的早期例子” — Sam Altman
如果我们没有从这个概述中学到其他东西,我们应该知道构建正确的prompt(即prompt工程)是在实践中成功利用大语言模型的很大一部分。语言模型由于其文本到文本的结构,具有令人难以置信的通用性,可用于解决各种任务。然而,我们必须为这些模型提供详细和适当的上下文,以便它们能够很好地执行。尽管最佳提示技巧因模型和任务的不同而不同,但我们可以利用许多高水平的提示来最大化成功的机会。
从zero-shot到few-shot。考虑到他们广泛的预训练(以及现在的微调)数据集,大语言模型包含大量信息,能够解决各种开箱即用的任务。为此,我们只向模型提供任务描述和相关输入数据,然后期望模型生成正确的输出。然而,由于提供给模型的有限上下文,zero-shot学习只能表现得还不错。为了进一步提高zero-shot学习的性能,我们应该通过在prompt中插入示例来利用few-shot学习。
遵循指令的大语言模型。虽然它表现得很好,但few-shot学习通常会消耗大量的tokens,这是一个问题,因为大多数大语言模型的上下文窗口有限。为了解决这个问题,我们可以采用一种指令提示方法,提供LLM期望行为的精确文本描述,而不是用正确输出的具体示例捕获这种行为。指令提示功能强大,但它需要经过微调的特定形式的LLM(例如,通过指令调优或RLHF)才能正常工作。预训练的大语言模型并不擅长开箱即用。
技巧和窍门。prompt工程提供了各种可以采用的技巧和最佳实践。通常,这些技术会随着每个新模型的发布而波动(例如,与之前的模型相比,GPT-4在处理非结构化prompts方面要好得多[2]),但是一些原则在相当长的一段时间内仍然适用。首先,我们应该总是从一个简单的prompt开始,然后慢慢增加复杂性。在开发prompt时,我们应该力求具体和详细,同时避免过于冗长(由于上下文窗口有限)。