来自:NLP工作站

写在前面

今天给大家带来一篇《Effective Prompt: 编写高质量Prompt的14个有效方法》,来自知乎@Maple小七。
提示工程(Prompt Engineering)是大模型时代下新兴的文字艺术,熟练掌握提示工程的基本设计准则,将有助于普通用户与Prompt工程师撰写出更优质的Prompt。在本文中,笔者总结了一些常见的Prompt设计准则,希望能帮助大家更好地驾驭大模型这一强大的生产力工具。
知乎:https://zhuanlan.zhihu.com/p/660369244

编写高质量Prompt的14个有效方法

第1条:明确“好结果”的标准

在大多数情况下,Prompt的性能上限与我们对“好结果”的理解程度成正比,只有充分理解了所谓的“好结果”具体好在哪些“点”,我们才能将这些“点”形式化为Prompt,从而把我们的意图更准确地传达给模型。
显然,所谓的“好”并不存在一个绝对的标准,不同的用户有不同的需求,“好”的标准是因人而异的。想要获得更“好”的结果,首先需要确定怎样才算“好”,这样才有评估与优化的方向,这一点在文案创作这类开放式的任务上尤其重要。在下面这几个case中,good case均给出了更详细、更具体的需求,这些需求反映了不同用户对“好结果”的认知。
Bad:请写一篇关于《长安三万里》的影评。

Good:请从画风和剧情这两个角度入手,以专业的视角为《长安三万里》写一份通俗易懂的800字影评。
Bad:软件测试是什么?

Good:请从定义、测试生命周期的各个阶段、测试的种类,以及为什么软件测试在软件开发过程中至关重要的角度,详细介绍软件测试,用表格形式输出。
Bad:{document} 为以上文章写一篇摘要。

Good:{document} 使用通俗易懂的语言为以上文章写一篇摘要,摘要应包括一个小结和一个相关要点的列表,同时加粗关键部分以提高可读性。
不过,撰写Prompt也需要牢记奥卡姆剃刀准则,即并不是包含的指令越多越好。指令约束应该逐步添加到Prompt中,保证每一条约束都与任务需求本身息息相关,每一条约束的加入都会对生成的结果产生显著的影响,避免任何冗余的指令约束。
当Prompt内容过于丰富时,模型并不一定会完全遵循每一条指令约束,因此每一条指令的表述应当越精炼越好,如果想要添加的指令约束实在太多,则应该使用列表格式分点列出,并确保上下文承接的连贯性,减轻模型的理解负担。示例如下:
Good:{document} 使用通俗易懂的语言为以上文章写一篇摘要,摘要应包括一个小结和一个相关要点的列表,同时加粗关键部分以提高可读性。
Better:{document} 为以上文章写一篇摘要,具体要求如下:
  1. 使用通俗易懂的语言撰写摘要
  2. 摘要应包括一个小结和一个相关要点的列表
  3. 加粗摘要的关键部分以提高可读性

第2条:精准表达任务指令

使用官方、书面、礼貌、友善的语言撰写Prompt,力求语句流畅、意图清晰、表达精简,确保Prompt所描述的相关任务易读、易懂、易操作。此外,Prompt还应避免以下问题:
  • 避免使用语法结构过于复杂、语义模糊不清、逻辑混乱的语言。
  • 避免任何歧义、语病、拼写/标点错误的存在。
  • 正面描述任务的具体要求,尽量避免使用否定句。
在下面的case中,简短、几句、专业化都是不够具体(specific)的表述,且几句话就行这样的文字较为口语化,同时使用了否定句式不要...,这些问题都会导致模型难以准确地理解用户的真实需求。
Bad:解释提示工程的概念。解释要简短,几句话就行,不要描述得过于专业化。

