高级prompt工程讲解

本文需要一点阅读基础,最好您使用过大模型,如ChatGPT、Claude.ai或Llama,当然也不排斥ChatGLM、通义千问、文心一言等。本文还有一篇基础篇,如果您真的想学习prompt,成为一个可以“掌控”大模型的人,那么,最好从这篇文章开始读。

一文讲清楚实用Prompt工程

大型语言模型(LLMs)的普及已经完全改变了我们作为人类解决问题的方式。在前几年,用计算机解决任何任务(例如,重新格式化文档或对句子进行分类)都需要创建一个程序(即,根据某种编程语言精确编写的一组命令)。对于大语言模型来说,解决这样的问题只需要一个文本prompt。例如,我们可以通过类似于下面所示的prompt让LLM重新格式化任何文档。

使用提示重新格式化XML文档正如上面的例子所示,大语言模型的通用文本输入到文本输出格式使我们很容易解决各种各样的问题。通过GPT-3的提出,我们第一次看到了这种潜力,表明足够大的语言模型可以使用few-shot学习以惊人的准确性解决许多任务。然而,随着大语言模型研究的进展,我们开始超越这些基本(但仍然非常有效!)的提示技术,如zero-shot/few-shot学习。

遵循指令的大语言模型(例如,InstructGPT和ChatGPT)引导我们探索语言模型是否可以解决真正困难的任务。也就是说,我们想要使用大语言模型来解决不仅仅是玩具问题。为了在实践中发挥作用,大语言模型需要能够遵循复杂的指令并执行多步推理,以正确回答人类提出的难题。不幸的是,使用基本提示技术通常无法解决此类问题。为了激发大语言模型解决复杂问题的行为,我们需要更复杂的东西。

扩大可能性的范围…

在之前的一篇文章中,我们了解了大语言模型更基本的提示方法,例如zero-shot/few-shot学习和指令提示。理解这些实用的提示技术对于掌握本文将介绍的更高级的提示过程非常重要。有关这些技术的更多细节,请查看链接这里的概述!

更好的提示→更好的结果.

这些技术可以用来完成很多大语言模型(假设它们被正确应用)。然而,由于种种原因,它们可能达不到要求。few-shot学习要求大多数大语言模型的有限上下文窗口被范例占用,如果不采取保护措施,大语言模型可能会被欺骗,提供有害的输出,并且大多数模型不擅长解决推理任务或遵循多步骤指令。考虑到这些限制,我们应该如何尝试用大语言模型解决困难的任务?

一种方法是创建更有能力的大语言模型,要么从零开始,要么通过更好的改进程序。然而,这需要很多的努力!如果我们能让现有模型更好地解决问题呢? 在这篇文章中,我们将探索更高级形式的prompt工程(例如,思维Chain提示,自动prompt工程,信息检索等),使我们能够提高LLM的性能,并引出更复杂的问题解决行为。学习这些想法很重要,因为它们拓宽了大语言模型的可能性范围。例如,使用这些技巧,我们可以:

  • 允许LLM访问外部知识库。
  • 能够解决复杂的、基于推理的问题。
  • 通过允许模型存储和访问对话中的先验信息,为LLM提供无限内存。

    prompt工程正在不断发展

这篇综述将集中于提供prompt工程最新进展的高级视图。而不是深入探索个别方法,我们将重点放在获得不同的提示技术,可能是有用的一个广泛的观点。然而,需要注意的是,prompt工程是一个新兴且发展迅速的课题。几乎每天都有新的研究发布,许多前沿的想法只是在网上分享,而不是正式发表。因此,这个话题在未来几个月可能会发生重大变化,从而扩大大语言模型可以解决的问题。

理解LLMs

由于它的重点是提示,这个概述不会解释语言模型的历史或机制。为了更好地理解语言模型(这是深入理解提示的重要先决条件),我编写了各种可用的概述。这些概述如下(按重要性排序):

  • 语言建模基础(GPT和GPT-2)
  • 尺度对语言模型的重要性(GPT-3)
  • 现代和专业大语言模型
  • PaLM, T5(v1和v2), Llama(v1和v2)

    高级提示技术

现在我们将讨论提示工程领域中三个有影响力的主题。首先,我们将了解如何使用思维链提示(包括几个值得注意的扩展和变体)来提高llm的推理能力。从这里开始,我们将讨论LLMs与外部数据库的集成,使相关的、准确的信息能够注入到每个提示中。最后,我们将学习如何使用自动提示工程方法从数据中发现更好的提示。

