目录
2.13 Program-Aided Language Models
0 完整章节内容
本文为李宏毅学习笔记——2024春《GENERATIVE AI》篇——“拓展内容(第2~3讲)”章节的拓展部分笔记,完整内容参见:
李宏毅学习笔记——2024春《GENERATIVE AI》篇
1 提示工程简介
提示工程是一个较新的学科,应用于开发和优化提示词(Prompt),帮助用户有效地将语言模型用于各种应用场景和研究领域。掌握了提示工程相关技能将有助于用户更好地了解大型语言模型的能力和局限性。研究人员可利用提示工程来提高大语言模型处理复杂任务场景的能力,如问答和算术推理能力。开发人员可通过提示工程设计和研发出强大的技术,实现和大语言模型或其他生态工具的高效接轨。
本指南介绍了提示词相关的基础知识,帮助用户了解如何通过提示词和大语言模型进行交互并提供指导建议。
除非另有说明,本指南默认所有示例都是在 OpenAI 的 Playground 上使用
gpt-3.5-turbo
进行测试。模型使用默认配置,即 temperature=1 和 top_p=1 。这些提示也应适用于具有类似功能的其他模型,如gpt-3.5-turbo,但模型响应可能会有所不同。
1.1 大语言模型设置
使用提示词时,您通常会通过 API 或直接与大语言模型进行交互。你可以通过配置一些参数以获得不同的提示结果。调整这些设置对于提高响应的可靠性非常重要,你可能需要进行一些实验才能找出适合您的用例的正确设置。以下是使用不同LLM提供程序时会遇到的常见设置:
-
Temperature:
- 控制生成结果的随机性。
- 低值(如 QA 或事实性任务):返回更确定、更简洁的结果。
- 高值(如诗歌或创造性任务):生成更多样化和创造性的输出。
-
Top_p:
- 控制模型选择的词元集合的概率范围。
- 低值:生成更有信心、准确的答案。
- 高值:考虑更多可能性,生成更丰富的响应。
- 注意:一般只调整 Temperature 或 Top_p 中的一个即可,不建议同时调整。
-
Max Length:限制生成响应的最大 token 数,防止生成过长或不相关的内容,控制生成成本。
-
Stop Sequences:指定一个停止字符串,限制模型生成到特定条件时停止。适用于控制列表长度或响应结构。
-
Frequency Penalty:
- 惩罚响应中出现次数较多的 token,减少重复。
- 适合希望避免词语多次重复的场景。
-
Presence Penalty:
- 惩罚重复出现的 token,无论出现次数多少,惩罚强度相同。
- 高值:生成更多样化的文本。
- 低值:生成更专注的内容。
- 注意:建议只调整 Frequency Penalty 或 Presence Penalty 中的一个。
核心建议:
- Temperature 与 Top_p 互斥,调整一个即可。
- Frequency Penalty 与 Presence Penalty 互斥,调整一个即可。
- 根据具体任务(如事实性或创造性)灵活调整参数,以优化生成质量。
1.2 基本概念
1)提示词(Prompt):
提示词是与语言模型互动的主要方式,内容可以是指令、问题、上下文或示例等。提示的质量直接影响模型输出的结果,更多的上下文和具体指示能帮助模型生成更精准的回答。
2)三个角色:
-
三个角色:在 OpenAI 的 GPT-4 或 GPT-3.5-turbo 模型中,构建提示词时可以使用三个角色:
- system:用于设定助手(assistant)的整体行为和目标,帮助模型理解用户需求(可选,但有助于优化表现)。
- user:用户发送的消息,通常作为提示词的主体。
- assistant:模型的响应,可以通过定义示例来指导模型的回答方式。
-
简化提示:在大多数情况下,示例中只使用用户消息(user)作为提示词,模型根据这个提示生成响应。
-
设置助手行为:通过定义
system
角色,可以为模型设定特定的行为和任务目标,从而提高响应的相关性和质量。
3)基本示例:
简短提示:“The sky is” 会得到“blue”作为输出,但没有提供足够上下文。
改进后的提示:“Complete the sentence: The sky is” 提供了明确的指示,输出更符合预期:“blue during the day and dark at night”。
4)提示格式:
- 标准格式:
问题形式:<问题>?
指令形式:<指令>
- 问答格式:常用于零样本提示,结构为
Q: <问题>? A: <答案>
。
请记住,使用问答格式并非必须。提示格式取决于手头的任务
5)零样本提示:
在没有示范的情况下,直接提出问题或指令,模型根据训练数据推断回答。复杂任务的执行质量可能因任务本身的难度和模型的训练情况而异。
6)少样本提示:
提供少量示例帮助模型理解任务,这对于许多任务(如文本分类)非常有效。例如:
输入:
This is awesome! // Positive
This is bad! // Negative
Wow that movie was rad! // Positive
What a horrible show! //
输出:
Negative
提供正面和负面句子的示例,帮助模型理解情感分析任务。
1.3 提示词要素
提示词通常由以下几个要素组成:
- 指令:明确告诉模型需要执行的任务或操作。例如:“将文本分类为中性、否定或肯定”。
- 上下文:提供额外的背景信息或相关资料,帮助模型更好地理解任务。上下文是可选的,但在一些复杂任务中非常有用。
- 输入数据:用户输入的内容或问题,是模型需要处理的实际数据。例如:“我觉得食物还可以”。
- 输出指示:指定模型输出的类型或格式,帮助指导模型的回应。例如:“情绪:”来指示返回情感分类。
1.4 设计提示的通用技巧
1)从简单开始:在设计提示时,建议从简单的提示开始,并逐步添加更多元素和上下文。通过不断迭代,你可以优化提示,直到获得最佳结果。
2)指令的使用:使用简单的命令(如“写入”、“分类”、“总结”、“翻译”等)来指导模型执行任务。通过实验不同的指令和上下文,找到最适合的提示方式。
3)具体性:提示越具体和详细,生成的结果通常越好。明确说明你希望模型执行的任务,尤其是在对结果风格和格式有明确要求时。示例可以帮助确保输出的准确性和格式一致。
提取以下文本中的地名。
所需格式:
地点:<逗号分隔的公司名称列表>
输入:“虽然这些发展对研究人员来说是令人鼓舞的,但仍有许多谜团。里斯本未知的香帕利莫德中心的神经免疫学家 Henrique Veiga-Fernandes 说:“我们经常在大脑和我们在周围看到的效果之间有一个黑匣子。”“如果我们想在治疗背景下使用它,我们实际上需要了解机制。””
地点:里斯本,香帕利莫德中心
4)避免模糊不清:提示应简洁、具体,避免使用模糊或不明确的语言。越直接、清晰,模型的回应越符合预期。
模糊不清:
解释提示工程的概念。保持解释简短,只有几句话,不要过于描述。
清晰的:
使用 2-3 句话向高中学生解释提示工程的概念。
5)强调要做什么:提示时应聚焦于“要做什么”而不是“不要做什么”。明确的任务描述有助于模型生成更合适的回应。
不好的:
以下是向客户推荐电影的代理程序。不要询问兴趣。不要询问个人信息。
客户:请根据我的兴趣推荐电影。
代理:
好的:
以下是向客户推荐电影的代理程序。代理负责从全球热门电影中推荐电影。它应该避免询问用户的偏好并避免询问个人信息。如果代理没有电影推荐,它应该回答“抱歉,今天找不到电影推荐。”。
```顾客:请根据我的兴趣推荐一部电影。
客服:
1.5 提示词示例
1)文本概括
Input:
Antibiotics are a type of medication used to treat bacterial infections. They work by either killing the bacteria or preventing them from reproducing, allowing the body’s immune system to fight off the infection. Antibiotics are usually taken orally in the form of pills, capsules, or liquid solutions, or sometimes administered intravenously. They are not effective against viral infections, and using them inappropriately can lead to antibiotic resistance.
Explain the above in one sentence:
译注:Explain the above in one sentence
可翻译为用一句话解释上面的信息:
Output:
Antibiotics are medications used to treat bacterial infections by either killing the bacteria or stopping them from reproducing, but they are not effective against viruses and overuse can lead to antibiotic resistance.
2)信息提取
Input:
Author-contribution statements and acknowledgements in research papers should state clearly and specifically whether, and to what extent, the authors used AI technologies such as ChatGPT in the preparation of their manuscript and analysis. They should also indicate which LLMs were used. This will alert editors and reviewers to scrutinize manuscripts more carefully for potential biases, inaccuracies and improper source crediting. Likewise, scientific journals should be transparent about their use of LLMs, for example when selecting submitted manuscripts.
Mention the large language model based product mentioned in the paragraph above:
Output:
The large language model based product mentioned in the paragraph above is ChatGPT.
3)问答
Input:
Answer the question based on the context below. Keep the answer short and concise. Respond "Unsure about answer" if not sure about the answer.Context: Teplizumab traces its roots to a New Jersey drug company called Ortho Pharmaceutical. There, scientists generated an early version of the antibody, dubbed OKT3. Originally sourced from mice, the molecule was able to bind to the surface of T cells and limit their cell-killing potential. In 1986, it was approved to help prevent organ rejection after kidney transplants, making it the first therapeutic antibody allowed for human use.Question: What was OKT3 originally sourced from?
Answer:
Output:
Mice.
4)文本分类
Input:
Classify the text into neutral, negative or positive.
Text: I think the food was okay.
Sentiment:
Output:
Neutral
5)对话
Input:
The following is a conversation with an AI research assistant. The assistant tone is technical and scientific.Human: Hello, who are you?
AI: Greeting! I am an AI research assistant. How can I help you today?
Human: Can you tell me about the creation of blackholes?
AI:
Output:
Sure! Black holes are regions of spacetime where the gravitational force is so strong that nothing, not even light, can escape from it. They are created when a very massive star dies and its core collapses in on itself, forming a singularity of infinite density. The intense gravity of the singularity pulls in all the matter and radiation around it, creating the black hole.
6)代码生成
Input:
"""
Table departments, columns = [DepartmentId, DepartmentName]
Table students, columns = [DepartmentId, StudentId, StudentName]
Create a MySQL query for all students in the Computer Science Department
"""
Output:
SELECT StudentId, StudentName
FROM students
WHERE DepartmentId IN (SELECT DepartmentId FROM departments WHERE DepartmentName = 'Computer Science');
7)推理
Input:
The odd numbers in this group add up to an even number: 15, 32, 5, 13, 82, 7, 1.
Solve by breaking the problem into steps. First, identify the odd numbers, add them, and indicate whether the result is odd or even.
Output:
Odd numbers: 15, 5, 13, 7, 1Sum: 41 41 is an odd number.
2 提示技术
2.1 零样本提示
零样本提示指的是无需提供示例,仅通过提示让语言模型完成任务的能力。例如,通过一句指令“将文本分类为中性、负面或正面”,模型可以直接给出分类结果。这种能力得益于LLM通过大量数据的训练以及指令调整的优化。
关键点:
- 零样本能力:无需示例,模型可直接完成任务。
- 指令调整:通过微调模型,使其能更好理解并执行指令描述的任务。
- RLHF(来自人类反馈的强化学习):进一步改进模型,使其符合人类偏好,例如ChatGPT的开发。
输入:
将文本分类为中性、负面或正面。
文本:我认为这次假期还可以。
情感:
输出:
中性
2.2 少样本提示
少样本提示(Few-shot Prompting)是通过在提示中加入示例来引导语言模型完成任务的技术。这种方法弥补了零样本提示在复杂任务上的不足,利用上下文学习增强模型表现。
关键点如下:
-
原理:在提示中提供演示示例(如1-shot, 3-shot),使模型能够从这些示例中学习任务模式。
示例条件化了任务语境,模型根据这些条件生成更准确的结果。 -
特性:
- 随模型规模增加,少样本提示能力显现(Kaplan et al., 2020)。
- 演示格式和标签分布对性能有显著影响:
- 格式的一致性提升模型表现。
- 随机标签比无标签更有效。
- 从真实标签分布中选择标签进一步优化结果。
-
限制:
- 对于复杂推理任务,如数值计算或多步骤逻辑推理,少样本提示表现可能不佳。
- 示例数量有限时,模型可能无法学到足够信息,需要更复杂的提示策略。
-
示例结果:
- 在简单任务(如情感分类)中,少样本提示表现良好,即使标签随机化或格式不一致。
- 在复杂任务(如奇数求和判断)中,模型未能通过少样本提示提供正确答案。
-
改进方向:
- 使用分步推理方法(如思维链提示,Chain-of-Thought Prompting)解决更复杂任务。
- 考虑微调模型以弥补提示不足。
例子:
输入:
“whatpu”是坦桑尼亚的一种小型毛茸茸的动物。一个使用whatpu这个词的句子的例子是:我们在非洲旅行时看到了这些非常可爱的whatpus。
“farduddle”是指快速跳上跳下。一个使用farduddle这个词的句子的例子是:
输出:
当我们赢得比赛时,我们都开始庆祝跳跃。
2.3 链式思考(CoT)
2.3.1 链式思考(CoT)提示
链式思考(Chain-of-Thought, CoT)提示是一种通过明确推理步骤解决复杂任务的提示技术。CoT通过将任务分解为多个中间步骤,提升了模型在复杂推理、算术和常识任务上的表现。以下是关键内容的提炼:
- 在回答之前通过明确的中间推理步骤进行复杂任务处理。
- 可以与少样本提示结合,提供少量示例并逐步推导出答案。
输入:
这组数中的奇数加起来是偶数:4、8、9、15、12、2、1。
A:将所有奇数相加(9、15、1)得到25。答案为False。
这组数中的奇数加起来是偶数:17、10、19、4、8、12、24。
A:将所有奇数相加(17、19)得到36。答案为True。
这组数中的奇数加起来是偶数:16、11、14、4、8、13、24。
A:将所有奇数相加(11、13)得到24。答案为True。
这组数中的奇数加起来是偶数:17、9、10、12、13、4、2。
A:将所有奇数相加(17、9、13)得到39。答案为False。
这组数中的奇数加起来是偶数:15、32、5、13、82、7、1。
A:
输出:
将所有奇数相加(15、5、13、7、1)得到41。答案为False。
2.3.2 零样本CoT(Zero-shot CoT)
- 简单地在提示中添加“让我们逐步思考”,无需提供示例,模型即开始分步推理。
- 示例:苹果计算问题在添加推理指令后,准确得出答案。
输入:
我去市场买了10个苹果。我给了邻居2个苹果和修理工2个苹果。然后我去买了5个苹果并吃了1个。我还剩下多少苹果?
让我们逐步思考。
输出:
首先,您从10个苹果开始。您给了邻居和修理工各2个苹果,所以您还剩下6个苹果。
然后您买了5个苹果,所以现在您有11个苹果。
最后,您吃了1个苹果,所以您还剩下10个苹果。
2.3.3 自动链式思考(Auto-CoT)
-
简介:
- 自动化生成推理链,减少人工设计的负担。
- 基于聚类和启发式选择生成多样化的示例。
-
两阶段流程:
- 问题聚类:将问题划分为多组,保证问题的多样性。
- 演示抽样:从每组中选取代表性问题,并使用零样本CoT生成推理链。
-
特点:
- 自动化设计提升效率,生成多样化且精准的示例。
- 使用启发式方法(如问题长度、推理步骤数)确保示例简洁高效。
2.4 自我一致性
-
采样多个推理路径:通过多次采样生成不同的推理链,每条链可以通向一个潜在答案。
-
选择最一致的答案:使用某种投票机制(如统计学上的多数投票),选择生成答案中最频繁出现的那个作为最终输出。
-
改进传统解码:替代贪婪解码(Greedy Decoding),避免单一推理路径导致错误答案。
例子1:
输入:
当我6岁时,我的妹妹是我的一半年龄。现在我70岁了,我的妹妹多大?
输出:
35
输出是错误的!我们如何通过自我一致性来改进这个问题?让我们试试。我们将使用 Wang 等人 2022 年的少量样本范例:
例子2:
输入:
Q:林中有15棵树。林业工人今天将在林中种树。完成后,将有21棵树。林业工人今天种了多少棵树?
A:我们从15棵树开始。后来我们有21棵树。差异必须是他们种树的数量。因此,他们必须种了21-15 = 6棵树。答案是6。
Q:停车场有3辆汽车,又来了2辆汽车,停车场有多少辆汽车?
A:停车场已经有3辆汽车。又来了2辆。现在有3 + 2 = 5辆汽车。答案是5。
Q:Leah有32块巧克力,她的姐姐有42块。如果他们吃了35块,他们总共还剩多少块?
A:Leah有32块巧克力,Leah的姐姐有42块。这意味着最初有32 + 42 = 74块巧克力。已经吃了35块。因此,他们总共还剩74-35 = 39块巧克力。答案是39。
Q:Jason有20个棒棒糖。他给Denny一些棒棒糖。现在Jason只有12个棒棒糖。Jason给Denny多少棒棒糖?
A:Jason有20个棒棒糖。因为他现在只有12个,所以他必须把剩下的给Denny。他给Denny的棒棒糖数量必须是20-12 = 8个棒棒糖。答案是8。
Q:Shawn有五个玩具。圣诞节,他从他的父母那里得到了两个玩具。他现在有多少个玩具?
A:他有5个玩具。他从妈妈那里得到了2个,所以在那之后他有5 + 2 = 7个玩具。然后他从爸爸那里得到了2个,所以总共他有7 + 2 = 9个玩具。答案是9。
Q:服务器房间里有9台计算机。从周一到周四,每天都会安装5台计算机。现在服务器房间里有多少台计算机?
A:从周一到周四有4天。每天都添加了5台计算机。这意味着总共添加了4 * 5 =
20台计算机。一开始有9台计算机,所以现在有9 + 20 = 29台计算机。答案是29。
Q:Michael有58个高尔夫球。星期二,他丢失了23个高尔夫球。星期三,他又丢失了2个。星期三结束时他还剩多少个高尔夫球?
A:Michael最初有58个球。星期二他丢失了23个,所以在那之后他有58-23 = 35个球。星期三他又丢失了2个,所以现在他有35-2 = 33个球。答案是33。
Q:Olivia有23美元。她用每个3美元的价格买了五个百吉饼。她还剩多少钱?
A:她用每个3美元的价格买了5个百吉饼。这意味着她花了15美元。她还剩8美元。
Q:当我6岁时,我的妹妹是我的一半年龄。现在我70岁了,我的妹妹多大?
A:
输出1:
当我6岁时,我的妹妹是我的一半年龄,也就是3岁。现在我70岁了,所以她是70-3 = 67岁。答案是67。
输出2:
当叙述者6岁时,他的妹妹是他年龄的一半,也就是3岁。现在叙述者70岁了,他的妹妹应该是70-3 = 67岁。答案是67。
输出3:
当我6岁时,我的妹妹是我的一半年龄,也就是3岁。现在我70岁了,所以她是70/2 = 35岁。答案是35。
2.5 生成知识提示
生成知识提示 是 Liu 等人(2022)提出的一种技术,用于在预测任务之前生成与问题相关的知识。其核心思想是让模型利用生成的知识作为提示来改进回答的准确性。这种方法尤其适用于需要广泛常识或领域知识的推理任务,例如常识问答、逻辑推理等。
背景与动机
- LLM 有时会因为缺乏相关的世界知识而在推理任务中犯错。
- 提供明确的上下文知识可以帮助模型更准确地理解和回答问题。
- 生成知识提示 (GENKNOW) 的关键是在回答问题前,先生成一段与问题相关的知识,并将其作为提示的一部分。
示例1:
输入:
高尔夫球的一部分是试图获得比其他人更高的得分。是或否?
输出:
是。
示例2:
输入:
输入:希腊比墨西哥大。
知识:希腊的面积约为131,957平方公里,而墨西哥的面积约为1,964,375平方公里,使墨西哥比希腊大了1,389%。
输入:眼镜总是会起雾。
知识:当你的汗水、呼吸和周围的湿度中的水蒸气落在冷的表面上,冷却并变成微小的液滴时,会在眼镜镜片上产生冷凝。你看到的是一层薄膜。你的镜片相对于你的呼吸会比较凉,尤其是当外面的空气很冷时。
输入:鱼有思考能力。
知识:鱼比它们看起来更聪明。在许多领域,如记忆力,它们的认知能力与或超过非人类灵长类动物等“更高级”的脊椎动物。鱼的长期记忆帮助它们跟踪复杂的社交关系。
输入:一个人一生中吸烟很多香烟的常见影响是患肺癌的几率高于正常水平。
知识:那些一生中平均每天吸烟不到一支香烟的人,患肺癌的风险是从不吸烟者的9倍。在每天吸烟1到10支香烟之间的人群中,死于肺癌的风险几乎是从不吸烟者的12倍。
输入:一块石头和一颗卵石大小相同。
知识:卵石是一种根据Udden-Wentworth沉积学尺度的颗粒大小为4到64毫米的岩屑。卵石通常被认为比颗粒(直径2到4毫米)大,比卵石(直径64到256毫米)小。
输入:高尔夫球的一部分是试图获得比其他人更高的得分。
知识:
知识1:
问题:高尔夫球的一部分是试图获得比其他人更高的得分。是或否?
知识:高尔夫球的目标是以最少的杆数打完一组洞。一轮高尔夫球比赛通常包括18个洞。每个洞在标准高尔夫球场上一轮只打一次。每个杆计为一分,总杆数用于确定比赛的获胜者。
解释和答案:
输出:
不是,高尔夫球的目标不是获得比其他人更高的得分。相反,目标是以最少的杆数打完一组洞。总杆数用于确定比赛的获胜者,而不是总得分。
知识2:
问题:高尔夫球的一部分是试图获得比其他人更高的得分。是或否?
知识:高尔夫球是一项精密的球杆运动,竞争选手(或高尔夫球手)使用许多类型的球杆,用最少的杆数将球打入球场上一系列洞中。目标是以最低的分数完成比赛,该分数是通过将每个洞上所用的杆数相加计算出来的。得分最低的选手赢得比赛。
解释和答案:
输出:
是的,高尔夫球的一部分是试图获得比其他人更高的得分。每个选手都试图以最少的杆数打完一组洞。总杆数用于确定比赛的获胜者,而不是总得分。得分最低的选手赢得比赛。
2.6 Prompt Chaining
链式提示 (Prompt Chaining) 是一种提示工程技术,将复杂任务分解为一系列子任务,通过多个提示逐步完成任务。每个提示生成的输出可以作为下一个提示的输入,直到任务完成。这种方法提升了任务的可控性和透明度,同时也增强了模型处理复杂任务的能力。
链式提示的特点
- 任务分解:将复杂任务拆解为多个子任务,每个子任务独立完成,降低模型出错的概率。
- 提升性能:针对性地解决每个子任务,使整体任务更高效可靠。
- 增强透明度:便于定位问题所在,改进每个阶段的表现。
- 提高可控性:通过精细的链条设计,确保最终结果符合预期。
示例:
提示1输入:
你是一个很有帮助的助手。你的任务是根据文档回答问题。第一步是从文档中提取与问题相关的引文,由####分隔。请使用<quotes></quotes>输出引文列表。如果没有找到相关引文,请回应“未找到相关引文!”。
####
{{文档}}
####
输出:
<quotes>
- Chain-of-thought (CoT) prompting[27]
- Generated knowledge prompting[37]
- Least-to-most prompting[38]
- Self-consistency decoding[39]
- Complexity-based prompting[41]
- Self-refine[42]
- Tree-of-thought prompting[43]
- Maieutic prompting[45]
- Directional-stimulus prompting[46]
- Textual inversion and embeddings[59]
- Using gradient descent to search for prompts[61][62][63][64]
- Prompt injection[65][66][67]
</quotes>
提示2输入:
根据从文档中提取的相关引文(由<quotes></quotes>分隔)和原始文档(由####分隔),请构建对问题的回答。请确保答案准确、语气友好且有帮助。
####
{{文档}}
####
<quotes>
- Chain-of-thought (CoT) prompting[27]
- Generated knowledge prompting[37]
- Least-to-most prompting[38]
- Self-consistency decoding[39]
- Complexity-based prompting[41]
- Self-refine[42]
- Tree-of-thought prompting[43]
- Maieutic prompting[45]
- Directional-stimulus prompting[46]
- Textual inversion and embeddings[59]
- Using gradient descent to search for prompts[61][62][63][64]
- Prompt injection[65][66][67]
</quotes>
输出:
文档中提到的提示技术包括:
1. Chain-of-thought (CoT) prompting[27]
2. Generated knowledge prompting[37]
3. Least-to-most prompting[38]
4. Self-consistency decoding[39]
5. Complexity-based prompting[41]
6. Self-refine[42]
7. Tree-of-thought prompting[43]
8. Maieutic prompting[45]
9. Directional-stimulus prompting[46]
10. Textual inversion and embeddings[59]
11. Using gradient descent to search for prompts[61][62][63][64]
12. Prompt injection[65][66][67]
每一种技术都采用独特的策略来增强或明确与大型语言模型的互动,以产生期望的结果。
2.7 思维树(ToT)
思维树(ToT)是一种基于思维链提示 (Chain of Thought, CoT) 的框架,用于解决复杂问题,尤其是那些需要探索、推理或战略规划的任务。由 Yao et al. (2023) 提出,ToT 引入了树状结构和搜索算法,使语言模型能够更系统地处理问题,通过验证和回溯来优化解答路径。
2.7.1 ToT 框架原理:
-
思维表示
- 每个思维是一个中间步骤,由连贯的语言序列表示。
- 这些步骤可以分阶段生成,并逐步探索更优解。
-
搜索与评估
- ToT 将语言模型生成的步骤结合经典搜索算法(如广度优先搜索 BFS、深度优先搜索 DFS、集束搜索 Beam Search),以系统地探索解答空间。
- 在每个步骤中,模型对候选选项进行评估,标记为:
- "Sure":一定正确的选项;
- "Maybe":可能正确的选项;
- "Impossible":一定错误的选项。
-
验证与回溯
- 对候选选项进行局部验证,通过逻辑或常识排除不合理的解,保留潜在可行路径。
- 如果当前路径无效,系统回溯到上一级继续探索。
2.7.2 例子:算 24 游戏
- 任务:给定四个数字,通过加减乘除得到 24。
- ToT 分解:
- 将任务分成 3 个中间步骤(每步生成一个中间方程)。
- 在每一步中,模型生成 5 个候选选项,并对其进行评估(Sure/Maybe/Impossible)。
- 使用广度优先搜索探索解答路径,验证是否能达到 24。
从下图中报告的结果来看,ToT 的表现大大超过了其他提示方法:
从大方向上来看,Yao et el. (2023) 和 Long (2023) 的核心思路是类似的。两种方法都是以多轮对话搜索树的形式来增强 LLM 解决复杂问题的能力。主要区别在于 Yao et el. (2023) 采用了深度优先(DFS)/广度优先(BFS)/集束(beam)搜索,而 Long (2023) 则提出由强化学习(Reinforcement Learning)训练出的 “ToT 控制器”(ToT Controller)来驱动树的搜索策略(包括什么时候回退和搜索到哪一级回退等等)。深度优先/广度优先/集束搜索是通用搜索策略,并不针对具体问题。相比之下,由强化学习训练出的 ToT 控制器有可能从新的数据集学习,或是在自对弈(AlphaGo vs. 蛮力搜索)的过程中学习。因此,即使采用的是冻结的 LLM,基于强化学习构建的 ToT 系统仍然可以不断进化,学习新的知识。
2.7.3 思维树(ToT)提示法
Hulbert (2023) 提出了思维树(ToT)提示法,将 ToT 框架的主要概念概括成了一段简短的提示词,指导 LLM 在一次提示中对中间思维做出评估。ToT 提示词的例子如下:
假设三位不同的专家来回答这个问题。
所有专家都写下他们思考这个问题的第一个步骤,然后与大家分享。
然后,所有专家都写下他们思考的下一个步骤并分享。
以此类推,直到所有专家写完他们思考的所有步骤。
只要大家发现有专家的步骤出错了,就让这位专家离开。
请问...
2.7.4 ToT 与其他提示技术的比较
2.8 检索增强生成(RAG)
检索增强生成(Retrieval-Augmented Generation,RAG)是一种将语言模型(如 GPT 等)与信息检索组件结合的方法,专门用于处理知识密集型任务。通过实时检索相关信息,RAG 能够动态扩展模型的知识范围,生成更加准确、可靠且与事实一致的输出。这种方法特别适合需要外部背景知识的任务,同时有效缓解语言模型常见的“幻觉”(hallucination)问题。
RAG 的工作机制
RAG 的架构由两个主要部分组成:
-
检索器
- 负责根据输入问题从知识库(如维基百科、文档数据库等)中检索出相关文档。
- 检索器通常使用密集向量检索(DPR)技术,通过神经网络编码的向量空间高效匹配文档。
-
生成器:将输入问题和检索到的文档作为联合上下文,通过生成模型(通常是预训练的 seq2seq 模型,如 BART 或 T5)生成最终的答案。
2.9 自动推理并使用工具(ART)
自动推理并使用工具(Automatic Reasoning and Tool-use,ART)是一个新型框架,旨在结合语言模型(LLM)和外部工具,自动生成多步推理程序以完成复杂任务。由 Paranjape 等人 (2023) 提出的 ART 通过零样本推理,减少了手写示范的需求,并在任务复杂性和泛化能力上表现卓越。
ART 的关键思想是动态集成 LLM 的推理能力和外部工具的功能,以应对需要多步推理和特定工具支持的任务。
主要步骤:
-
任务库和工具库初始化
- 任务库包含示范案例,展示如何完成多步推理任务以及在合适的步骤调用工具。
- 工具库包含可以被模型调用的外部工具(如计算器、搜索引擎、翻译器等)。
-
推理程序自动生成
- 在新任务到来时,ART 自动从任务库中总结适用的多步推理示范,并拆解为中间步骤。
- 在推理过程中,如果需要工具支持,ART 会暂停生成,调用外部工具,将工具的输出整合后继续推理。
-
自动化与扩展性
- ART 使用冻结的 LLM,因此无需进一步训练。
- 更新任务库和工具库即可轻松扩展其能力,例如修正错误的推理逻辑或添加新的工具。
在 BigBench 和 MMLU 基准测试中,ART 在未见任务上的表现大大超过了少样本提示和自动 CoT;配合人类反馈后,其表现超过了手写的 CoT 提示。
下面这张表格展示了 ART 在 BigBench 和 MMLU 任务上的表现:
2.10 自动提示工程师
自动提示工程师(Automatic Prompt Engineer,APE)是由 Zhou 等人 (2022) 提出的一个框架,旨在自动化生成和选择提示指令,优化语言模型(LLM)的任务执行效果。APE 通过将指令生成问题建模为自然语言合成问题,并利用 LLM 作为“黑盒”优化工具,生成和搜索最合适的提示指令。
APE 的工作原理分为两个主要步骤:
-
生成候选指令:使用一个大型语言模型作为推理模型,输入一些输出示范,并生成一组任务的指令候选项。每个候选指令将引导后续的搜索过程。
-
选择最合适的指令:通过目标模型执行这些指令,并根据模型评估分数选择最适合的指令。这样,APE 可以自动化优化任务执行时所需的提示。
传统的提示工程通常依赖人工设计的固定模板或预定义的模式,如“让我们一步一步地解决这个问题”。然而,APE 自动优化提示,通过搜索和评估候选解来提供更高效的提示。
本文涉及与提示工程相关的重要主题,即自动优化提示的想法。虽然我们在本指南中没有深入探讨这个主题,但如果您对此主题感兴趣,以下是一些关键论文:
- Prompt-OIRL - 使用离线逆强化学习来生成与查询相关的提示。
- OPRO - 引入使用 LLMs 优化提示的思想:让 LLMs “深呼吸”提高数学问题的表现。
- AutoPrompt - 提出了一种基于梯度引导搜索的方法,用于自动创建各种任务的提示。
- Prefix Tuning - 是一种轻量级的 fine-tuning 替代方案,为 NLG 任务添加可训练的连续前缀。
- Prompt Tuning - 提出了一种通过反向传播学习软提示的机制。
2.11 Activate-Prompt
Active-Prompt 是 Diao 等人(2023)提出的一种新型提示方法,旨在解决传统思维链(CoT)方法的局限性,尤其是 CoT 方法依赖于固定的人工注释范例,这些示例可能并不适用于所有任务。Active-Prompt 的核心思想是根据任务的特定需求,动态选择和调整最有效的示例,以优化 LLM 的性能。
Active-Prompt 的流程可以概括为以下几个步骤:
-
生成候选答案:使用少量的 CoT 示例(或完全不使用)查询 LLM,对一组训练问题生成 kkk 个可能的答案。这些答案是根据当前模型的理解和推理能力生成的,覆盖不同的可能性。
-
计算不确定度度量:对生成的 kkk 个答案进行评估,计算其不确定度。具体来说,不确定度度量是基于答案之间的不一致性。例如,如果多个答案在同一问题上的输出差异很大,说明模型对该问题的理解存在较大的不确定性。
-
选择最不确定的问题进行注释:基于计算出的不确定度,选择那些模型最不确定的问题。这些问题可能是模型没有很好处理的实例,因此需要更多的人工干预。人类对这些问题进行注释,提供更精准的 CoT 推理示例,以指导模型的进一步训练。
-
使用新的注释范例进行推理:将人类注释的示例加入到训练集中,利用这些新的、经过调整的范例重新训练模型。通过这种方式,模型能在每个问题上获得更多的上下文和知识,逐步提高其推理能力。
2.12 方向性刺激提示
方向性刺激提示(DSP) 是 Li 等人(2023)提出的一种新型提示技术,旨在通过更好地引导 LLM 生成所需的摘要或输出。与传统的固定提示方法不同,DSP 使用了可调节的策略语言模型(策略 LM)来生成提示,从而优化了 LLM 的表现。
工作原理
-
策略语言模型(策略 LM)
DSP 使用一个经过训练的策略语言模型(strategy LM),该模型能够生成一系列有指导性的提示/刺激。这些提示的作用是引导 LLM 朝着正确的方向生成文本,从而实现更精确的结果。 -
优化过程
DSP 中的策略 LM 通过强化学习(RL)进行优化,以确保生成的提示能够有效地指导冻结的 LLM。强化学习的目标是让策略 LM 学习如何生成最合适的提示,以增强 LLM 在生成任务中的表现。 -
动态提示生成
DSP 不像传统的固定提示那样一成不变,而是根据任务需求动态生成能够引导模型的提示。这使得 LLM 可以根据不同的上下文和任务生成更精准的输出。
下图显示了方向性刺激提示与标准提示的比较:
2.13 Program-Aided Language Models
程序辅助语言模型(PAL) 是由 Gao 等人(2022)提出的一种方法,旨在通过将程序生成作为中间推理步骤来增强大型语言模型(LLM)的能力。与传统的思维链(CoT)方法不同,PAL 通过生成程序代码(例如 Python)来执行推理和计算,而不是依赖自然语言推理。这样可以利用编程语言的精确性和执行能力来提供更加可靠和高效的答案。
工作原理
-
问题转化为程序
PAL 通过将自然语言问题转化为程序代码来解决问题。程序可以是用于执行推理步骤的 Python 代码(或其他编程语言)。在这种方法中,推理和计算被卸载到类似 Python 解释器的环境中,而不是仅通过文本生成来解决。 -
生成代码并执行
LLM 读取输入的自然语言问题,并生成相应的程序代码。这些代码通常包括对日期、时间等的计算,或者其他需要数值计算和逻辑推理的问题。 -
通过执行代码得出答案
生成的程序代码被执行,实际的计算结果作为答案返回。这种方法能够更精确地处理需要明确计算步骤的问题,减少推理错误。
示例:日期理解
下面是如何使用 PAL 来处理日期相关问题的一个例子。我们使用 OpenAI 的 GPT-3 和 LangChain 来开发一个应用程序,能够解释并回答日期相关的问题。
1)设置环境和模型
首先,我们设置 OpenAI API 和 LangChain 环境:
import openai
from datetime import datetime
from dateutil.relativedelta import relativedelta
import os
from langchain.llms import OpenAI
from dotenv import load_dotenv
load_dotenv()
# API configuration
openai.api_key = os.getenv("OPENAI_API_KEY")
# for LangChain
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
# 设置模型实例
llm = OpenAI(model_name='text-davinci-003', temperature=0)
2)问题和提示设置
我们需要给模型提供一个提示,并定义一个日期相关问题:
question = "Today is 27 February 2023. I was born exactly 25 years ago. What is the date I was born in MM/DD/YYYY?"
DATE_UNDERSTANDING_PROMPT = """
# Q: 2015 is coming in 36 hours. What is the date one week from today in MM/DD/YYYY?
# If 2015 is coming in 36 hours, then today is 36 hours before.
today = datetime(2015, 1, 1) - relativedelta(hours=36)
# One week from today,
one_week_from_today = today + relativedelta(weeks=1)
# The answer formatted with %m/%d/%Y is
one_week_from_today.strftime('%m/%d/%Y')
# Q: The first day of 2019 is a Tuesday, and today is the first Monday of 2019. What is the date today in MM/DD/YYYY?
# If the first day of 2019 is a Tuesday, and today is the first Monday of 2019, then today is 6 days later.
today = datetime(2019, 1, 1) + relativedelta(days=6)
# The answer formatted with %m/%d/%Y is
today.strftime('%m/%d/%Y')
# Q: The concert was scheduled to be on 06/01/1943, but was delayed by one day to today. What is the date 10 days ago in MM/DD/YYYY?
# If the concert was scheduled to be on 06/01/1943, but was delayed by one day to today, then today is one day later.
today = datetime(1943, 6, 1) + relativedelta(days=1)
# 10 days ago,
ten_days_ago = today - relativedelta(days=10)
# The answer formatted with %m/%d/%Y is
ten_days_ago.strftime('%m/%d/%Y')
# Q: It is 4/19/1969 today. What is the date 24 hours later in MM/DD/YYYY?
# It is 4/19/1969 today.
today = datetime(1969, 4, 19)
# 24 hours later,
later = today + relativedelta(hours=24)
# The answer formatted with %m/%d/%Y is
today.strftime('%m/%d/%Y')
# Q: Jane thought today is 3/11/2002, but today is in fact Mar 12, which is 1 day later. What is the date 24 hours later in MM/DD/YYYY?
# If Jane thought today is 3/11/2002, but today is in fact Mar 12, then today is 3/12/2002.
today = datetime(2002, 3, 12)
# 24 hours later,
later = today + relativedelta(hours=24)
# The answer formatted with %m/%d/%Y is
later.strftime('%m/%d/%Y')
# Q: Jane was born on the last day of Feburary in 2001. Today is her 16-year-old birthday. What is the date yesterday in MM/DD/YYYY?
# If Jane was born on the last day of Feburary in 2001 and today is her 16-year-old birthday, then today is 16 years later.
today = datetime(2001, 2, 28) + relativedelta(years=16)
# Yesterday,
yesterday = today - relativedelta(days=1)
# The answer formatted with %m/%d/%Y is
yesterday.strftime('%m/%d/%Y')
# Q: {question}
""".strip() + '\n'
llm_out = llm(DATE_UNDERSTANDING_PROMPT.format(question=question))
print(llm_out)
3)生成和执行 Python 代码
模型会生成相应的 Python 代码来解决问题:
# If today is 27 February 2023 and I was born exactly 25 years ago, then I was born 25 years before.
today = datetime(2023, 2, 27)
# I was born 25 years before,
born = today - relativedelta(years=25)
# The answer formatted with %m/%d/%Y is
born.strftime('%m/%d/%Y')
然后,执行这段代码来计算出生日期:
exec(llm_out)
print(born)
输出结果:
02/27/1998
2.14 ReAct框架
ReAct(推理与行动结合)框架是一种创新的方法,通过结合推理轨迹和任务特定操作提升大语言模型(LLMs)的任务解决能力。以下是 ReAct 框架的核心内容以及如何使用它来开发智能代理。
2.14.1 ReAct 框架的特点
-
推理与行动交替
- ReAct 提示 LLMs 同时生成“思考”(推理轨迹)和“行动”(具体操作)。
- 通过推理明确任务目标,利用行动与外部工具(如搜索引擎或计算器)交互。
-
解决问题的动态规划
- 推理轨迹帮助模型构建、调整计划。
- 行动允许模型收集额外信息并利用工具执行具体任务。
-
解决常见问题
- 事实幻觉:通过获取外部信息提高答案准确性。
- 知识更新:克服LLMs知识库的时效性局限。
下图展示了 ReAct 的一个示例以及执行问题回答所涉及的不同步骤:
2.14.2 示例
下面是一个 ReAct 提示的示例(摘自论文,为简单起见缩短为一个示例):
问题 科罗拉多造山带东部区域延伸到的区域的海拔范围是多少?
思考 1 我需要搜索科罗拉多造山带,找到科罗拉多造山带东段延伸的区域,然后找到该区域的海拔范围。
操作 1 搜索 [科罗拉多造山带]
观察 1 科罗拉多造山带是科罗拉多及其周边地区造山运动的一段。
思考 2 它没有提到东部地区。所以我需要查一下东部地区。
操作 2 查找 [东部地区]
观察 2 (结果 1 / 1) 东部区域延伸至高平原,称为中原造山带。
思考 3 科罗拉多造山运动的东部区域延伸到高平原。所以我需要搜索高平原,找到它的海拔范围。
操作 3 搜索 [高平原]
观察 3 高平原指的是两个截然不同的陆地区域之一。
思考 4 我需要搜索高平原(美国)
操作 4 搜索 [高平原(美国)]
观察 4 高平原是大平原的一个分区。从东到西,高平原的海拔从 1800 到 7000 英尺 (550 到 2130 米) 不等。[3]
思考 5 高平原海拔高度从 1800 到 7000 英尺,所以答案是 1800 到 7000 英尺。
操作 5 结束 [1800 到 7000 英尺]
...
请注意,不同的提示设置用于不同类型的任务。对那些以推理为主要目标的任务 (例如 HotpotQA),多思考-操作-观察步骤用于任务-解决轨迹。对于涉及许多操作步骤的决策任务来说,则较少使用思考。
2.14.3 在知识密集型任务上的表现结果
论文首先对 ReAct 在知识密集型推理任务如问答 (HotPotQA) 和事实验证 (Fever) 上进行了评估。PaLM-540B 作为提示的基本模型。
我们还可以观察到 ReAct 在 Fever 上的表现优于 CoT,而在 HotpotQA 上落后于 CoT。文中对该方法进行了详细的误差分析。总而言之:
- CoT 存在事实幻觉的问题
- ReAct 的结构性约束降低了它在制定推理步骤方面的灵活性
- ReAct 在很大程度上依赖于它正在检索的信息;非信息性搜索结果阻碍了模型推理,并导致难以恢复和重新形成思想
2.14.4 在决策型任务上的表现结果
论文还给出了 ReAct 在决策型任务上的表现结果。ReAct 基于两个基准进行评估,分别是 ALFWorld (基于文本的游戏) 和 WebShop (在线购物网站环境)。两者都涉及复杂的环境,需要推理才能有效地行动和探索。
请注意,虽然对这些任务的 ReAct 提示的设计有很大不同,但仍然保持了相同的核心思想,即结合推理和行为。下面是一个涉及 ReAct 提示的 ALFWorld 问题示例。
ReAct 在 ALFWorld 和 Webshop 上都优于 Act。没有思考的 Act 不能正确地把目标分解成子目标。尽管在这些类型的任务中,ReAct 的推理显露出优势,但目前基于提示的方法在这些任务上的表现与人类专家相差甚远。
2.14.5 长链 ReAct 的使用
下面是 ReAct 提示方法在实践中如何工作的高阶示例。我们将在 LLM 和 langchain 中使用OpenAI,因为它已经具有内置功能,可以利用 ReAct 框架构建代理,这些代理能够结合 LLM 和其他多种工具的功能来执行任务。
1)环境配置与安装
# 安装库
!pip install --upgrade openai langchain python-dotenv google-search-results
# 引入库
import openai
import os
from langchain.llms import OpenAI
from langchain.agents import load_tools, initialize_agent
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["SERPER_API_KEY"] = os.getenv("SERPER_API_KEY")
2)配置 LLM 和工具
# 配置 LLM
llm = OpenAI(model_name="text-davinci-003", temperature=0)
# 配置工具:Google 搜索与数学计算器
tools = load_tools(["google-serper", "llm-math"], llm=llm)
# 初始化代理
agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
3)执行示例任务
# 执行任务
query = "奥利维亚·王尔德的男朋友是谁?他现在的年龄的0.23次方是多少?"
response = agent.run(query)
print(response)
4)生成回答
> 正在输入新代理执行器链......
我得查出奥利维亚·王尔德的男友是谁然后计算出他的年龄的 0.23 次方。
操作: 搜索
操作输入: “奥利维亚·王尔德的男友”
观察: 奥利维亚·王尔德与杰森·苏代基斯在多年前订婚,在他们分手后,她开始与哈里·斯泰尔斯约会 — 参照他们的关系时间线。
思考: 我需要找出哈里·斯泰尔斯的年龄。
操作: 搜索
操作输入: “哈里·斯泰尔斯的年龄”
观察: 29 岁
思考: 我需要计算 29 的 0.23 次方。
操作: 计算器
操作输入: 29^0.23
观察: 答案: 2.169459462491557
思考: 现在我知道最终答案了。
最终答案: 哈里·斯泰尔斯, 奥利维亚·王尔德的男朋友, 29 岁。他年龄的 0.23 次方是 2.169459462491557。
> 结束链。
"哈里·斯泰尔斯, 奥利维亚·王尔德的男朋友, 29 岁。他年龄的 0.23 次方是 2.169459462491557。"
2.15 Reflexion
自我反思(Reflexion)框架是一种创新方法,旨在通过语言反馈强化基于语言模型(LLM)的智能体的能力。它结合了记忆、评估和反思机制,使智能体能够通过反复试验和自我改进提高任务表现。
2.15.1 关键组成部分:
-
参与者(Actor):
- 执行任务,根据当前环境生成文本和动作。
- 使用 链式思考(CoT) 或 ReAct 生成推理和行为轨迹。
- 记忆组件为智能体提供上下文,用于存储长期经验。
-
评估者(Evaluator):
- 对参与者生成的轨迹进行评价。
- 根据任务类型,使用启发式方法或语言模型生成奖励信号。
- 奖励信号用于评估智能体行为是否达到预期效果。
-
自我反思(Self-Reflection):
- 通过分析当前轨迹和奖励信号,生成语言化的反思反馈。
- 帮助智能体总结经验并优化未来的行为。
- 反思的结果被存储在长期记忆组件中,为后续学习提供支持。
2.15.2 运作流程
Reflexion 的主要工作流程可以概括为以下几个步骤:
- 定义任务: 明确智能体需要完成的目标。
- 生成轨迹: 参与者模型根据环境状态生成推理和行动。
- 评估: 使用评估者模型对轨迹进行奖励打分。
- 执行自我反思: 自我反思模型生成改进建议,并更新记忆。
- 生成新轨迹: 利用反思反馈优化后的策略,智能体重新执行任务。
这一过程持续迭代,使智能体逐步优化其行为。
2.15.3 实验结果与优势
实验结果表明,自我反思能够显著提高 AlfWorld 上的决策任务、HotPotQA 中的问题推理以及在 HumanEval 上的 Python 编程任务性能。
在序列决策 (AlfWorld) 任务上进行评估时,ReAct + Reflexion 用启发式和 GPT 的自我评估进行二元分类,完成了 130/134 项任务,显着优于 ReAct。
在仅仅几个学习步骤中,自我反思显著优于所有基线方法。仅对于推理以及添加由最近轨迹组成的情景记忆时,Reflexion + CoT 的性能分别优于仅 CoT 和具有情景记忆的 CoT。
如下表所示,在 MBPP、HumanEval 和 Leetcode Hard 上编写 Python 和 Rust 代码时,Reflexion 通常优于之前的 SOTA 方法。
2.15.4 自我反思最适合的情况
智能体需要从尝试和错误中学习:自我反思旨在通过反思过去的错误并将这些知识纳入未来的决策来帮助智能体提高表现。这非常适合智能体需要通过反复试验来学习的任务,例如决策、推理和编程。
传统的强化学习方法失效:传统的强化学习(RL)方法通常需要大量的训练数据和昂贵的模型微调。自我反思提供了一种轻量级替代方案,不需要微调底层语言模型,从而使其在数据和计算资源方面更加高效。
需要细致入微的反馈:自我反思利用语言反馈,这比传统强化学习中使用的标量奖励更加细致和具体。这让智能体能够更好地了解自己的错误,并在后续的试验中做出更有针对性的改进。
可解释性和直接记忆很重要:与传统的强化学习方法相比,自我反思提供了一种更可解释、更直接的情景记忆形式。智能体的自我反思存储在其记忆组件中,让分析和理解其学习过程变得更加简单。
3.15.5 有效的任务:
- 序列决策:自我反思提高了智能体在 AlfWorld 任务中的表现,涉及在各种环境中导航并完成多步目标。
- 推理:自我反思提高了 HotPotQA 上智能体的性能,HotPotQA 是一个需要对多个文档进行推理的问答数据集。
- 编程:自我反思的智能体在 HumanEval 和 MBPP 等基准测试上编写出了更好的代码,在某些情况下实现 SOTA 结果。
2.15.6 一些限制:
- 依赖自我评估能力:反思依赖于智能体准确评估其表现并产生有用反思的能力。这可能是具有挑战性的,尤其是对于复杂的任务,但随着模型功能的不断改进,预计自我反思会随着时间的推移而变得更好。
- 长期记忆限制:自我反思使用最大容量的滑动窗口,但对于更复杂的任务,使用向量嵌入或 SQL 数据库等高级结构可能会更有利。
- 代码生成限制:测试驱动开发在指定准确的输入输出映射方面存在限制(例如,受硬件影响的非确定性生成器函数和函数输出)。
2.16 多模态思维链提示方法
多模态思维链提示方法(Multimodal Chain-of-Thought, MCOT) 是一种创新性的方法,结合了文本与视觉信息以增强推理能力。由 Zhang 等人(2023) 提出的 MCOT 框架拓展了传统语言模态思维链(CoT)的能力,通过引入多模态数据,更好地处理涉及图文结合的复杂推理任务。
MCOT 方法分为两个主要阶段:
第一阶段:多模态理性生成
- 输入包括文本和视觉信息(如图像和问题描述)。
- 模型基于多模态信息生成中间推理步骤(理性推理链)。
- 融合感知与语言表示,确保模型能从视觉信号中提取关键信息并将其转化为逻辑推理过程。
第二阶段:答案推断
- 使用第一阶段生成的多模态理性推理作为上下文。
- 推断最终答案,确保逻辑推理过程贯穿始终。
这一框架强化了模型的推理能力,特别是在涉及视觉感知的复杂场景中。
多模态CoT模型(1B)在ScienceQA基准测试中的表现优于GPT-3.5。
2.17 基于图的提示
GraphPrompt 是一种由 Liu 等人(2023) 提出的新型图提示框架,旨在提升图结构数据上的下游任务性能。通过将提示学习(Prompting)的思想引入图领域,GraphPrompt 展示了强大的泛化能力和对多样化任务的适应性。
2.17.1 什么是 GraphPrompt?
GraphPrompt 将图结构数据与提示学习相结合,通过设计特定的图提示(Graph Prompts),使模型能够更好地理解和处理图数据。其目标是以一种轻量化方式,通过提供上下文提示优化模型在图任务上的表现。
2.17.2 GraphPrompt 的工作流程
-
图提示生成:
- 创建与目标任务相关的提示结构,例如基于节点、边或子图的提示。
- 提示可以是手动设计的,也可以通过学习生成。
-
任务适配:
- GraphPrompt 将图提示与原始图数据结合,通过对提示的解释性增强模型的任务适配能力。
- 支持各种图任务,包括图分类、节点分类和链接预测。
-
目标任务执行:
- 在引入图提示后,模型执行下游任务。
- 这种方法避免了对大规模图神经网络(GNN)进行微调的需求,从而提高了训练效率。
2.17.3 GraphPrompt 的优势
-
轻量化学习:
- 通过提示学习避免了繁琐的微调过程,仅需设计或学习少量的图提示。
- 大幅降低了计算成本和数据需求。
-
增强泛化性:GraphPrompt 提供了跨任务和跨领域的适应能力,特别是在少样本学习或无监督环境中表现优异。
-
灵活性:
- GraphPrompt 适用于各种图数据,包括知识图谱、社交网络和生物网络。
- 支持多种任务类型,如节点分类、链接预测和图级别分类。
2.17.4 GraphPrompt 的应用场景
- 知识图谱:GraphPrompt 可用于对知识图谱中的实体和关系进行分类。
- 社交网络分析:通过提示增强社交图中的社区检测和影响力预测任务。
- 生物网络:GraphPrompt 在蛋白质相互作用预测和药物发现任务中展示了潜力。
- 推荐系统:在图表示学习中,通过提示优化推荐算法。
2.18 meta-prompting
Meta-Prompting 是一种新兴的方法,旨在通过引导模型生成更好的提示,从而优化其在多种任务中的表现。与传统的提示工程不同,Meta-Prompting 不直接为任务设计提示,而是设计用于生成提示的“元提示”(meta-prompts),让模型学习如何为自身或其他模型生成适合的提示。
2.18.1 Meta-Prompting 的核心思想
-
提示的提示:
- Meta-Prompting 的关键是通过“提示生成提示”的方式提高提示质量。
- 这种方法旨在让模型更智能地理解任务需求,并生成高度相关、任务特定的提示。
-
动态调整:Meta-Prompting 不仅能生成初始提示,还可以根据任务反馈动态调整提示,使得模型能够更快适应不同任务。
-
跨任务泛化:借助 Meta-Prompting,模型能够在一个任务上学习到的提示设计技能迁移到新的任务中,显著提高多任务处理能力。
2.18.2 Meta-Prompting 的工作流程
-
元提示生成:
- 首先为模型输入一个元提示,指导其生成任务特定的提示。
- 示例元提示:“为给定的任务生成一个高质量的提示,该提示应尽可能清晰地指导模型解决任务。”
-
提示优化:模型根据元提示生成任务提示,随后通过反复迭代优化提示,结合用户反馈或模型自身的性能反馈。
-
任务执行:使用优化后的提示完成目标任务。
-
反馈循环:根据任务输出结果调整元提示或提示内容,进一步改进任务表现。
3 提示应用
3.1 生成数据
LLMs具有生成连贯文本的强大能力。使用有效的提示策略可以引导模型产生更好、更一致和更真实的响应。LLMs还可以特别有用地生成数据,这对于运行各种实验和评估非常有用。例如,我们可以使用它来为情感分类器生成快速样本,如下所示:
输入:
生成10个情感分析的范例。示例被归类为正面或负面。生成2个负面示例和8个正面示例。使用以下格式的示例:Q:<句子>A:<情感>
输出:
Q:我刚刚得到了最好的消息!
A:正面
Q:我们刚刚在工作中得到了加薪!
A:正面
Q:我为今天所取得的成就感到非常自豪。
A:正面
Q:我度过了最美好的一天!
A:正面
Q:我真的很期待周末。
A:正面
Q:我刚刚得到了最好的礼物!
A:正面
Q:我现在感到非常快乐。
A:正面
Q:我很幸运有这么棒的家人。
A:正面
Q:外面的天气很阴沉。
A:负面
Q:我刚刚得到了一些可怕的消息。
A:负面
3.2 Generating Code
ChatGPT 等大语言模型擅长代码生成和辅助开发工作。在本节中,我们展示了如何使用 ChatGPT 提高代码编写效率,包括代码生成、编辑、调试、以及数据库相关操作。以下所有示例基于 OpenAI 的 gpt-3.5-turbo
模型和 Playground 聊天模式。
3.2.1 基础代码生成
提示示例:
我们可以使用系统消息来定义模型的行为,例如:
“您是一位有用的代码助手,可以教初级开发人员如何编写代码。您选择的语言是 Python。不解释代码,只生成代码块。”
在这种设置下,模型生成的输出更加专注于代码内容。
代码生成示例 1:
用户提示:
写一段代码询问用户他们的名字并向他们说 Hello。
生成代码:
name = input("What is your name? ")
print(f"Hello, {name}!")
3.2.2 将注释转换为代码
提示示例:
提供分步注释,模型可以直接将其转换为完整代码。
用户提示:
创建一个包含电影名称及评分的 JSON 对象,步骤如下:
- 创建一个电影名称列表
- 创建这些电影的评分列表
- 组合它们并生成一个包含 10 部电影及评分的 JSON 对象
生成代码:
import json
movies = ["The Shawshank Redemption", "The Godfather", "The Dark Knight", "Schindler's List",
"Pulp Fiction", "The Lord of the Rings: The Return of the King", "Forrest Gump",
"Star Wars: Episode V - The Empire Strikes Back", "Inception", "The Silence of the Lambs"]
ratings = [9.3, 9.2, 9.0, 8.9, 8.9, 8.9, 8.8, 8.7, 8.7, 8.6]
movie_ratings = {movies[i]: ratings[i] for i in range(len(movies))}
json_object = json.dumps(movie_ratings, indent=4)
print(json_object)
注意:模型可能忽略一些必要的细节,例如 import
语句,因此代码需要手动检查和测试。
3.2.3 完成代码功能
提示示例:
部分函数的补全是大语言模型的强项之一。
用户提示:
编写一个函数,用于将两个数字相乘并加 75。
生成代码:
def multiply(a, b):
result = a * b
result += 75
return result
3.2.4 数据库操作:MySQL 查询生成
查询生成示例:
用户提示:
Table
departments
, columns = [DepartmentId, DepartmentName]
Tablestudents
, columns = [DepartmentId, StudentId, StudentName]
创建一个查询语句,获取所有在计算机科学系的学生信息。
生成代码:
SELECT students.StudentId, students.StudentName
FROM students
INNER JOIN departments
ON students.DepartmentId = departments.DepartmentId
WHERE departments.DepartmentName = 'Computer Science';
3.2.5 创建数据库结构:
用户提示:
为上述表创建一个有效的数据库结构。
生成代码:
CREATE TABLE departments (
DepartmentId INT PRIMARY KEY,
DepartmentName VARCHAR(50)
);
CREATE TABLE students (
DepartmentId INT,
StudentId INT PRIMARY KEY,
StudentName VARCHAR(50),
FOREIGN KEY (DepartmentId) REFERENCES departments(DepartmentId)
);
3.2.6 生成测试数据:
用户提示:
基于上述结构,为每个表生成 4 条插入语句。
生成代码:
INSERT INTO departments (DepartmentId, DepartmentName)
VALUES (1, 'Computer Science'), (2, 'Mathematics'), (3, 'Physics'), (4, 'Biology');
INSERT INTO students (DepartmentId, StudentId, StudentName)
VALUES (1, 101, 'John Doe'), (1, 102, 'Jane Doe'), (2, 201, 'Alice Smith'), (2, 202, 'Bob Johnson');
3.2.7 代码解释
ChatGPT 也可以用来解释代码,帮助用户理解某段代码的逻辑或功能。
示例:
用户提示:
解释以下 SQL 查询:
SELECT students.StudentId, students.StudentName
FROM students
INNER JOIN departments
ON students.DepartmentId = departments.DepartmentId
WHERE departments.DepartmentName = 'Computer Science';
生成解释:
这个 SQL 查询从
students
表中选择学生的 ID (StudentId
) 和姓名 (StudentName
),并通过内部连接 (INNER JOIN
) 将学生的DepartmentId
与departments
表的DepartmentId
匹配。
条件WHERE departments.DepartmentName = 'Computer Science'
筛选出属于“计算机科学”系的学生。
3.3 毕业生工作分类案例研究
Clavié等人(2023)提供了一项关于提示工程应用于生产系统中中等规模文本分类用例的案例研究。通过使用将工作分类为真正的“初级职位”(是否适合应届毕业生的任务),他们评估了一系列提示工程技术,并使用GPT-3.5 (gpt-3.5-turbo)报告了他们的结果。
该研究表明,LLMs在所有经过测试的模型中表现最佳,包括DeBERTa-V3中的一个极强的基准模型。gpt-3.5-turbo在所有关键指标上也明显优于早期的GPT3变体,但需要进行额外的输出解析,因为其遵循模板的能力似乎不如其他变体。
他们的提示工程方法的关键发现是:
- 对于像这样不需要专业知识的任务,Few-shot CoT提示在所有实验中的表现都不如Zero-shot提示。
- 提示对于引导正确推理的影响非常巨大。简单地要求模型对给定的工作进行分类会得到65.6的F1分数,而后提示工程模型的F1分数为91.7。
- 试图强制模型遵循模板会降低所有情况下的性能(这种行为在GPT-4的早期测试中消失,这项测试在该论文之后进行)。
- 许多小的修改对性能产生了巨大的影响。
- 下面的表格显示了所有经过测试的修改。
- 正确地给出指令并重复关键点似乎是最有效的提升性能的方法。
- 简单地给模型一个(人类的)名字并这样称呼它,可以将F1分数提高0.6个百分点。
经本文测试的 Prompt策略
所有Prompt性能策略对性能的影响
“Template stickiness” 指的是模型多频繁地按照所期望的格式作答。
3.4 提示函数
提示函数是将提示进行封装的一种方法,使其在与 GPT 交互时具备类似编程语言中“函数”的可重用性和结构性。通过为每个提示指定一个函数名、输入参数和规则,用户可以清晰地定义与 GPT 的交互方式,并将其用于执行特定任务。这种方法不仅简化了复杂流程的实现,还能提高交互效率。
3.4.1 提示函数的主要组成部分
function_name
:函数的名称,用于标识这个提示的功能。input
:函数的输入参数,可定义单个或多个输入变量。rule
:关于如何处理输入的具体说明,是提示函数的核心内容。
结构化模板:
function_name: [函数名称]
input: ["输入参数"]
rule: [规则:描述如何处理输入,提供具体要求]
示例调用:
function_name(input)
3.4.2 创建单参数提示函数
例 1:英文翻译函数
function_name: [trans_word]
input: ["文本"]
rule: [请充当英文翻译员和拼写纠正员。我将提供一个包含"文本"的输入形式,你需要检测语言,将其翻译成英文,并改进翻译结果。]
trans_word('婆罗摩火山处于享有“千岛之国”美称的印度尼西亚.')
例 2:扩展文本函数
function_name: [expand_word]
input: ["文本"]
rule: [请充当一个语言增强员。我将提供"文本",你需要在不改变原意的前提下,将文本扩展得更加文学化和优美。]
expand_word('这是一段简单的文字。')
例 3:纠正英文函数
function_name: [fix_english]
input: ["文本"]
rule: [请充当英文拼写纠正员和语言增强员。我将提供一段包含"文本"的英文内容,你需要改进它的用词和句式,使其更自然、更优雅。保持原意。]
fix_english('This is a simple text that needs to be corrected.')
3.4.3 创建多参数提示函数
例:密码生成器函数
function_name: [pg]
input: ["length", "capitalized", "lowercase", "numbers", "special"]
rule: [作为一个密码生成器,我将为需要一个安全密码的个人提供帮助。我会提供包括"length"(长度)、"capitalized"(大写字母)、"lowercase"(小写字母)、"numbers"(数字)和"special"(特殊字符)在内的输入形式。你的任务是使用这些输入形式生成一个复杂的密码,并将其提供给我。在你的回答中,请不要包含任何解释或额外的信息,只需提供生成的密码即可。例如,如果输入形式是length = 8、capitalized = 1、lowercase = 5、numbers = 2、special = 1,你的回答应该是一个类似于"D5%t9Bgf"的密码。]
pg(length=12, capitalized=2, lowercase=6, numbers=2, special=2)
3.4.4 提示函数的应用场景
- 英语学习: 创建一系列翻译、扩展、纠正的提示函数。
- 内容生成: 定义模板化任务,如生成邮件、报告或代码片段。
- 数据处理: 创建针对性的数据清洗、格式化提示。
- 自动化工作流: 将多个提示函数串联,自动化处理复杂任务。
3.4.5 基于 GPT 的编程工具
现在,已经有许多项目正在开发基于 GPT 的编程工具,例如:
但是那些项目要么是为产品客户设计的,要么是为那些能够使用 Python 或其他编程语言进行编码的用户设计的。 对于普通用户来说,可以使用这个简单的模板进行日常工作,并进行几次迭代。使用一个笔记应用程序来记录函数,甚至可以将其更新为一个库。 或者,一些开源的 ChatGPT 工具,比如 ChatGPT-Next-Web、chatbox 和 ChatGPT-Desktop,也可以使用。目前,ChatGPT-Next-Web 允许在初始化新聊天之前添加一些片段。 我们可以利用这个功能来添加我们的函数,然后可以使用它。
3.5 Function Calling
函数调用是一种让LLM(大语言模型)与外部工具或API交互的关键能力,适用于许多实际应用场景。以下是关于如何实现和应用函数调用的全面指南,涵盖了GPT模型的调用示例以及潜在用例。
3.5.1 具体步骤
-
定义工具(函数):
- 使用JSON格式定义函数的名称、描述以及所需的参数结构。
- 确定函数的用途和功能,比如查询天气、执行数据库查询等。
-
发送用户请求:用户通过自然语言向模型提出问题或任务。
-
调用函数生成参数:模型根据用户输入,识别需要调用的函数及其参数,并以JSON对象的形式返回调用信息。
-
执行外部调用:使用模型返回的参数,通过实际的API或工具执行外部调用。
-
返回结果:将外部调用的结果传递回模型,生成最终的自然语言回复。
3.5.2 使用GPT-4进行函数调用的例子
作为一个基本示例,假设我们要求模型检查特定地点的天气。
LLM本身无法响应此请求。因为它所使用的训练数据集截止至之前的某个日期。解决这个问题的方法是将LLM与外部工具结合起来。您可以利用模型的函数调用能力来确定要调用的外部函数及其参数,然后让它返回最终回复结果。以下是一个简单的示例,展示了如何使用OpenAI API实现这一点。
假设一个用户向模型提出以下问题:
伦敦的天气如何?
要使用函数调用处理此请求,第一步是定义一个或一组天气函数。您将作为OpenAI API请求的一部分传递这些函数:
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
]
get_current_weather
函数能够返回指定位置的天气情况。当您将这个函数定义作为请求的一部分传递时,它实际上并不执行函数,只是返回一个包含调用函数所需参数的JSON对象。以下是一些如何实现这一点的代码片段。
您可以如下定义一个完整的函数:
def get_completion(messages, model="gpt-3.5-turbo-1106", temperature=0, max_tokens=300, tools=None):
response = openai.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
tools=tools
)
return response.choices[0].message
您可以像这样构造用户提问:
messages = [
{
"role": "user",
"content": "伦敦的天气如何?"
}
]
最后,您可以调用get_completion
函数,将结果传递给response
中的messages
和tools
:
response = get_completion(messages, tools=tools)
response
的构造如下所示:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='...', function=Function(arguments='{"location":"London","unit":"celsius"}', name='get_current_weather'), type='function')])
特别地,arguments
对象包含了模型提取的重要参数,这些参数将被用于完成请求。
然后您可以调用一个外部天气API来获取实际的天气信息。一旦您有了天气信息,就可以将其传回模型,随后根据原始用户问题总结出最终回应。
3.6 context-gpt4o
3.7 generating_textbooks
3.8 synthetic_rag
4 Prompt Hub
待更新