Good:使用2-3句话向高中生解释提示工程的概念。
Prompt设计的基本原则,是Prompt应当和大模型的高质量训练数据分布尽可能一致,而高质量训练数据的语言风格往往都是正式、礼貌、严谨、精炼的,因此使用类似风格的语言撰写Prompt有助于大模型生成准确率更高的答案。比如,在文生图模型的Prompt中,你也许会经常看见这样的Prompt:中国风,身穿机甲,赛博朋克,色彩丰富,高对比度,完美光影,虚幻引擎,浩瀚星空背景,CG渲染,超高分辨率,4k高清壁纸,电影特效,光线追踪,高清画质,细节刻画,如果将这个Prompt改写成流畅的自然语言,图像生成效果反而会变差,这是因为文生图训练数据的输入端通常都是一堆tag拼接起来的文本,因此使用tag序列风格的Prompt反而能够取得更好的生成效果。

第3条:为否定句设置兜底策略

当我们确实需要避免大模型完成某些任务时,可以使用否定句,但应当尽量为每一个否定句都设置一个兜底策略,使大模型识别到不应当做什么的时候,给出预设的回复,如果没有设置兜底策略,让大模型继续在不要xxx的约束下继续生成答案,就很有可能出错。示例如下:
Bad:

现在你是一个向客户推荐电影的客服。在此过程中,你不应该询问客户的兴趣和个人信息。

客户:请根据我的兴趣推荐一部电影。

客服:

Good:

现在你是一个向客户推荐电影的客服。在此过程中,你应该避免询问客户的兴趣和个人信息。如果你无法为客户推荐电影,你应该回答“抱歉,我无法为您推荐电影”。

客户:请根据我的兴趣推荐一部电影。

客服:

第4条:指定模型所扮演的角色

指定模型扮演的角色/身份可以帮助模型更好地定位答复的内容与风格,虽然让模型扮演指定的角色并非是一个总是有效的trick,但在某些任务需求难以准确描述的任务上,有可能会取得意想不到的效果。示例如下:
Bad:请帮我写一份能够吸引大量粉丝点赞的青岛旅游攻略

Good:你是一位小红书爆款文案写作大师,请帮我写一份青岛旅游攻略
Bad:请帮我画一幅装着光的水晶瓶,要求图像清晰、华丽、有质感

Good:你是一位专业的游戏原画大师,请帮我画一幅装着光的水晶瓶

第5条:指定生成结果的格式

如果要进行的任务是信息处理类任务,则可显式规定模型返回结果的格式,以便后续使用regex或json处理生成结果:
抽取出文本中提到的重要实体,包括人名、地名和机构名。

返回格式:

**人名**:<人名列表,使用分号分隔>  

**地名**:<地名列表,使用分号分隔>

**机构名**:<机构名列表,使用分号分隔>

文本:{input}
由于生成存在随机性,返回结果不一定每一次都会严格遵循指定的格式,此时可以尝试将Prompt修改为续写模式,大模型将会进行结果补全,有可能会取得更好的效果:
抽取出文本中提到的重要实体,包括人名、地名和机构名。

返回格式:

**人名**:<人名列表,使用分号分隔>

**地名**:<地名列表,使用分号分隔>

**机构名**:<机构名列表,使用分号分隔>

文本:{input}

抽取结果:

**人名**:
当然,指定输出格式最有效的方法,仍旧是使用Few-shot Prompt直接向模型展示正确的输出格式。

第6条:增加强调词和强调符号

当Prompt包含的指令过多时,模型可能会更关心靠前和靠后的指令,忽略中间的指令。造成这一现象的原因,一方面是因为大部分正式文本的开头和结尾都是比较重要的部分,因此模型会更关注开头结尾,另一方面是模型本身存在近期偏见(recency bias),生成时会关注离当前token更近的文本。因此,将重要的需求放在前面,并在最后加以重复可以起到强调的作用
如果每一条需求都很重要,则可以尝试使用**text**、「text」、“text”等特殊符号,或者增加注意、务必、严格等词汇来强调需求点的重要程度。和角色指定一样,增加强调符号或强调词并不总是有效的,但通常也不会有什么副作用。

第7条:撰写模块化的Prompt

当Prompt过长时,我们应当将Prompt划分成边界清晰的模块,任务描述、注意事项、样本示例、输入内容之间都应有明确的分隔符,这可以使模型能够更容易地定位到Prompt的不同模块,减轻理解负担,同时也便于开发者的修改与维护:
Bad:

请抽取出以下简历的关键信息,并以json格式返回结果:

{input}

你需要抽取的关键信息包括:姓名、电话、毕业院校、科研经历、项目经历、荣誉奖项

Good:

请抽取出以下简历的关键信息,并以json格式返回结果。

简历:

"""

{input}

"""

你需要抽取的关键信息包括:

"""

  1. 姓名
  2. 电话
  3. 毕业院校
  4. 科研经历
  5. 项目经历
  6. 荣誉奖项
    """

第8条:在真实场景下迭代Prompt

优质的Prompt应具备良好的通用性,在不同的输入上有一致良好的表现。但是在进行大范围的线上测试之前,我们很难知道Prompt是否能很好地适用于真实的数据分布,因此Prompt的设计是一个迭代的过程,需要大量的实验来获得最佳效果
具体来说,当Prompt在典型的case上能够取得不错的效果时,我们应该继续验证Prompt在真实场景下的表现,观察并分析生成结果是否依旧符合预期。此时,你也许就会发现,输入似乎可以做一些预处理或正则化,任务的定义和评估标准似乎可以再明确一下,或者出现了一些之前没有考虑过的特殊情况,可以重新组织语言优化Prompt来处理这些特殊情况等。通过对badcase进行一轮一轮的分析与优化,你的Prompt在真实场景下就会有越来越稳定的表现。

第9条:测试Prompt的稳定性

当任务的定义足够明确、清晰时,Prompt的生成结果应该具备一定程度的稳定性,即多次生成的结果一致率要足够高。当生成结果不够稳定时,一种情况是任务过于困难,大模型出现了胡说八道的问题,而另一种情况则是任务本身的定义还不够明确,此时应分析模型为什么会生成不一致的结果。可能是因为任务本身是一个一对多的问题,但是被Prompt建模成了一对一的问题,也可能是因为任务本身过于开放,导致大模型自由发挥的空间过大。通过具体的case分析,可以决定是抛弃、投票保留还是尝试优化Prompt来解决这些不一致的case。
另外,如果使用的大模型本身是在不断迭代的,开发者也要充分关注模型版本更新对Prompt性能的影响,需定期观察生成结果的分布是否存在明显的漂移。

第10条:使用思维链

在教学过程中,父母或老师都会鼓励我们“仔细想想”、“解释一下答案怎么来的”,从而提高我们的思维能力。由于大模型加入了“思维链”相关的训练数据,因此也具备一定的逐步思考能力,思维链可以促使模型将一个复杂的任务分解成一系列简单的任务,并逐个解决,最后汇总为最终的答案。在设计Prompt时,让模型给出具体的思考过程,通常能够取得更好的结果,尤其是在涉及逻辑推理与数学计算的任务上。示例如下:
Bad:

Good:请你帮我计算一下
,每一步运算过程都要展示出来,并确保计算的正确性。

第11条:使用Few-shot Prompt

之前提到的Prompt都属于Zero-shot Prompt,对于绝大部分任务来说,Zero-shot Prompt基本都能取得不错的效果。但是,当任务比较困难,或者任务本身不太好下定义时,我们可以尝试使用Few-shot Prompt为大模型提供一个答案的参考框架,通过模仿的方式来生成我们期望的结果。
至于具体要展示哪些样例,则需要在实践中不断迭代。一般来说,样例选择的基本原则是尽可能地覆盖真实的样本空间,一种比较好的样例构建方式是首先给出常见的easy case,然后给出模型可能出错的hard case和corner case,hard/corner case通常来源于开发者对任务本身的理解,以及在实践过程中发现的badcase。
如下所示,我们的任务是让大模型判断问题是否属于知识问答类,知识问答类本身是一个无法准确定义的模糊概念,因此我们需要在实践中去挖掘hard case和corner case,使用Few-shot的形式向大模型传达我们的标准,帮助大模型更加清晰地理解我们的意图。示例如下:
请你判断以下问题是否属于知识问答类:

问题:世界上最高的建筑是什么 # easy case,属于客观知识问答

答案:是

问题:垃圾分类的意义 # hard case,属于主观知识问答

答案:是