思维链提示和超越

我们在之前的一篇文章中介绍了思维链(CoT)提示背后的主要思想和它的一些流行变体。

什么是CoT提示?

CoT提示是一种简单的技术,用于提高法学硕士在常识或符号推理等推理任务上的表现。CoT提示通过在提示中插入几个正在解决的推理问题的示例来利用少量学习。每个例子都与一系列的思想(或理论)相匹配,通过文本解释如何一步一步地解决问题来增加问题的答案.

见下文。

由于他们的few-shot学习能力,大语言模型可以通过观察CoT prompt中的示例来学习生成基本原理以及他们的答案。先前的工作表明,以这种方式生成准确的基本原理可以提高推理性能,我们在CoT提示的实验中也看到了这种效果。也就是说,教LLM输出解释其最终答案的相关思维链可以大大提高算术、符号和常识性推理等任务的表现;见下文。

流行的CoT变体。

除了基本的CoT提示外,还探索了该技术的几种变体,例如:

  • zero-shot CoT提示:替换所有示例理据,在提示符的末尾注入“Let ‘s think step by step”语句。
  • 自一致性: 使用LLM生成多个思想链,并将这些多个输出的多数投票作为最终答案。
  • 最小到最多提示[15]: 将推理问题分解为更小的步骤,每次解决一个,其中每个子问题的输出用作下一个子问题的输入。

这些技术(如下图所示)类似于CoT提示并产生类似的结果,但是它们各自都有独特的优点。例如,zero-shot CoT提示非常简单!我们只需要在我们的提示中插入一个语句,而不是手写或策划几个相关的思维链示例。另一方面,最少到最多提示比普通的CoT提示稍微复杂一些,但是这种技术也更能够解决需要许多步骤的推理问题。因此,我们可以使用最少到最多提示来解决CoT提示不足的最困难的任务。

在这些技巧中,自我一致是我个人的最爱。为什么?因为这是一个简单的技术,广泛适用,非常有效。事实上,这个想法甚至不是针对CoT提示的!在许多情况下,自一致性可以提高LLM应用程序的性能。我们不是用LLM生成单个输出,而是生成多个输出并取其平均值作为最终答案,从而提高了可靠性和准确性。

这个想法让我想起了深度学习中的模型集成,其中我们 i)独立训练几个模型来解决一些任务,ii)在推理时对每个模型的输出取平均值。虽然自洽只使用单个模型而不是集合,但类似的技术已经应用于更广泛的深度学习文献;例如,为了模拟一个集成,可以从包含不确定性模块(如dropout)的神经网络中生成多个输出并取平均值。

延伸式CoT提示.

CoT提示是否真的教会了大语言模型如何“推理”尚不清楚。尽管如此,CoT提示具有重要的实际意义,因为它可以用于解决复杂的、多步骤的大语言模型问题。因此,围绕CoT提示的各种有趣的想法最近已经被探索。探讨了CoT提示的多模态版本,其中使用图像和文本模态来执行不同的推理任务;见下文。

除了探索多种数据模式(即图像和文本)外,中的作者还通过将多步骤基本原理生成和答案推理作为解决基于推理的任务的两个不同步骤,略微调整了CoT设置;见下文。

通过清楚地隔离这些组件,我们可以更容易地分析CoT提示中的错误来源。因此,作者发现,i)错误的答案往往是由生成的基本原理中的幻觉引起的,ii)使用多模态数据可以生成更有效的基本原理。

更进一步,将CoT提示与主动学习的思想结合起来(即使用模型本身来识别应该包含在训练集中的数据)。LLMs首先使用CoT提示回答几个问题。从这里开始,输出“不确定性”(基于同一LLM生成的多个答案之间的不一致来测量)用于识别模型不太理解的问题。然后用正确的思维链对该组中的问题进行手工注释(由人类),并将其用作解决未来问题的示例。

在实践中应用CoT提示时,我们可能遇到的最大问题之一是缺乏与我们试图解决的任务很好地结合在一起的少量示例。也许我们有几个高质量的思维链可以包含在我们的提示中,但如果我们试图解决的问题与这些示例中解决的问题略有不同,我们该怎么办?*虽然这个问题会导致性能下降。也就是说,我们可以使用主动学习来动态识别用于CoT提示的可用示例是否不足以解决某个问题。

