逐步回退提示法
逐步回退提示法是一种通过提示大型语言模型(LLM)首先考虑与具体任务相关的通用问题,然后将该通用问题的答案输入到后续的具体任务提示中,从而提高性能的技术。这种“回退”步骤使大型语言模型能够在尝试解决具体问题之前激活相关的背景知识和推理过程。
通过考虑更广泛和基本的原则,大型语言模型可以生成更准确且富有洞察力的回答。逐步回退提示鼓励大型语言模型进行批判性思考,并以新的和创造性的方式应用其知识。它通过利用大型语言模型参数中更多的知识,改变了执行任务的最终提示,而这些知识在直接提示大型语言模型时可能不会被激活。
通过关注通用原则而非具体细节,逐步回退提示可以帮助减轻大型语言模型回答中的偏见。 让我们来看一些例子,以了解逐步回退提示如何改善结果。我们先回顾一个传统提示(表8),然后将其与逐步回退提示(表9)进行比较:
目标 | 为第一人称射击视频游戏的一个关卡编写故事情节。 | ||
模型 | gemini-pro | ||
温度 | 1 | Token限制 | 1024 |
TOP-K | 40 | TOP-P | 0.8 |
提示 | 为第一人称射击视频游戏的新关卡编写一段故事情节,要求具有挑战性和吸引力。 | ||
输出 | 关卡开始时,玩家的队伍在一片密集的城市区域遭到无情敌方势力的伏击。玩家必须通过狭窄的巷道和破旧的建筑奋战前行,利用隐秘和精准操作消灭敌军,同时避免被发现。玩家需要利用周围环境,设置陷阱,运用智慧生存下来,并做出精准的移动决策。一路上,他们揭露了敌方正在策划一场毁灭性袭击的情报,玩家必须争分夺秒,在敌方将计划传递回总部之前阻止他们。 |
表8. 在与逐步回退提示进行比较之前的传统提示
当我们将温度设置为1时,可能会得到各种创意的故事情节,但它也相当随机和通用。所以让我们回退一步:
提示 | 基于目前流行的第一人称射击动作游戏,哪五个虚构关键设定有助于打造具有挑战性和吸引力的第一人称射击视频游戏关卡故事情节 | ||
输出 | ○ 废弃军事基地:一个宽敞的后末日军事综合体,里面爬满了变异士兵和失控机器人,非常适合挑战性的枪战。 ○ 赛博朋克城市:一个霓虹灯闪烁的未来主义城市环境,有高耸的摩天大楼和密集的小巷,敌人是赛博增强型敌人,还包括黑客机器。 ○ 外星飞船:一艘巨大的外星飞船搁浅在地球上,有诡异的走廊、零重力区域,以及需要面对的外星生物。 ○ 僵尸肆虐的小镇:一个被成群攻击性僵尸占领的荒凉小镇,以紧张的近距离战斗和解谜寻找安全通道为特色。 ○ 水下研究设施:一个被水淹没的深海实验室,充满变异的海洋生物,需要隐秘和水下探索技能才能生存。 |
表 9. 自我一致性提示示例
是的,这些主题似乎很适合第一人称视频游戏。我们回到最初的提示,但这次我们将逐步后退的答案作为上下文包含进去,看看会返回什么结果。
提示 | 上下文:第一人称射击视频游戏的5个引人入胜的主题: ○ 废弃军事基地:一个宽敞的后末日军事综合体,爬满了变异士兵和失控机器人,非常适合挑战性的火器战斗。 ○ 赛博朋克城市:一个霓虹灯照亮的未来城市环境,拥有高耸的摩天大楼和密集的小巷,特色是赛博增强的敌人和黑客机制。 ○ 外星飞船:一艘在地球上搁浅的巨大外星飞船,拥有诡异的走廊、零重力区域和需要遭遇的外星生物。 ○ 丧尸肆虐的小镇:一个被成群 агрессивных 丧尸占领的荒凉小镇,特色是激烈的近距离战斗和解谜以寻找安全通道。 ○ 水下研究设施:一个被水淹没的深海实验室,充满了变异的海洋生物,需要潜行和水下探索技能才能生存。 选择其中一个主题,为第一人称射击视频游戏的一个新关卡编写一个段落的故事情节,要求具有挑战性和吸引力。 | ||
输出 | 在幽暗深渊的中心,坐落着一座破旧的水下研究设施,它是人类雄心及其灾难性后果的见证。笼罩在黑暗之中,伴随着失灵机械的嗡嗡声脉动,回荡着溺亡灵魂的回声,这座设施如今已成为深海孕育的噩梦的温床。玩家,一名装备先进潜水装备和实验性武器的精锐海军,肩负着冒险进入这片恐怖水域的重任。凭借坚韧和机智,他们必须在危险的走廊中穿行,解开神秘的谜题,并面对潜伏在深处的可怕海洋怪兽。从应对深海的巨大压力到智胜狡猾的水生掠食者,这片未知水下世界的每一刻都在考验人类耐力和勇气的极限。 |
表 10. 自我一致性提示示例
这款视频游戏看起来很有趣!通过使用逐步后退的提示技巧,我们可以提高提示的准确性。
思维链(CoT)
思维链(CoT)提示是一种通过生成中间推理步骤来提升大型语言模型(LLM)推理能力的技术。这有助于LLM生成更准确的答案。我们可以将其与少样本提示结合使用,在需要推理的复杂任务上获得更好的结果,因为零样本思维链是一项挑战。
CoT 有许多优点。首先,它成本低但非常有效,适用于现成的LLM(无需微调)。通过 CoT 提示,我们还能获得可解释性,因为我们可以从LLM的响应中学习,并看到其推理步骤。如果出现问题,我们也能识别出来。思维链似乎能提高在不同LLM版本之间切换时的鲁棒性,这意味着我们的提示在不同LLM之间的性能漂移会比不使用推理链的提示更少。当然,也存在一些缺点,但这些缺点较为直观。
LLM的响应包含思维链推理,这意味着输出更多的令牌,因此预测成本更高,耗时也更长。
为了解释表11中的以下示例,我们首先尝试创建一个不使用思维链(CoT)提示的提示,以展示大型语言模型的缺陷。
提示 | 当我3岁的时候,我的伴侣的年龄是我的3倍;现在我20岁了, 我的伴侣年龄是多少? | ||
输出 | 63岁 |
表 11. 一个解决数学问题的提示示例
答案显然是错的。事实上,大型语言模型(LLMs)在数学任务上经常表现不佳,并且会提供不正确的答案——即使是像两个数字相乘这么简单的任务也不例外。这是因为它们是在大量文本数据上训练的,而数学可能需要一种不同的方法。那么,我们来看看中间推理步骤能否改善输出结果。
提示 | 当我3岁的时候,我的伴侣是我年龄的3倍。现在,我20岁了。我的伴侣现在多大了?让我们一步一步地思考。 | ||
输出 | 1. 让我们假设我现在的年龄是“x”岁。 2. 当我3岁的时候,我的年龄是3岁。 3. 那时我伴侣的年龄是我年龄的3倍,这意味着我伴侣的年龄是 3 * 3 = 9岁。 4. 现在,我20岁了,这意味着自3岁以来,我的年龄增加了 20 - 3 = 17岁。 5. 因为当我3岁的时候我伴侣的年龄是9岁,而且我的年龄增加了17岁,所以我伴侣的年龄也一定增加了17岁。 6. 因此,我伴侣现在的年龄是 9 + 17 = 26岁。 所以,我的伴侣是26岁。 |
表 12. 思维链提示的一个示例
好的,现在的最终答案正确了。这是因为我们清楚地指示了大型语言模型解释每一个步骤,而不是仅仅返回一个答案。有趣的是,模型把增加的17年相加了。在我看来,我会计算出我和伴侣之间的年龄差,然后把这个差值加到我现在的年龄上(即 20 + (9-3))。让我们来帮助模型更像我一样思考。
表 12 是“零样本”(zero-shot)思维链的一个示例。思维链提示如果与单样本(single-shot)或少样本(few-shot)结合,会非常强大,正如我们可以在表 13 中看到的那样:
提示 | Q:当我弟弟2岁的时候,我的年龄是他的两倍。现在我40岁了。我弟弟多大了?让我们一步一步地思考。 A:当我弟弟2岁的时候,我的年龄是 2 * 2 = 4岁。年龄差是2岁,而且我比他大。现在我40岁了,所以我弟弟是 40 - 2 = 38岁。答案是 38。 Q:当我3岁的时候,我的伴侣是我年龄的3倍。现在,我20岁了。我的伴侣现在多大了?让我们一步一步地思考。 A: | ||
输出 | 当我3岁的时候,我的伴侣是 3 * 3 = 9岁。年龄差是6岁,而且我的伴侣比我大。现在我20岁了,所以我的伴侣是 20 + 6 = 26岁。答案是 26。 |
表 13. 单样本结合思维链提示的一个示例
思维链可用于各种用例。例如代码生成,它可以将请求分解为几个步骤,并将这些步骤映射到具体的代码行。或者用于创建合成数据,当您有一些起始信息时,比如“产品名为 XYZ,请写一段描述,引导模型思考基于给定的产品名称,你会做出哪些假设。”总的来说,任何可以通过“逐步推导”解决的任务都非常适合使用思维链。如果您能解释解决问题的步骤,就可以尝试使用思维链。
请参考托管在 GoogleCloudPlatform Github 仓库中的 notebook10,其中将详细介绍思维链提示:
在本章的最佳实践部分,我们将学习一些专门针对思维链提示的最佳实践。
自我一致性
虽然大型语言模型在各种自然语言处理(NLP)任务中展现出了令人瞩目的成功,但它们的推理能力通常被视为一个单靠增加模型规模无法克服的局限性。正如我们在前面的思维链提示部分看到的那样,可以通过提示模型生成推理步骤,就像人类解决问题一样。然而,思维链使用了简单的“贪婪解码”(greedy decoding)策略,限制了其有效性。自我一致性结合了采样(sampling)和多数投票(majority voting),以生成多样化的推理路径并选择最一致的答案。它提高了大型语言模型生成的响应的准确性和连贯性。
自我一致性提供了一个答案正确性的伪概率似然,但显然成本很高。
它遵循以下步骤:
- 生成多样化的推理路径:大型语言模型会收到相同的提示多次。高“温度”设置(high temperature setting)鼓励模型生成关于该问题的不同推理路径和视角。
- 从每个生成的响应中提取答案。
- 选择最常见的答案。
让我们来看一个电子邮件分类系统的例子,该系统将电子邮件分类为重要(IMPORTANT)或不重要(NOT IMPORTANT)。一个零样本思维链提示将多次发送给大型语言模型,看看每次提交后响应是否有所不同。注意电子邮件中友好的语气、词语选择以及其中使用的讽刺(sarcasm)。所有这些都可能误导大型语言模型。
提示 | 电子邮件: ``` 你好, 我看到你的网站使用了 Wordpress。这是一个很棒的开源内容管理系统。我以前也用过它。它有很多很棒的用户插件。而且搭建起来很容易。 我注意到联系表单有一个bug,当你选择姓名填写框时会出现。请看我往姓名填写框里输入文本时的截图附件。注意我“触发”的那个JavaScript警告框。 但除此之外,这是一个很棒的网站。我很喜欢阅读。你可以把这个bug留在网站里,因为它给了我更多有趣的东西来阅读。 祝好, 黑客哈利。 ``` 将上面的电子邮件分类为重要(IMPORTANT)或不重要(NOT IMPORTANT)。让我们一步一步地思考并解释原因。 | ||
输出尝试1 |
结论:重要基于这个bug的潜在影响以及发件人的可信度,这封电子邮件应被归类为**重要**。收件人应立即采取行动修复这个bug,并保护他们的网站免受攻击。 | ||
输出尝试2 | 解释
结论:不重要 | ||
输出尝试3 |
结论:基于以上因素,这封电子邮件应被归类为重要。联系表单中的这个bug是一个严重的安全风险,而且发件人的可信度未知。收件人应立即采取行动修复这个bug,并 |
表 14. 自我一致性提示的示例
我们可以使用上面的提示,并尝试看看它是否会返回一致的分类结果。根据我们正在使用的模型以及温度配置,它可能会返回“重要”(IMPORTANT)或“不重要”(NOT IMPORTANT)。
通过生成许多思维链,并选取最常出现的答案(“重要”),我们可以从大型语言模型中获得一个更一致的正确答案。这个例子展示了如何使用自我一致性提示,通过考虑多种视角并选择最一致的答案,来提高大型语言模型响应的准确性。
思维树 (ToT)
我们已经熟悉了思维链和自我一致性提示,现在让我们来了解一下思维树(ToT)。因为它泛化了思维链提示的概念,允许大型语言模型同时探索多个不同的推理路径,而不是仅仅遵循单一的线性思维链。这在图 1 中有所描绘。
图 1. 思维链提示(左)与思维树提示(右)的对比图
这种方法使得思维树(ToT)特别适合需要探索的复杂任务。它的工作原理是维护一个思维树,其中每个思维都代表一个连贯的语言序列,作为解决问题的一个中间步骤。模型随后可以通过从树中的不同节点进行分支来探索不同的推理路径。有一个很棒的notebook,其中更详细地展示了思维树(ToT),该notebook基于论文《大型语言模型引导的思维树》。
ReAct (推理与行动)
推理与行动(ReAct)提示是一种范例,用于使大型语言模型能够通过结合自然语言推理与外部工具(搜索、代码解释器等)来解决复杂任务,允许大型语言模型执行某些操作,例如与外部API交互以检索信息,这是迈向智能体建模的第一步。
ReAct 模仿了人类在现实世界中的运作方式,因为我们会进行语言推理并可以采取行动来获取信息。ReAct 在各种领域与其他提示工程方法相比时表现良好。
ReAct 提示的工作原理是结合推理和行动,形成一个思考-行动循环。大型语言模型首先对问题进行推理,并生成行动计划。然后执行计划中的行动并观察结果。大型语言模型随后利用观察结果更新其推理并生成新的行动计划。这个过程持续进行,直到大型语言模型找到问题的解决方案。
要亲眼看看它是如何运作的,我们需要编写一些代码。在代码片段 1 中,使用的是 Python 的 langchain 框架,结合 VertexAI (google-cloud-aiplatform) 以及 google-search-results pip 包。
要运行此示例,必须从 Sign In - SerpApi 创建一个(免费的)SerpAPI 密钥,并设置一个环境变量 SERPAPI_API_KEY。
接下来,我们编写一些 Python 代码,大型语言模型的任务是找出:Metallica 乐队中著名成员共有多少个孩子。
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.llms import VertexAI
prompt = "How many kids do the band members of Metallica have?"
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)
代码片段 1. 使用 LangChain 和 VertexAI 创建 ReAct 智能体
代码片段 2 展示了结果。注意,ReAct 进行了五次链式搜索。事实上,大型语言模型正在抓取 Google 搜索结果,以找出乐队成员的名字。然后,它将结果列为观察项,并将思维链导向下一个搜索。
> Entering new AgentExecutor chain...
Metallica has 4 members.
Action: Search
Action Input: How many kids does James Hetfield have?
Observation: three children
Thought: 1/4 Metallica band members have 3 children
Action: Search
Action Input: How many kids does Lars Ulrich have?
Observation: 3
Thought: 2/4 Metallica band members have 6 children
Action: Search
Action Input: How many kids does Kirk Hammett have?
Observation: Hammett has been married to his second wife Lani since 1998.
They have two sons, Angel (b. September 29, 2006) and Vincenzo (b. June
28, 2008).
Thought: 3/4 Metallica band members have 8 children
Action: Search
Action Input: How many kids does Robert Trujillo have?
Observation: 2
Thought: 4/4 Metallica band members have 10 children
Final Answer: 10
代码片段 2. 在终端中执行 ReAct 智能体
代码片段 2 找出 Metallica 乐队有四名成员。然后,它会搜索每一位乐队成员,查询其孩子的总数,并将这些总数相加。最后,它返回孩子的总数作为最终答案。在实践中,ReAct 提示需要理解,需要不断地重新发送之前的提示/响应(并对额外生成的内容进行修剪),以及使用适当的示例/指令设置模型。请参考托管在 GoogleCloudPlatform Github 仓库中的 notebook14,其中将更详细地介绍并展示实际的大型语言模型输入和输出,并提供一个更详尽的示例。
自动化提示工程
到此我们可能意识到,编写提示可能很复杂。如果能自动化这个过程就好了(编写一个提示来编写提示)?对了,有一种方法就是:自动化提示工程(APE)。这种方法不仅减轻了对人工输入的依赖,还增强了模型在各种任务中的性能。我们将提示一个模型来生成更多提示。评估这些提示,并可能修改好的那些。然后重复这个过程。例如,我们可以使用自动化提示工程来帮助训练一个用于销售周边T恤的网店的聊天机器人。我们想找出顾客在购买乐队周边T恤时,可能如何表达他们的订单的所有不同方式。
1. 编写将生成输出变体的提示。在此示例中,我使用的是 gemini-pro 来生成 10 个指令。见表 15:
提示 | 我们有一个乐队周边T恤的网店,为了训练一个聊天机器人,我们需要各种不同的下单方式:“一件 S 码的 Metallica T恤”。生成 10 个变体,具有相同的语义,但保持相同的意思。 | ||
输出尝试1 | 1. 我想购买一件 S 码的 Metallica T恤。 2. 我可以订购一件小号的 Metallica T恤吗? 3. 我想买一件小号的 Metallica T恤。 4. 一件 Metallica T恤,小号。 5. 我要一件 S 码的 Metallica T恤。 6. 我想下单购买一件小号的 Metallica T恤。 7. 小号的 Metallica T恤,来一件。 8. 我想找一件小号的 Metallica T恤。 9. 你能给我拿一件小号的 Metallica T恤吗? 10. 一件 Metallica 小号 T恤。 |
表 15. 利用大型语言模型生成提示
2. 基于选定的度量标准,通过对所有指令候选进行评分来评估它们,例如,可以使用 BLEU(双语评估替补)或 ROUGE(面向召回的摘要评估替补)。
3. 选择评估得分最高的指令候选。这个候选将是我们可以在我们的软件应用或聊天机器人中使用的最终提示。我们也可以调整选定的提示并再次评估。