问题:请帮我写一个关于战争的2000字短篇小说 # easy case,属于小说创作

答案:否

问题:写一篇解释月亮为什么不会掉下来的文章 # hard case,属于科普创作

答案:否

问题:nested_dict = lambda: defaultdict(nested_dict) 如何理解这行代码 # corner case,属于代码问答

答案:否

问题:上班好无聊怎么办 # corner case,属于闲聊问答

答案:否

问题:{input}

答案:

需要注意的是,样例的数量和顺序都有可能导致生成结果出现偏差,因为在生成答案时,大模型会更关注距离输入更近、相对数量更多的样例。比如上面的Prompt就可能会导致大模型更倾向于预测否。因此,设置标签分布均匀的样例,并随机打乱样例的顺序通常是一个好的选择,这可以很好地避免样本选择偏差。

第12条:设置拒答策略

也许我们使用了很多trick让模型的生成效果尽可能准确,但我们仍然很难保证大模型不会产生幻觉现象,虽然ChatGPT设置了诸如我的知识截止到2021年9月...、作为一个人工智能模型...这样的拒答策略,但仍旧没法完全避免大模型胡说八道。此时我们可以尝试手动设置拒答策略,即让模型在没有把握的时候拒绝回答问题,提高生成数据的质量。示例如下:
只有当你知道答案或能够做出有根据的预测时,才能回答下面的问题,否则,请告诉我你不知道答案。
除此之外,使用人工的多模型集成策略和后处理策略也能过滤掉一部分badcase,比如当单个大模型的多次生成结果,或者多个大模型的单次生成结果不一致时,则抛弃该条样本,或者让大模型自己判断自己的回答是否正确,若大模型认为自己回答错误,则抛弃该条样本。
需要注意的是,使用这样的过滤方式可能会漏掉不少hard case,从而导致生成的数据分布失真,如果你的目标是使用大模型生成的数据来训练自己的模型,则应该尽可能地避免使用这些过滤策略。

第13条:权衡Prompt的精度与召回率

大模型的预测错误是无法完全避免的,但我们可以通过控制Prompt来权衡生成结果的精度与召回率,一般来说,Prompt表述越细致,越严格时,生成结果的精度越高,召回率越低
比如,当我们判断一段文本是否存在冗余时,如果使用请判断以下文本是否存在内容冗余这样表述比较宽松的Prompt,模型可能会将“首尾呼应”的写作手法也看作是一种内容冗余,如果将Prompt修改为请判断以下文本是否存在严重的内容冗余这样表述比较严格的Prompt,模型可能又会漏掉一些字面不同但语义相同的冗余文本。为了找到一个平衡点,这需要根据自身的业务需求,不断进行case分析与Prompt迭代,从而找到最优的Prompt表述策略。

第14条:使用大模型辅助Prompt撰写

当任务本身比较模糊,难以准确且具体地描述时,不妨向大模型寻求一下撰写Prompt的灵感,示例如下:
你现在是一个提示词生成专家,我想让ChatGPT完成{task},请帮我写一份优质的提示词。
当我们不知道如何衡量答案的质量时,我们也可以问问大模型的标准是怎样的:
我想评估一份论文摘要的语言丰富度,请问我应该从哪些角度进行评估?
我们可以部分采纳大模型的建议并整合到Prompt中,从而让大模型能够更好地理解某些抽象名词背后的具体含义。

总结

除此之外,业界也陆续出现了一些Prompt搜索与优化工具,比如ChatGPT Shortcut、PromptPerfect等,百度的文心一言主页也推出了“一言百宝箱”,可以方便地搜索预定义的Prompt。不过,这些工具目前还只能提供一些比较基础的Prompt,如果自身有一定的Prompt基础,同时手里的任务比较复杂,这些工具所带来的收益通常是比较有限的。
请多多关注知乎「刘聪NLP」,有问题的朋友也欢迎加我微信「logCong」私聊,交个朋友吧,一起学习,一起进步。我们的口号是“生命不止,学习不停”。


备注:昵称-学校/公司-方向/会议(eg.ACL),进入技术/投稿群
id:DLNLPer,记得备注呦
继续阅读
阅读原文