Google Prompt Engineering

AI 第五篇

这几天想起翻起来Google之前新发布的白皮书《Prompt Engineering》,学习下再简单用Claude提取下主要内容记录下。

掌握提示工程:打造AI高效交互的艺术与科学

在人工智能迅猛发展的今天,提示工程(Prompt Engineering)已成为连接人类意图与AI输出的关键桥梁。Google最新发布的白皮书《Prompt Engineering》为我们提供了全面而深入的指南,让我们一起探索如何通过精心设计的提示让大语言模型发挥最大潜力。

提示工程的本质

提示工程是设计高质量提示的过程,旨在引导大语言模型(LLM)产生准确、相关且有用的输出。正如白皮书中所强调的:

“你不需要成为数据科学家或机器学习工程师——每个人都可以编写提示。然而,设计最有效的提示可能很复杂。”

大语言模型本质上是一个预测引擎,它接收序列文本作为输入,然后基于训练数据预测下一个词元(token)应该是什么。当你编写提示时,你正在尝试设置LLM以预测正确的词元序列。

理解大语言模型的输出配置

在开始提示工程之前,了解如何配置LLM输出至关重要:

输出长度控制

控制模型生成的词元数量是一项重要配置。生成更多词元需要更多计算资源,导致能耗增加、响应时间潜在变慢,以及成本提高。限制输出长度对于某些提示技术特别重要,如ReAct(推理与行动),在这种情况下,LLM会在你想要的响应后继续生成无用词元。

采样控制机制

LLM不会正式预测单个词元,而是为每个可能的下一个词元分配概率。这些词元概率然后被采样以确定下一个生成的词元。

温度参数

温度控制词元选择中的随机性程度:

  • 低温度(接近0):适用于需要确定性响应的提示,选择概率最高的词元
  • 高温度(接近1或更高):产生更多样化或意外的结果,使所有词元被选中的可能性更加均等

Top-K和Top-P(核采样)

这两种设置限制预测的下一个词元只能来自概率最高的词元:

  • Top-K采样:从模型预测分布中选择K个最可能的词元
  • Top-P采样:选择累积概率不超过特定值(P)的最可能词元

综合配置时,一般起点建议:

  • 相对连贯且有创意的结果:温度0.2,top-P 0.95,top-K 30
  • 特别有创意的结果:温度0.9,top-P 0.99,top-K 40
  • 较少创意的结果:温度0.1,top-P 0.9,top-K 20
  • 只有一个正确答案的任务(如数学问题):温度0

提示技术详解

零样本提示(Zero-shot)

最简单的提示类型,仅提供任务描述和一些文本让LLM开始。适用于模型已经理解的简单任务。

示例

1
2
3
将电影评论分类为积极、中性或消极。
评论:"她"是一项揭示人工智能发展方向的研究,如果AI继续不受控制地发展,人类将走向何方。我希望有更多像这样的杰作。
情感:

单样本和少样本提示(One-shot & Few-shot)

通过在提示中提供一个或多个示例,帮助模型理解所需的输出格式或模式。这种方法特别适用于需要特定输出结构的任务。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
解析客户的披萨订单为有效的JSON:

例子1:
我想要一个小号披萨,配芝士、番茄酱和意大利香肠。
JSON响应:
{
"size": "small",
"type": "normal",
"ingredients": [["cheese", "tomato sauce", "pepperoni"]]
}

例子2:
我想要一个大号披萨,配番茄酱、罗勒和马苏里拉奶酪。
{
"size": "large",
"type": "normal",
"ingredients": [["tomato sauce", "basil", "mozzarella"]]
}

现在,我想要一个大号披萨,一半是芝士和马苏里拉奶酪,另一半是番茄酱、火腿和菠萝。
JSON响应:

少样本提示的示例数量取决于任务复杂性、示例质量和模型能力。一般建议至少使用3-5个示例,复杂任务可能需要更多。

系统、角色和上下文提示

这三种技术都用于引导LLM生成文本,但侧重点不同:

系统提示

设置语言模型的整体上下文和目的,定义模型应该做什么的”大局观”。

示例

1
2
3
将电影评论分类为积极、中性或消极。只返回大写的标签。
评论:"她"是一部揭示AI不受控制进化可能导致人类走向何方的令人不安的研究。它太令人不安以至于我无法观看完。
情感:

角色提示

为语言模型分配特定角色或身份,帮助模型生成与该角色一致的响应。

示例

1
2
3
我希望你扮演旅游指南的角色。我会告诉你我的位置,你将为我推荐3个附近可以参观的地方。在某些情况下,我还会告诉你我想参观的地点类型。
我的建议:"我在阿姆斯特丹,我只想参观博物馆。"
旅游建议:

上下文提示

提供与当前对话或任务相关的具体细节或背景信息,帮助模型理解要求的细微差别。

示例

1
2
上下文:你正在为一个关于80年代街机视频游戏的博客撰写文章。
建议3个可以撰写文章的主题,并简要描述这些文章应该包含什么内容。