知识的增加

虽然大语言模型在预训练期间学习了很多信息,但用额外的相关信息来增加他们的prompts通常是有帮助的。这种方法可以通过在LLM的prompt中提供准确的信息源来帮助解决幻觉(即生成不正确的事实)等问题,这些信息可以在生成输出时用作上下文。虽然有几种方法可以实现这一点,但我们将重点关注基于信息检索和生成知识的技术。

信息检索

LLM社区最近把重点放在矢量数据库技术(例如,Pinecone, Milvus, Weaviate等),因为它在执行信息检索中的作用;见上图。在高层次上,信息检索的目标是使大语言模型能够通过以下方式访问大量文本信息库(超出最大上下文窗口):

  1. 把文本分成小块。
  2. 为每个文本块生成一个Embedding。
  3. 将这些Embeddings存储在矢量数据库中。
  4. 执行向量相似性搜索(基于这些Embeddings)来查找相关的文本块以包含在prompt符中。

最终的结果是,我们可以快速找到相关的文本信息,以提供额外的上下文在LLM的prompt。这种方法甚至可以与CoT提示相结合,引导检索过程获得新的有用信息。

生成的知识.

信息检索是强大的(即,它可以访问几乎无限量的信息!),但是我们可能会想:外部向量数据库是完全必要的吗?有趣的是,最近的研究[1]表明答案可能是否定的!我们可以通过提示单独的LLM生成信息来提高LLM的性能,而不是存储和检索外部知识;见上图。特别是,我们可以使用Few-shot学习,通过提示LLM关于各种主题的知识生成示例,并以生成有关所需主题的有用上下文的请求结束;见下文。

在这里,我们可以在生成预测时将生成的信息作为额外的上下文。尽管不依赖于任何外部数据库,但这种方法可以显著提高LLM在几个常识性推理任务上的性能;见下文。

生成的知识对于假设理解世界上的常识性知识的任务(如常识推理)最有帮助。简而言之,大语言模型是一个很好的信息源,只要它们被谨慎地用于正确的任务。

“生成的知识提示强调了大型语言模型作为改进常识推理的外部知识的灵活来源”

自动提示

Prompt工程的目标是调整语言模型的输入,使模型提供正确结果的机会最大化。考虑到这一点,我们甚至可以将我们的prompt视为一组可以更新的可训练参数(例如,使用梯度下降或其他一些数据驱动的标准)来生成正确答案。基于数据自动更新prompt的想法非常普遍,但在最近的研究中已经成功地探索了几种这样的技术。

自动prompt工程师(APE)

提出了一种自动生成指令提示的简单方法。首先,LLM通过使用具有多个指令示例的few-shot prompt来提出一组潜在指令。探索了一些用于生成指令的prompt模板;见下文。

然后,我们通过评估使用每个指令的LLM的zero-shot性能(即正确结果的准确性或对数概率)来搜索这个指令“候选”池。换句话说,LLM在每个prompt下的表现被用作评估教学质量的指标。

进一步说,我们在中看到,指令可以通过重复这个过程来迭代地改进。特别是,我们可以 i)提出一组候选对象,ii)根据性能评估这些候选对象,iii)选择最佳候选对象, iv)通过提示LLM生成类似指令(即重新采样)来生成最佳候选对象的新变体。

这个过程(以及相关的prompt符)如下图所示。

gradient-base搜索.

除了搜索更好的文本prompts的技术之外,还有一系列有用的prompt工程工作,探索对prompt Embeddings的持续更新。首先,我们应该回顾一下语言模型中的prompt Embeddings是什么。给定一个文本prompt,我们通常对该prompt进行标记(即,将其分成单词或子单词),然后查找每个结果token的Embedding。这个过程为我们提供了一个token Embeddings列表(即prompt Embedding!),我们将其作为输入传递给语言模型;见下文。

