快问快答:你用什么从大型语言模型(LLM)生成内容?
答案是:提示!(Prompt)
显然,提示是任何生成型人工智能应用程序的关键元素,因此也适用于任何检索增强生成(RAG)应用程序。RAG 系统将信息检索和生成型语言模型的能力结合起来,以提高生成文本的质量和相关性。在这个背景下,提示工程涉及策略性地制定和优化输入提示,以改善相关信息的检索,从而增强生成过程。提示是生成型人工智能领域中的一个重要环节,甚至可以写出整本书来讨论。虽然有许多不同策略可以应用于提示,以改善 LLM 的使用效果,但我们将在本章中专注于那些更适用于 RAG 应用程序的策略。
在本章中,我们将重点讨论以下主题:
- 关键的提示工程概念和参数
- 专门针对 RAG 应用程序的提示设计和提示工程基础
- 针对不同 LLM(不仅仅是 OpenAI 模型)调整提示
- Code lab 13.1 – 创建自定义提示模板
- Code lab 13.2 – 提示选项
到本章结束时,你将具备坚实的 RAG 提示工程基础,并掌握优化提示的实用技巧,以便检索相关信息、生成高质量文本,并根据具体用例进行调整。我们将从介绍提示世界中的一些关键概念开始,首先讨论提示参数。
技术要求
本章的代码位于以下 GitHub 仓库:github.com/PacktPublis…
提示参数
大多数LLM都有许多共同的参数,但我们将讨论一个小子集,这些参数很可能会对你的RAG工作产生影响:温度(temperature)、top-p 和种子(seed)。
温度(Temperature)
如果你将输出视为一串标记(tokens),那么在最基本的意义上,LLM是根据你提供的数据和它已经生成的前一个标记来预测下一个单词(或标记)。LLM预测的下一个单词是由一个概率分布决定的,代表所有潜在单词及其概率。
在许多情况下,某些单词的概率会远高于其他单词,但LLM仍然有可能选择那些不太可能的单词。温度(temperature)设置就是决定模型选择概率分布中较低概率单词的可能性。换句话说,温度允许你设置模型输出的随机性程度。你可以将温度作为一个参数传递给LLM定义,这是一个可选项。如果不使用,默认值为1。你可以将温度值设置在0到2之间。较高的温度值将使输出更加随机,意味着模型会更强烈地考虑概率分布中较低概率的单词,而较低的温度值则会相反。
简单温度示例
让我们通过一个简单的下一个单词概率分布来展示温度如何工作。假设你有句子"The dog ran",你正在等待模型预测下一个单词。假设基于这个模型的训练和它正在考虑的所有数据,一个非常简单的条件概率分布如下:
P("next word" | "The dog ran") = {"down": 0.4, "to" : 0.3, "with": 0.2, "away": 0.1}
总概率加起来是1。最可能的单词是“down”,第二可能的单词是“to”。然而,这并不意味着“away”永远不会出现在推理中。模型会根据这个选择应用概率模型,有时随机选择一个不太可能的单词。在某些场景下,这对于你的RAG应用是一个优势,但在其他场景中,可能是一个劣势。如果你将温度设置为0,它将只使用最可能的单词。如果你将其设置为2,则更可能查看所有选项并随机选择较不可能的单词。换句话说,通过提高温度,你可以增加模型的随机性。
我们从一开始就使用了温度,设置为0。以下是我们添加的代码行:
llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)
这里的意图是使我们的代码实验结果更具可预测性,这样你在运行它们时,得到的结果会比较相似。你的结果可能会有所不同,但至少在温度为0时,它们有更大的相似性。
你可能并不总是想使用0的温度。考虑一些场景,例如当你希望LLM输出更具创意的内容时,此时你可以在RAG应用中利用温度来发挥其优势。
温度和top-p在某种程度上是相关的,因为它们都管理模型输出中的随机性。然而,它们之间也有差异。接下来,我们将讨论top-p,并谈论这些差异。
Top-p
类似于温度,top-p也可以帮助你在模型的输出中引入随机性。然而,温度主要控制随机性的整体程度,而top-p则帮助你在概率分布中特定的部分引入这种随机性。在之前的简单示例中,我们讨论了概率分布:
P("next word" | "The dog ran") = {"down": 0.4, "to" : 0.3, "with": 0.2, "away": 0.1}
记住,我们之前提到的总概率加起来为1.0。使用top-p时,你可以选择要考虑的概率分布的特定部分。例如,如果你将top-p设置为0.7,它将只考虑这个概率分布中的前两个单词,这些单词的概率加起来为0.7(总概率为1.0的一部分)。使用温度时,你没有这种针对性控制。top-p也是可选的。如果你不使用它,默认值为1,这意味着会考虑所有选项。
你可能会倾向于同时使用温度和top-p,但这可能会变得非常复杂和不可预测。因此,通常建议只使用其中之一,而不是同时使用。
| LLM 参数 | 结果 |
|---|---|
| Temperature | 一般随机性 |
| Top-p | 有针对性的随机性 |
| Temperature + Top-p | 不可预测的复杂性 |
表 13.1 – 显示每个LLM参数的输出类型
接下来,我们将学习如何在模型中使用top-p。它与我们之前使用的其他参数略有不同,因为你必须将其作为model_kwargs变量的一部分传递,代码如下:
llm = ChatOpenAI(model_name="gpt-4o-mini", model_kwargs={"top_p": 0.5})
model_kwargs变量是一种方便的方式,用来传递那些不是LangChain直接内置的,但在LLM底层API中存在的参数。top-p是这个ChatGPT模型的一个参数,但对于其他模型,它可能叫不同的名字,或者根本不存在。务必查阅你使用的每个API的文档,并使用正确的引用方式来访问模型的参数。
现在我们已经了解了帮助定义输出随机性的参数,接下来我们将讨论种子设置,它帮助我们控制不可控的随机性。
种子(Seed)
默认情况下,LLM的响应是非确定性的,这意味着每次请求的推理结果可能不同。然而,作为数据科学家,我们通常需要更确定、可重复的结果。这些细节看似矛盾,但实际上并非如此。OpenAI等公司最近已经做出了一些努力,提供了一些控制确定性输出的方式,让你能够使用种子(seed)参数和系统响应字段system_fingerprint。
种子是许多软件应用中常见的设置,涉及生成随机数或随机数据序列。通过使用种子,你仍然可以生成随机序列,但每次生成的随机序列是相同的。这使得你能够在API调用中获得(大多数)确定性的输出。你可以将种子参数设置为任意整数,并在希望获得确定性输出的请求中使用相同的值。此外,即使使用温度或top-p等其他随机设置,使用种子后,你仍然(大多数情况下)可以依赖于获得相同的响应。
需要注意的是,即使使用了种子,由于你使用的是连接到不断变化的服务的API,结果仍然可能不同。这些变化可能会随时间推移导致不同的结果。像ChatGPT这样的模型提供了一个system_fingerprint字段,你可以比较它们,作为指示系统变化的依据,这些变化可能会导致响应的不同。如果你使用相同的种子,而system_fingerprint值与上次调用LLM API时不同,那么即使使用相同的种子,你可能仍然会看到不同的输出,原因是OpenAI对其系统做了更改。
种子参数也是可选的,并且在LangChain的LLM参数集中并不存在。因此,像top-p参数一样,我们必须通过model_kwargs参数传递种子,代码如下:
optional_params = {
"top_p": 0.5, "seed": 42
}
llm = ChatOpenAI(model_name="gpt-4o-mini", model_kwargs=optional_params)
在这里,我们将种子参数与top-p参数一起添加到一个字典中,并传递给model_kwargs参数。
对于你可能使用的不同模型,还有许多其他参数值得你探索,但这些参数很可能对你的RAG应用产生最大影响。
接下来,我们将讨论另一个与提示相关的关键概念:shot的概念,着重于你为LLM提供的背景信息量。
尽情发挥:No-shot、Single-shot、Few-shot和Multi-shot
在讨论提示策略时,"shot" 是你经常会听到的一个术语。它们都源自一个共同的概念,其中一个"shot"指的是你给语言模型(LLM)提供的一个示例,帮助它确定如何回应你的查询。如果这个概念不清楚,我可以通过一个例子来解释。哦,等等,这不正是"shot"概念背后的意思吗?你可以提供零个示例(no-shot)、一个示例(single-shot),或者多个示例(few-shot或multi-shot)。每一个示例就是一个"shot",每一个示例就是一个"shot"。下面是一个你可以给LLM的示例(我们可以称之为single-shot,因为我只提供了一个示例):
“给我一个使用动物和动物进行某种有趣行为的笑话。 使用这个例子来指导你提供的笑话: 笑话问题:为什么鸡要过马路? 笑话答案:为了到另一边。”
在这个假设中,通过提供这个示例,你是在帮助引导LLM如何回应。
在RAG应用中,你通常会在上下文中提供示例。这并不总是如此,因为有时候上下文只是附加的(但很重要)数据。然而,如果你在上下文中提供了实际的问题和答案示例,并希望引导LLM用类似的方式回答新的用户查询,那么你就是在使用shot方法。你会发现,一些RAG应用会更紧密地遵循multi-shot模式,但这实际上取决于你应用的目标以及你所拥有的数据。
提示:提示设计、提示工程回顾
在第一章的词汇部分,我们讨论了这三个概念及其相互作用。为了复习,我们提供了以下要点:
- 提示(Prompting)是向LLM发送查询或提示的行为。
- 提示设计(Prompt design)指的是你设计将发送给LLM的提示策略。不同的提示设计策略适用于不同的场景。
- 提示工程(Prompt engineering)更多地关注提示周围的技术方面,旨在通过改善与LLM的互动来提高输出质量。例如,你可能将复杂的查询分解成两到三个不同的LLM交互,从而优化它,获得更好的结果。
我们曾承诺在第13章回顾这些话题,现在我们就来实现这个承诺!我们不仅会回顾这些话题,还会向你展示如何在代码中执行这些操作。提示是一个相对直接的概念,因此我们将重点讨论另外两个话题:设计和工程。
提示设计与工程方法的对比
在“尽情发挥”部分讨论的不同shot方法属于提示设计。然而,我们在填充提示模板时,也实施了提示工程,将我们从RAG系统的其他部分提取的查询和上下文数据填入其中。当我们将这些数据填充到提示中时,你可能还记得这被称为"hydrating"(灌水),它是一个特定的提示工程方法。提示设计和提示工程有显著的重叠,因此你经常会听到这两个术语被交替使用。在我们的案例中,我们将一起讨论它们,特别是它们如何被用来改善我们的RAG应用。
过去几年中,我看到这些概念有很多不同的描述,因此我们这个领域似乎还没有完全定义出每个概念,或者明确划分它们之间的界限。为了理解这本书中的这些概念,我描述提示设计和提示工程之间的区别是:提示工程是一个更广泛的概念,它不仅包括提示的设计,还包括优化和微调用户与语言模型之间的整个互动过程。
提示设计与工程的应用技巧
理论上,有许多提示设计技巧可以用来改善你的RAG应用。重要的是要跟踪你拥有的选项,并理解每种方法适用于哪些场景。通过实验不同的提示设计方法,你可以确定哪种方法最适合你的应用。没有“通用”的提示设计方案。我们将提供一个简短的示例列表,但我们强烈鼓励你从其他来源了解更多提示设计方法,并记下哪些方法可能帮助你的特定应用:
-
Shot设计:
- 提示设计思考过程的起点
- 精心制作初始提示,使用示例帮助引导AI模型朝着期望的输出方向
- 可以与其他设计模式结合使用,以增强生成内容的质量和相关性
-
链式思维提示(Chain-of-thought prompting) :
- 将复杂问题分解为更小、更易于管理的步骤,每个步骤都要求LLM提供中间推理
- 通过提供清晰、逐步的思维过程,增强LLM生成答案的质量,确保更好的理解和更准确的回答
-
角色提示(Personas/role prompting) :
- 创建一个虚拟角色,基于用户群体的代表性细分,定义角色的名称、职业、人口统计、个人故事、痛点和挑战
- 确保输出内容与目标受众的需求和偏好相关,赋予内容更多的个性和风格
- 一个强大的工具,有助于开发与用户需求对接的有效语言模型
-
密度链(Chain of density/summary) :
- 确保LLM适当地完成了内容总结,检查是否没有遗漏关键的内容,并且总结简明扼要
- 在LLM迭代总结时使用实体密度,确保最重要的实体被包含
-
思维树(Tree of thoughts/探索性思维) :
- 从初始提示开始,生成多个思维选项,并反复选择最佳选项,生成下一轮思维
- 允许对想法和概念进行更广泛和全面的探索,直到生成期望的输出文本
-
图结构提示(Graph prompting) :
- 一种专门设计用于处理图结构数据的提示框架
- 使LLM能够理解并生成基于图中实体之间关系的内容
-
知识增强(Knowledge augmentation) :
- 通过向提示中增加额外的相关信息,提升生成内容的质量和准确性
- 可以通过RAG等技术实现,将外部知识集成到提示中
-
展示与告诉提示(Show Me versus Tell Me prompts) :
- 提供指令的两种不同方法:展示(Show Me)包括提供示例或演示,而告诉(Tell Me)则提供明确的指令或文档
- 同时使用这两种方法提供灵活性,并根据任务的特定上下文和复杂性提高生成AI的响应准确性
这个列表只是皮毛,实际上有许多其他方法可以用来提升提示工程和生成AI性能。随着提示工程领域的发展,新的创新技巧可能会涌现,进一步增强生成AI模型的能力。
接下来,我们将讨论帮助RAG应用的提示设计基础。
提示设计基础
在为RAG应用程序设计提示时,必须牢记以下基础原则:
-
简洁和具体:清晰定义您希望AI模型执行的任务,并提供完成任务所需的必要信息。例如,表达“请分析给定的上下文并回答问题,考虑所有相关信息和细节”相比“基于提供的上下文,回答以下问题:[具体问题]”要更不简洁和具体。
-
一次性只提一个任务:将复杂任务分解成更小、更易管理的子任务,为每个子任务创建独立的提示,以确保更好的结果。例如,如果您说“总结上下文的要点,识别提到的关键实体,然后回答给定问题”,这涉及到同时要求多个任务。您可能会得到更好的结果,如果您将其拆分成多个提示,如下所示:
- 总结以下上下文的要点:[上下文]
- 识别以下总结中提到的关键实体:[上一提示的总结]
- 使用上下文和识别出的实体,回答以下问题:[具体问题]
-
将生成任务转化为分类任务:尽可能将开放式生成任务重新表述为分类任务,限定选项的数量,因为这样可以使AI模型的回答更加精确和集中。例如,不要说“基于上下文,表达了什么情感对这个话题?”相反,如果您说“基于上下文,将表达的情感分类为正面、负面或中性”,可能会得到更好的结果。
-
通过示例提高回答质量:我们将继续使用之前提到的“单一示例”或“多个示例”的概念。这个基本概念着重于在提示中提供相关示例,以引导AI模型朝着期望的输出格式和风格发展。例如,不要说“根据提供的上下文回答以下问题”,而是要说“使用下面的示例作为指导,基于提供的上下文回答以下问题:
- 示例1:[问题] [上下文] [答案]
- 示例2:[问题] [上下文] [答案]
- 当前问题:[问题] 上下文:[上下文]”。
-
从简单开始,逐步迭代:从简单的提示开始,随着需要,逐步添加更多元素和上下文,以获得更好的结果。通过这种迭代方法,您可以微调提示并优化性能。例如,“总结文章的要点,识别关键实体,然后回答以下问题:[问题]。提供示例并使用以下格式回答:[格式] 文章:[长篇文章文本]”的提示可能不如以下逐步迭代的提示效果好:
- 第1步:总结以下文章的要点:[文章文本]
- 第2步:总结要点并识别文章中的关键实体:[文章文本]
- 第3步:根据总结和关键实体回答以下问题:[问题] 文章:[文章文本]
-
将指令放在提示的开头:清晰地在提示的开始部分陈述指令,并使用清晰的分隔符,如“###”,来区分指令和上下文部分。这有助于AI模型更好地理解和遵循给定的指令。例如,提示“[上下文] 请使用上述上下文回答以下问题:[问题] 以简洁的方式提供答案”相比于以下提示效果较差:
- 指令:使用下面提供的上下文回答问题,并简洁地给出答案。
- 上下文:[上下文] 问题:[问题]
虽然提示设计的基础提供了创建有效提示的坚实基础,但请记住,不同的语言模型可能需要特定的适应,以实现最佳效果。接下来我们将讨论这个话题。
为不同的LLM调整提示
随着人工智能领域的不断发展,人们不再仅仅依赖OpenAI来满足语言建模需求。其他公司,如Anthropic的Claude模型,由于能够处理长上下文窗口,也逐渐受到了广泛关注。谷歌也在发布(并将继续发布)强大的模型。此外,开源模型社区正在迎头赶上,像Llama这样的模型已被证明是可行的替代方案。
然而,值得注意的是,提示并不能无缝地从一个LLM转移到另一个LLM。每个LLM可能有其特定的技巧和技术,这些技巧和技术对其架构最有效。例如,Claude-3在提示时偏好XML编码,而Llama3在标注提示的不同部分时使用特定的语法,如SYS和INST。以下是一个为Llama模型设计的提示示例,使用了SYS和INST标签:
<SYS> 你是一个AI助手,旨在提供有用和信息丰富的回答。 </SYS>
<INST> 分析用户下面的问题,并利用你的知识库提供一个清晰、简洁的答案。如果问题不清楚,请请求进一步的澄清。
用户的问题: "与化石燃料相比,使用可再生能源的主要优势是什么?" </INST>
在这个示例中,SYS标签简要地设定了AI作为助手的角色,旨在提供有帮助的回答。INST标签提供了回答用户问题的具体指示,这些指示被包含在INST块内。SYS是系统消息(system message)的简写,而INST则用于表示指令。
在为RAG应用程序设计提示时,考虑与所选LLM相关的具体需求和最佳实践非常重要,以确保最佳的性能和结果。所有知名的模型都提供了提示文档,能够解释在使用它们时需要做什么。
现在,让我们将本章第一部分所讨论的所有概念付诸实践,通过代码实验来实现!
代码实验 13.1 – 自定义提示模板
提示模板(PromptTemplate)是一个类,用于在LangChain中管理和使用提示。与大多数模板一样,它包含提供的文本,以及表示输入的变量。使用PromptTemplate包来管理提示可以确保其在LangChain生态系统中正常工作。本代码基于我们在第8章8.3代码实验中完成的代码,可以在GitHub仓库的CHAPTER13目录中找到,文件名为CHAPTER13-1_PROMPT_TEMPLATES.ipynb。
作为复习,我们之前使用过的模板是:
prompt = hub.pull("jclemens24/rag-prompt")
打印该提示时,结果如下所示:
You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know.
Question: {question}
Context: {context}
Answer:
这存储在PromptTemplate对象中,可以打印出来。如果打印,您会看到类似以下内容:
ChatPromptTemplate(input_variables=['context', 'question'], metadata={'lc_hub_owner': 'jclemens24', 'lc_hub_repo': 'rag-prompt', 'lc_hub_commit_hash': '1a1f3ccb9a5a92363310e3b130843dfb2540239366ebe712ddd94982acc06734'}, messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['context', 'question'], template="You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know.\nQuestion: {question} \nContext: {context} \nAnswer:"))])
如我们所见,完整的PromptTemplate对象不仅仅包含文本和变量。首先,我们可以说这是PromptTemplate对象的一种特定版本,称为ChatPromptTemplate对象,这意味着它在聊天场景中最为有用。输入变量是context和question,它们会在模板字符串中出现。在接下来的部分,我们将设计一个自定义模板,但这个特定的模板来自LangChain hub。您可以看到这里的元数据,指示了hub的所有者、仓库和提交哈希。
让我们通过用我们自己的自定义模板替换这个提示模板开始代码实验。
我们已经导入了LangChain包:
from langchain_core.prompts import PromptTemplate
此时不需要添加更多的导入!我们将替换以下代码:
prompt = hub.pull("jclemens24/rag-prompt")
替换成以下代码:
prompt = PromptTemplate.from_template(
"""
You are an environment expert assisting others in
understanding what large companies are doing to
improve the environment. Use the following pieces
of retrieved context with information about what
a particular company is doing to improve the
environment to answer the question.
If you don't know the answer, just say that you don't know.
Question: {question}
Context: {context}
Answer:"""
)
如您所见,我们已将此提示模板自定义为专门关注我们的数据(谷歌环境报告)所涉及的主题。我们使用了角色提示设计模式(personas prompt design pattern)来确立LLM要扮演的角色,旨在使其更符合我们的特定主题。
提示模板接收一个字典作为输入,其中每个键表示模板中需要填充的变量。PromptTemplate对象的输出是一个PromptValue变量,它可以直接传递给LLM或ChatModel实例,或作为LCEL链中的一步。
使用以下代码打印提示对象:
print(prompt)
输出如下所示:
input_variables=['context', 'question'] template="\n You are an environment expert assisting others in \n understanding what large companies are doing to \n improve the environment. Use the following pieces \n of retrieved context with information about what \n a particular company is doing to improve the \n environment to answer the question. \n \n If you don't know the answer, just say that you don't know.\n \n Question: {question} \n Context: {context} \n \n Answer:"
我们看到,它已捕捉到输入变量,而无需我们显式声明它们:
input_variables=['context', 'question']
使用以下代码,我们可以仅打印出模板文本:
print(prompt.template)
这将提供一个更具可读性的版本,显示我们刚才展示的最后输出,但只显示提示文本本身。
您会注意到,在此之后,我们已经有了一个定制的提示模板,专注于确定我们的相关性评分:
relevance_prompt_template = PromptTemplate.from_template(
"""
Given the following question and retrieved context, determine if the context is relevant to the question.
Provide a score from 1 to 5, where 1 is not at all relevant and 5 is highly relevant.
Return ONLY the numeric score, without any additional text or explanation.
Question: {question}
Retrieved Context: {retrieved_context}
Relevance Score:"""
)
如果您运行代码的其余部分,您将看到它对RAG应用程序最终结果的影响。这个提示模板被视为字符串提示模板(String prompt template),意味着它是使用一个普通字符串创建的,其中包含提示文本以及动态内容的占位符(例如{question}和{retrieved_context})。您还可以使用ChatPromptTemplate对象来格式化消息列表。它本身由一系列模板组成。
提示模板在最大化RAG系统性能中扮演着关键支持角色。在本章的剩余代码实验中,我们将使用提示模板作为主要元素。然而,我们现在将重点转向编写提示时需要牢记的一系列概念。我们的下一个代码实验将涵盖所有这些概念,从提示格式化开始。
代码实验 13.2 – 提示选项
此代码可以在GitHub仓库的CHAPTER13目录中的CHAPTER13-2_PROMPT_OPTIONS.ipynb文件中找到。
通常,在设计提示时,您需要牢记一些常见的概念。这些概念包括迭代、总结、转换和扩展。每个概念都有不同的使用场景,且常常可以以各种方式组合。在改进RAG应用程序时,掌握如何设计提示的基础知识会非常有用。我们将通过一个真实世界的场景来演示不同的提示设计方法,其中你将帮助公司营销部门编写提示。我们从迭代开始。
迭代
这个概念主要关注通过迭代提示来获得更好的结果。很少有第一次编写的提示会是最终的最佳提示。本节将介绍一些基本技巧和概念,帮助您快速迭代提示,使其更加适合您的RAG应用程序。
迭代语气
您的老板刚刚打电话过来,告诉您营销团队说他们希望使用RAG应用程序的输出作为营销材料,但它必须以一种更像营销事实表的格式提供。没问题,我们可以直接在提示设计中进行调整!
我们将在第一个提示后添加第二个提示:
prompt2 = PromptTemplate.from_template(
"""Your task is to help a marketing team create a
description for the website about the environmental
initiatives our clients are promoting.
Write a marketing description based on the information
provided in the context delimited by triple backticks.
If you don't know the answer, just say that you don't know.
Question: {question}
Context: ```{context}```
Answer:"""
)
接下来,您需要将rag_chain_from_docs链中的提示更改为prompt2。请查看RunnablePassthrough()行之后:
rag_chain_from_docs = (
…
"answer": (
RunnablePassthrough()
| prompt2 # <- 这里进行更新
| llm
| str_output_parser
)
…
)
然后,从prompt2开始重新运行代码,您将得到如下输出:
Google is at the forefront of environmental sustainability, leveraging its technological prowess to drive impactful initiatives across various domains. Here are some of the key environmental initiatives that Google is promoting:
Empowering Individuals: Google aims to help individuals make more sustainable choices through its products. In 2022, Google reached its goal of assisting 1 billion people in making eco-friendly decisions. This was achieved through features like eco-friendly routing in Google Maps, energy-efficient settings in Google Nest thermostats, and carbon emissions information in Google Flights. By 2030, Google aspires to help reduce 1 gigaton of carbon equivalent emissions annually.
…[TRUNCATED FOR BREVITY]…
By organizing information about the planet and making it actionable through technology, Google is helping to create a more sustainable future. The company's efforts span from individual empowerment to global partnerships, all aimed at reducing environmental impact and fostering a healthier planet.
如果您阅读完整的输出,您会注意到这看起来确实更具营销导向。这可能正是营销团队所需要的。然而,您刚才记得老板还提到,这段内容将放在网站上的一个小方框里,最多只能容纳50个单词!
缩短长度
对于prompt3,我们只需要添加这段小片段:使用最多50个单词。如下所示:
prompt3 = PromptTemplate.from_template(
"""Your task is to help a marketing team create a
description for the website about the environmental
initiatives our clients are promoting.
Write a marketing description based on the information
provided in the context delimited by triple backticks.
If you don't know the answer, just say that you don't know.
Use at most 50 words.
Question: {question}
Context: ```{context}```
Answer:"""
)
更新链中的提示为prompt3。然后运行其余代码,您将得到如下输出:
Google's environmental initiatives include promoting electric vehicles, sustainable agriculture, net-zero carbon operations, water stewardship, and a circular economy. They aim to help individuals and partners reduce carbon emissions, optimize resource use, and support climate action through technology and data-driven solutions.
营销团队非常喜欢您的工作!一切顺利!做得好!时间流逝……
一个月后,决定不再关注客户的所有环境努力,而是专注于与技术相关的努力。
改变焦点
我们希望LLM聚焦于更具体的技术方面。这是一本宣传册,因此可以再长一点。我们将设计prompt4来引导LLM改变焦点,并去掉长度限制:
prompt4 = PromptTemplate.from_template(
"""Your task is to help a marketing team create a
description for the website about the environmental
initiatives our clients are promoting.
Write a marketing description based on the information
provided in the context delimited by triple backticks.
The description is intended for a technology audience,
so this should focus on only the aspects of the
company's efforts that relate to using technology. If
you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
同样,记得在链中更新提示为prompt4,然后运行其余代码以获得如下输出:
Google is at the forefront of leveraging technology to drive environmental sustainability. Here are some of the key initiatives that highlight their commitment to using technology for a greener future:
Eco-Friendly Product Features:
Google Maps: Introduced eco-friendly routing, which has helped prevent over 1.2 million metric tons of carbon emissions since its launch.
Google Nest: Energy efficiency features in Google Nest thermostats help users reduce their energy consumption.
Google Flights: Provides carbon emissions information to help travelers make more sustainable choices.
…TRUNCATED FOR BREVITY…
Sustainability-Focused Accelerators:
Google for Startups Accelerator: Supports early-stage innovations aimed at tackling sustainability challenges, fostering the growth of technologies that can positively impact the planet.
Google's comprehensive approach to environmental sustainability leverages their technological expertise to create significant positive impacts. By integrating sustainability features into their products, optimizing their operations, and collaborating with partners, Google is driving forward a more sustainable future.
我们在书中不得不将其缩短,但如果你查看代码中的结果,效果非常好。显然,技术方面的环境努力得到了更高的关注。你的营销团队对此印象深刻!
这是一个有趣的示例,但这并不远离构建此类系统时发生的情况。在现实世界中,您可能会进行更多的迭代,但采取迭代的方法来设计提示,将帮助您更好地优化RAG应用程序,就像RAG系统的其他部分一样。
接下来,让我们讨论如何将大量数据压缩成更少的信息,这也叫做摘要。
摘要
摘要是RAG的常见用途。将公司内部的大量数据消化成较小、简洁的信息,可以成为提高生产力的快速且简便的方式。这对于依赖信息或需要跟上快速变化信息的工作尤为有用。我们已经看到如何设计一个带有字数限制的提示,那个是在prompt3中。 然而,在这个例子中,我们将更加专注于让LLM进行内容总结,而不是尝试成为专家或编写营销文案。代码如下:
prompt5 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
Summarize the retrieved context below, delimited by
triple backticks, in at most 30 words.
If you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
将链中的提示更新为prompt5,然后再次运行其余代码,您将得到如下输出:
Google's environmental initiatives include achieving net-zero carbon, promoting water stewardship, supporting a circular economy, and leveraging technology to help partners reduce emissions.
好,这个摘要简洁且很有总结性。只是陈述事实而已!
下一个示例是另一个情况,我们可以聚焦LLM,但还需要进行摘要。
聚焦的摘要
对于prompt6,我们将保留前一个提示中的大部分内容。然而,我们将尝试将LLM聚焦于产品的环保特性:
prompt6 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
Summarize the retrieved context below, delimited by
triple backticks, in at most 30 words, and focusing
on any aspects that mention the eco-friendliness of
their products.
If you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
将链中的提示更新为prompt6,然后运行代码以获得如下输出:
Google's environmental initiatives include eco-friendly routing in Google Maps, energy-efficient Google Nest thermostats, and carbon emissions information in Google Flights.
这个摘要简洁明了,并且如果你对比更长的描述,它确实专注于PDF中展示的那些产品。这是一个相当不错的结果,但通常当你要求进行总结时,即使聚焦于特定方面,LLM仍可能包含你不想要的信息。为了解决这个问题,我们将使用extract方法。
提取而不是总结
如果你遇到总结中包含太多不必要信息的常见问题,尝试使用“提取”而不是“总结”。这看似是一个小小的细节,但它对LLM的效果可能有很大的影响。提取一词给人的印象是你在从中提取特定的信息,而不是试图捕捉整个文本中的所有数据。LLM不会忽视这一细微的差别,这可以成为一种有效的技术,帮助你避免总结中有时出现的挑战。我们将基于这个改变设计prompt7:
prompt7 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
If you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
将链中的提示更新为prompt7,然后运行代码以获得以下输出:
Google's environmental initiatives include eco-friendly routing in Google Maps, energy efficiency features in Google Nest thermostats, and carbon emissions information in Google Flights to help users make sustainable choices.
这与prompt6的回应略有不同,但我们已经得到了一个很好的聚焦结果。当你的摘要回应包含不必要的数据时,尝试这种技术来帮助改善你的结果。
然而,迭代和总结并不是唯一能够提升你提示设计的概念。接下来,我们将讨论如何利用RAG应用从现有数据中推断信息。
推断
推断的根本目的是让模型查看你的数据,并提供某种额外的分析。这通常涉及提取标签、名称和主题,甚至确定文本的情感。对于RAG应用,这些能力具有深远的意义,因为它们使得一些曾被认为只有人类阅读者才能完成的任务变得可自动化。让我们从一个简单的布尔情感分析开始,其中我们考虑文本是正面还是负面:
prompt8 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
After this summary, determine what the sentiment
of context is, providing your answer as a single word,
either "positive" or "negative". If you don't know the
answer, just say that you don't know.
Question: {question}
Context: ```{context}```
Answer:"""
)
在这段代码中,我们基于前一个提示中的摘要,添加了对LLM消化数据情感的分析。在这种情况下,它将情感定为“正面”:
Google is enhancing eco-friendliness through features like eco-friendly routing in Maps, energy-efficient Nest thermostats, and carbon emissions data in Flights, aiming to reduce emissions significantly.
Sentiment: positive
另一个与此类似的常见应用是从上下文中提取特定数据。
提取关键信息
作为参考,您的任务是识别客户文档中提到的与其环境努力相关的任何具体产品。在这个案例中,Google(客户)有许多产品,但他们在这份文档中只提到了其中一部分。如何快速将这些产品提取出来并识别它们呢?让我们通过以下提示来尝试:
prompt9 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
After this summary, determine any specific products
that are identified in the context below, delimited
by triple backticks. Indicate that this is a list
of related products with the words 'Related products: '
and then list those product names after those words.
If you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
在这段代码中,我们继续基于之前的提示进行扩展,但我们不再要求情感分析,而是要求列出与我们检索到的文本相关的产品。我们使用的GPT-4o-mini模型成功地执行了这些指令,列出了文本中具体提到的每个产品:
Google is enhancing eco-friendliness through products like eco-friendly routing in Google Maps, energy efficiency features in Google Nest thermostats, and carbon emissions information in Google Flights.
Related products: Google Maps, Google Nest thermostats, Google Flights
再次看到,LLM能够很好地处理我们要求的所有内容。不过,有时我们只是想对主题有一个整体的了解。接下来,我们将讨论如何使用LLM进行推断。
推断主题
你可以将这看作是总结的极端案例。在这个例子中,我们将成千上万的词汇总结成一个简短的主题集合。这能做到吗?让我们试试看!我们将从以下代码开始:
prompt10 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
After this summary, determine eight topics that are
being discussed in the context below delimited
by triple backticks.
Make each item one or two words long.
Indicate that this is a list of related topics
with the words 'Related topics: '
and then list those topics after those words.
If you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
在这段代码中,我们使用类似于之前提示的方法,但我们要求列出至少八个与检索到的文本相关的主题。再次地,我们使用的GPT-4o mini模型成功地执行了这些指令,列出了文本中特别涉及的八个高度相关的主题:
Google is enhancing eco-friendliness through products like eco-friendly routing in Google Maps, energy-efficient Google Nest thermostats, and carbon emissions information in Google Flights.
Related topics:
1. Electric vehicles
2. Net-zero carbon
3. Water stewardship
4. Circular economy
5. Supplier engagement
6. Climate resilience
7. Renewable energy
8. AI for sustainability
我们已经涵盖了迭代、总结和推断,这些概念都能显著提升你的提示设计效果。接下来,我们将讨论另一个概念:转化。
转化
转化是指将当前的数据转变为不同的状态或格式。一个非常常见的例子是语言翻译,但也有很多其他的转化方式,包括将数据转换为特定的编码格式,例如JSON或HTML。你还可以应用其他转化,例如检查拼写或语法错误。
我们将从语言翻译开始。
语言转化(翻译)
市场部又联系了!到目前为止,你做得非常棒,但现在事情越来越大,我们要进入国际市场!我们选择的第一个国际市场包括讲西班牙语和法语的国家。此外,我们公司的一位新投资者还是个海盗迷,所以没错,我们也会涵盖海盗方言!既然我们在谈论转化,我们称之为语言转化,但在这个背景下,“翻译”这个词也非常常见。让我们开始吧:
prompt11 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
Translate the summary into three additional languages,
Spanish, French, and English Pirate:
labeling each language with a format like this:
English: [summary]
Spanish: [summary]
French: [summary]
English pirate: [summary]
If you don't know the answer, just say that you don't
know.
Question: {question}
Context: ```{context}```
Answer:"""
)
在这段代码中,我们基于之前的提示进行扩展,但要求LLM生成四个不同版本的简短总结:英语、西班牙语、法语和英语海盗语。显然,我们应该更多地使用海盗语,因为它最具娱乐性:
English: Google enhances eco-friendliness through features like eco-friendly routing in Maps, energy-efficient Nest thermostats, and carbon emissions info in Flights, helping reduce carbon emissions significantly.
Spanish: Google mejora la eco-amigabilidad con funciones como rutas ecológicas en Maps, termostatos Nest eficientes en energía e información de emisiones de carbono en Flights, ayudando a reducir significativamente las emisiones de carbono.
French: Google améliore l'éco-responsabilité avec des fonctionnalités telles que les itinéraires écologiques dans Maps, les thermostats Nest économes en énergie et les informations sur les émissions de carbone dans Flights, aidant à réduire significativement les émissions de carbone.
English pirate: Google be makin' things greener with eco-routes in Maps, energy-savin' Nest thermostats, and carbon info in Flights, helpin' to cut down on carbon emissions mightily.
语言翻译是RAG的一个常见应用,但还有其他可能有用的转化方式。接下来我们看一个给总结添加不同语气的例子。
语气转化
到目前为止,我们的总结和营销文案写得很成功,但现在我们需要拓展到其他渠道,如电子邮件,并为我们的总结赋予更友好、轻松的语气,以匹配这一格式。为此,我们将应用语气转化:
prompt12 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
After providing the summary, translate the summary
into an email format with a more friendly and
casual tone. If you don't know the answer, just say
that you don't know.
Question: {question}
Context: ```{context}```
Answer:"""
)
在这里,我们继续使用原来的总结,但要求LLM使用相同的信息编写一封电子邮件,并赋予它更友好、轻松的语气:
Google is enhancing eco-friendliness through features like eco-friendly routing in Google Maps, energy-efficient Google Nest thermostats, and carbon emissions data in Google Flights.
Email Format:
Subject: Exciting Eco-Friendly Features from Google!
Hi [Recipient's Name],
I hope you're doing well! I wanted to share some cool updates from Google about their efforts to help the environment. They've introduced some awesome features like eco-friendly routing in Google Maps, energy-efficient Google Nest thermostats, and even carbon emissions data in Google Flights. It's great to see such big steps towards a greener future!
Best, [Your Name]
通过这些例子,我们可以看到LLM在提升RAG应用中的作用。还有一些不太适用的转化(但在其他场景中依然非常有价值),例如将数据转化为特定的编码格式,或者在不同的编码格式之间进行转换。拼写和语法检查也是常见的转化应用。
我们已经覆盖了迭代、总结、推断和转化。接下来,我们将讨论最后一个概念:扩展。
扩展
在许多方面,扩展的目标可以看作是之前我们讨论的概念(如总结)的反向。总结的目标是将大量数据整合成较小的数据量,同时尽量保留数据的含义。扩展则正好相反,它的目标是将少量数据扩展为更大的信息集合。让我们通过一个可以实施扩展的场景来理解:扩展一个简短的总结。
扩展简短文本
我们的努力持续增长!我们最新的任务是将我们讨论的环保概念推广给客户的投资者。在这个新的提示中,我们将以一个简短的总结为基础,假设这是我们唯一拥有的内容。然后我们会要求LLM基于这个简短的总结进行扩展,重点是如何让它更具吸引力,以吸引投资者。让我们看看它能做出什么:
prompt13 = PromptTemplate.from_template(
"""Your task is to generate a short summary of what a
company is doing to improve the environment.
From the retrieved context below, delimited by
triple backticks, extract the information focusing
on any aspects that mention the eco-friendliness of
their products. Limit to 30 words.
After providing the summary, provide a much longer
description of what the company is doing to improve
the environment, using only the summary you have
generated as the basis for this description. If you
don't know the answer, just say that you don't know.
Question: {question}
Context: ```{context}```
Answer:"""
)
在现实场景中,当你希望LLM扩展数据时,通常不会有原始上下文。因此,通过告诉LLM将扩展的来源限制为仅使用提供的总结,我们更准确地模拟了这一场景。我们的LLM没有让我们失望,它提供了一个扩展的环保努力描述,并根据投资者的需求进行了调整:
总结:Google 提供了 Google Maps 中的环保路线、能效高的 Google Nest 温控器以及 Google Flights 中的碳排放信息,帮助用户做出可持续的选择。
扩展描述:Google 正积极提升其产品的环保性,整合了一些促进可持续性的功能。例如,Google Maps 现在提供环保路线选择,Google Nest 温控器旨在提高能效,Google Flights 提供碳排放信息。这些举措不仅帮助用户做出更加环保的决策,还展示了 Google 在减少碳足迹方面的承诺。对于投资者来说,这种可持续性战略可以成为一个重要的价值主张,因为它符合消费者对环保产品日益增长的需求,并可能带来长期的成本节约和监管优势。此外,这也使 Google 成为环保责任的领导者,可能提升其品牌声誉和市场份额。
这只是一个扩展概念如何应用的例子。考虑一下在你的RAG应用中何时、如何使用数据扩展。
本章总结了提高提示设计的所有关键概念:迭代、总结、推理、转化和扩展。这些概念构成了许多更深入、更复杂概念的基础,这些概念可以使你的RAG应用更加有效。可以把它视为你在这一领域的知识起点,随着新的技术和方法的出现,继续跟踪和学习它们。
总结
在本章中,我们探讨了提示工程在提高RAG系统性能和效果中的关键作用。通过战略性地设计和优化输入提示,我们可以改善相关信息的检索,从而提升生成文本的质量。我们讨论了各种提示设计技术,如少样本设计、思维链提示、角色设定和知识增强,这些技术可以应用于优化RAG应用。
在整个章节中,我们讨论了提示设计的基本概念,包括简洁性、具体性和定义明确性的重要性,以及逐步迭代和使用清晰分隔符的必要性。我们还强调了不同LLM需要不同提示的事实,并指出根据所使用的具体模型调整提示的重要性。
通过一系列代码实验,我们学习了如何使用LangChain中的PromptTemplate类创建自定义提示模板,以及如何应用各种提示概念来提升我们的RAG工作。这些概念包括:迭代以精炼提示、总结以压缩信息、推理以提取附加见解、将数据转化为不同格式或语气,以及扩展简短总结以生成更全面的描述。我们还探索了使用提示参数,如温度、top-p和种子,以控制LLM输出的随机性和确定性。
通过利用本章涵盖的技术和概念,我们可以显著提升RAG应用的性能,使其在检索相关信息、生成高质量文本以及适应特定用例方面更加有效。随着提示工程领域的不断发展,保持对最新技术和最佳实践的了解,将对最大化RAG系统在各个领域的潜力至关重要。
在我们下一章也是最后一章中,我们将讨论一些更高级的技术,您可以用来对RAG应用进行潜在的重大改进!