退一步提示(Step-back)

先考虑与特定任务相关的一般问题,然后将答案用于后续提示,激活相关背景知识和推理过程。

示例

1
2
3
步骤1:基于流行的第一人称射击游戏,什么是5个虚构的关键设置有助于第一人称射击游戏中挑战和引人入胜的关卡故事线?

步骤2:利用上面的主题,为第一人称射击游戏编写一个新关卡的一段故事情节,既具挑战性又引人入胜。

思维链提示(Chain of Thought)

通过生成中间推理步骤来改善推理能力,特别适用于数学问题、逻辑推理等需要分步思考的任务。

示例

1
2
3
4
5
6
当我3岁时,我的伙伴是我年龄的3倍。现在,我20岁了。我的伙伴多大?让我们一步一步思考。

1. 当我3岁时,我的伙伴是3*3=9岁。
2. 这意味着我的伙伴比我大6岁。
3. 现在我20岁了,所以我的伙伴应该是20+6=26岁。
因此,我的伙伴现在26岁。

思维链提示可以与单样本或少样本结合使用,效果更佳:

1
2
3
4
5
问题:当我哥哥2岁时,我的年龄是他的两倍。现在我40岁了。我哥哥多大?让我们一步一步思考。
答案:当我哥哥2岁时,我是2*2=4岁。这意味着我比他大2岁。现在我40岁了,所以我哥哥是40-2=38岁。答案是38。

问题:当我3岁时,我的伙伴是我年龄的3倍。现在,我20岁了。我的伙伴多大?让我们一步一步思考。
答案:

自我一致性(Self-consistency)

结合抽样和多数投票,生成多样化的推理路径并选择最一致的答案。这种方法改进了LLM在各种任务中的准确性和回答一致性。

过程

  1. 使用相同提示多次,生成不同的推理路径
  2. 从每个生成的响应中提取答案
  3. 选择最常见的答案

思维树(Tree of Thoughts)

允许LLM同时探索多个不同的推理路径,通过在树的不同节点分支来解决问题。特别适合需要探索的复杂任务。

推理与行动(ReAct)

结合自然语言推理与执行外部工具操作的能力,使LLM能够解决复杂任务。例如,查询网络获取信息,然后基于结果继续推理。

Python示例

1
2
3
4
5
6
7
8
9
10
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.llms import VertexAI

prompt = "Metallica乐队成员有多少个孩子?"
llm = VertexAI(temperature=0.1)
tools = load_tools(["serpapi"], llm=llm)
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run(prompt)

自动提示工程(Automatic Prompt Engineering)

利用LLM自身生成更多提示,评估它们,并可能修改好的提示,然后重复这个过程:

  1. 编写生成输出变体的提示
  2. 根据选定指标评估所有指令候选
  3. 选择评估分数最高的指令候选

代码提示技巧

编写代码提示

LLM可以帮助开发人员加速编写代码过程,实现各种自动化任务:

示例

1
用Bash编写一个代码片段,询问文件夹名称。然后将该文件夹的内容重命名,在文件名前加上"draft"。

解释代码提示