语言模型中的prompts和prompt Embeddings一些作品探讨了直接修改promptEmbedding的prompt工程策略(即,每个token的Embeddings列表)。换句话说,这些作品并不直接修改prompt的单词,而是使用梯度下降等规则更新promptEmbeddings。这方面的主要工作概述如下:

  • AutoPrompt将原始prompt输入与一组共享(跨所有输入数据)“触发tokens”相结合,这些令牌是通过基于梯度的搜索选择的,以提高性能。
  • 前缀调优在输入层和隐藏层的promptEmbedding中添加几个“前缀”tokens,然后使用梯度下降作为参数高效的微调策略训练该前缀的参数(保持模型参数固定)。
  • prompt调优类似于前缀调优,但前缀tokens只添加到输入层。这些tokens对语言模型解决的每个任务进行了微调,允许前缀tokens为给定任务调整模型。
  • P-Tuning向模型的输入层添加了特定于任务的锚定tokens,但允许将这些tokens放置在任意位置(例如,prompt的中间),使该方法比前缀调优更灵活。

    我们应该用哪一个?

所有这些方法(如下所示)都探索向语言模型添加“软”tokens,这些语言模型在目标数据集上进行监督微调。值得注意的是,这些技术不能用于只能通过付费API访问的语言模型(例如,OpenAI API)。这是因为我们需要访问和修改prompt Embeddings的能力,而大多数api只显示模型的文本输入和输出。目前,如果我们正在使用自己的自托管LLM,我们只能使用基于梯度的自动提示技术。

在这些方法中,prompt调优是最简单的方法,可以产生令人印象深刻的性能优势。通过prompt调优,我们只需i)向输入添加一些前缀token Embeddings,ii)在单个下游任务上执行这些Embeddings的参数高效微调。通过在每次更新中混合几个不同的任务并为每个任务提供唯一的学习前缀来执行多任务微调;见下文。

通常,对语言模型进行微调意味着我们必须为每个任务存储模型参数的单独副本。相比之下,prompt调优只是对一小部分前缀token Embeddings进行微调,并保持剩余的模型参数不变。尽管只对一小组参数进行了微调,但prompt调优非常接近于匹配端到端微调的性能,如下图所示。

启示

“我们还能指望推理能力在模型尺度上提高多少?还有哪些提示方法可以扩展语言模型可以解决的任务范围?” **

本文概述的主要目的是探索不同的提示技术,这些技术可能对解决大语言模型的难题有实际帮助。如果应用得当,像zero-shot/few-shot学习和指令prompt这样的基本技术是有用和有效的。然而,可能需要一些更复杂的东西来使大语言模型能够解决基于推理的任务或遵循复杂的、多步骤的指令。尽管随着时间的推移,模型的质量可能会有所提高,并且更容易处理此类困难的情况,但本文概述中涵盖的技术可以用于扩展当前可用的大语言模型的范围。下面概述了这些技术的一些基本要点。

解决难题。

对CoT提示的分析表明,大语言模型能够解决复杂的、多步骤的问题。然而,要做到这一点,需要为LLM或由LLMs将问题分解成更小的部分。我们可以通过鼓励模型在给出答案之前生成解决问题的基本原理来隐含地做到这一点,或者通过使用最小到最大的提示来明确地将问题分解成由LLM单独解决的小部分。无论哪种方式,我们通常看到鼓励LLM一步一步地解决问题而不是整体解决问题的好处。

学习prompt。

如果我们听到“prompt工程”这个词,我们大多数人可能会想到调整prompt的单词或结构,看看什么最有效。然而,这并不是prompt工程的唯一方法!也就是说,我们可以采用一种自动提示方法,通过梯度下降从数据中学习最优prompts。为此,我们使prompt Embedding(即,prompt中每个token的Embeddings列表)可训练并执行微调。虽然这种方法很有趣也很有用,但有一些注意事项需要记住:

  1. 学习到的prompt Embeddings不能映射回文本prompt,因为模型词汇表中每个token的Embeddings是离散的。
  2. 只有当我们能够访问语言模型的Embedding层时,我们才能使用这些方法。这种访问不是通过付费api(例如,来自OpenAI)提供的。

    简单但功能强大。

    尽管本概述侧重于先进的prompt工程技术,但仍有许多简单的技巧可以轻松应用于改进LLM应用程序。例如,自一致性可以通过生成多个答案并取其平均值来提高大语言模型的可靠性。通过在prompt符的末尾附加一条语句,zero-shot CoT提示可以很容易地提高LLM推理能力。最后,生成的知识可以通过简单地要求模型在生成最终答案之前列出有关主题的有用信息来提高LLM的性能。在许多情况下,将简单的技巧添加到我们的prompt工程工具包中可以产生很大的不同!

2