LLM也可以帮助理解他人的代码:

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
解释以下Bash代码:
#!/bin/bash
echo "Enter the folder name: "
read folder_name
if [ ! -d "$folder_name" ]; then
echo "Folder does not exist."
exit 1
fi
files=( "$folder_name"/* )
for file in "${files[@]}"; do
new_file_name="draft_$(basename "$file")"
mv "$file" "$new_file_name"
done
echo "Files renamed successfully."

翻译代码提示

将代码从一种语言翻译到另一种语言:

示例

1
2
将以下Bash代码翻译为Python片段:
[Bash代码]

调试和审查代码提示

修复代码中的错误并提供改进建议:

示例

1
2
3
4
5
6
7
8
以下Python代码报错:
Traceback (most recent call last):
File "/Users/leeboonstra/Documents/test_folder/rename_files.py", line 7, in <module>
text = toUpperCase(prefix)
NameError: name 'toUpperCase' is not defined

调试错误并解释如何改进代码。
[Python代码]

提示工程最佳实践

提供示例

在提示中提供示例是最重要的最佳实践之一,它作为强大的教学工具,展示期望的输出或类似响应,提高模型输出的准确性、风格和语调。

设计简单

提示应简洁、清晰、易于理解。如果对你来说已经令人困惑,对模型来说也可能如此。避免使用复杂语言和提供不必要的信息。

示例改进

1
2
3
4
5
改进前:
我现在正在纽约参观,想了解更多关于好地方的信息。我带着两个3岁的孩子。我们假期应该去哪里?

改进后:
作为旅游指南,描述纽约曼哈顿适合带3岁孩子参观的好地方。

明确输出要求

具体说明所需的输出形式。简洁的指令可能无法充分引导LLM或过于笼统。

示例

1
生成一篇关于5大视频游戏主机的3段落博客文章。博客文章应该信息丰富且引人入胜,并以对话风格撰写。

使用指令而非约束

指令和约束在提示中用于引导LLM输出,但研究表明,专注于积极指令比严重依赖约束更有效:

  • 指令:直接传达期望的结果
  • 约束:设置响应的限制或边界

示例

1
2
3
4
5
推荐做法:
生成一段关于5大视频游戏主机的博客文章。只讨论主机、制造公司、发布年份和总销量。

避免做法:
生成一段关于5大视频游戏主机的博客文章。不要列出视频游戏名称。

控制最大令牌长度

通过配置或在提示中明确要求特定长度来控制生成的LLM响应长度:

1
用推特长度的消息解释量子物理学。

在提示中使用变量

使用变量使提示更加动态和可重用,特别是在集成到应用程序中时:

1
2
3
4
5
变量:
{city} = "阿姆斯特丹"

提示:
你是一名旅游指南。告诉我关于这个城市的一个事实:{city}

实验输入格式和写作风格

不同的模型、配置、提示格式、词汇选择可能产生不同结果。因此,尝试不同的提示属性如风格、词汇选择和提示类型(零样本、少样本、系统提示)非常重要。

例如,关于Sega Dreamcast的提示可以表述为:

  • 问题:Sega Dreamcast是什么,为什么它是如此革命性的主机?
  • 陈述:Sega Dreamcast是世嘉在1999年发布的第六代视频游戏主机…
  • 指令:写一段描述Sega Dreamcast主机并解释为什么它如此革命性的段落。

分类任务中混合类别

对于分类任务的少样本提示,确保混合可能的响应类别,避免模型只是记住示例顺序而非学习每个类别的关键特征。

适应模型更新

随时了解模型架构变化、添加的数据和新功能。尝试新版模型并调整提示以更好地利用新特性。

尝试不同输出格式

考虑实验输出格式,对于非创意任务(如提取、选择、解析、排序、排名或分类数据),尝试使用JSON或XML等结构化格式。

JSON输出优势

  • 始终以相同风格返回
  • 专注于您想要接收的数据
  • 降低幻觉风险
  • 使其关系感知
  • 获得数据类型
  • 可以排序

处理JSON输出的特殊考虑

JSON修复

虽然以JSON格式返回数据提供了众多优势,但也存在一些缺点。JSON的结构化特性虽然有利于解析和在应用程序中使用,但需要比纯文本更多的词元,导致处理时间增加和成本提高。此外,JSON的冗长可能轻易消耗整个输出窗口,特别是当生成由于词元限制而突然中断时,这通常会导致缺少关键的闭合大括号或方括号,使输出无法使用。

幸运的是,json-repair库(可在PyPI上获取)在这些情况下非常宝贵。此库智能地尝试自动修复不完整或格式错误的JSON对象。

使用JSON模式

JSON模式定义了JSON输入的预期结构和数据类型。通过提供模式,您为LLM提供了一个清晰的数据蓝图,帮助它专注于相关信息并减少误解输入的风险。此外,模式可以帮助建立不同数据片段之间的关系,甚至通过包含特定格式的日期或时间戳字段使LLM”时间感知”。

与其他提示工程师合作实验

如果您需要尝试制定良好的提示,找多人进行尝试可能会有所帮助。当每个人都遵循最佳实践时,您会看到不同提示尝试之间的性能差异。

思维链最佳实践

  • 在推理之后放置答案是必需的,因为推理的生成会改变模型在预测最终答案时获得的词元
  • 使用思维链和自我一致性时,需要能够从提示中提取最终答案,与推理分开
  • 对于思维链提示,将温度设置为0
  • 思维链提示基于贪婪解码,根据语言模型分配的最高概率预测序列中的下一个词。通常,在使用推理得出最终答案时,可能只有一个正确答案,因此温度应始终设置为0

记录提示尝试

详细记录您的提示尝试至关重要,这样您可以随着时间的推移了解什么有效,什么无效。建议使用谷歌表格,包含以下字段:

  • 名称
  • 目标
  • 模型
  • 温度
  • 令牌限制
  • Top-K
  • Top-P
  • 提示
  • 输出

除了这些字段外,跟踪提示版本(迭代)、结果是否OK/NOT OK/SOMETIMES OK的字段,以及反馈字段也很有帮助。

结语

提示工程是一门艺术,也是一门科学,需要持续的实践和改进。通过掌握本白皮书中详述的各种技术和最佳实践,您可以有效地引导大语言模型产生准确、相关且有用的输出,充分发挥AI的潜力,无论是用于个人项目还是企业级应用。

记住,提示工程是一个迭代过程。设计并测试不同的提示,分析并记录结果。根据模型的表现优化您的提示。不断实验,直到达到所需的输出。当您更换模型或模型配置时,回顾并继续使用先前使用的提示进行实验。

通过这种方法,您将能够与AI系统建立更有效、更精确的交互,释放其真正的潜力。