LangChain学习笔记之提示工程 | 豆包MarsCode AI刷题

108 阅读8分钟

提示工程

提示工程的两大原则(吴恩达提出):

  1. 写出清晰而具体的指示
  2. 给模型思考的时间

提示工程6大策略(Open AI官方):

  1. 写清晰的指示
  2. 给模型提供参考(也就是示例)
  3. 将复杂任务拆分成子任务
  4. 给GPT时间思考
  5. 使用外部工具
  6. 反复迭代问题

提示框架

  • 指令(Instruction):告诉模型这个任务大概要做什么、怎么做。比如如何使用提供的外部信息、如何查询以及如何构造输出。
  • 上下文(Content):充当模型的额外知识来源。这些信息可以手动插入到提示中,通过矢量数据库检索的来,或通过其他方式(如调用API、计算器等工具)拉入。
  • 提示输入(Prompt Input):通常就是具体的问题或者需要大模型做的具体事情,这部分可以与指令合二为一,但拆分出来更加结构化、便于复用。这通常是作为变量,再调用模型之前传递给提示模板,以形成具体的提示。
  • 输出指示器(Output Indicator):标记输入结束,也标志着要生成的文本的开始。LangChain中的代理在构建提示模板时,经常性的会用一个“Thought:”(思考)作为引导词,指示模型开始输出自己的推理(Reasoning)。

这个提示框架在上诉中已经体现过了。指令就是一个模板,模板中有很多的变量需要填充。上下文比如向量数据库中的查询结果就是一个很好的例子。提示输入做为变量填充到模板中,输出指示器就是一个标志。


LangChain 提示模板的类型

LangChain中提供String (StringPromptTemplate)和Chat(BaseChatPromptTemplate)两种基本类型的模板,并基于它们构建了不同类型的提示模板。

序号提示模板含义
1PromptTemplateString提示模板
2ChatPromptTemplateChat提示模板,用于组合各种角色的消息模板,传入聊天模型
3FewShotPrompt少样本提示模板,通过示例来”教“模型如何回答
4PipelinePrompt用于把几个提示组合在一起使用
5自定义模板LangChain允许基于其他模板类来定制自定义的提示模板

消息模板:具体的消息模板包括 ChatMessagePromptTemplate、HumanMessagePromptTemplate、AIMessagePromptTemplate 和 SystemMessagePromptTemplate。

导入方式如下:

 # String提示模板
 from langchain.prompts import PromptTemplate
 # Chat提示模板
 from langchain.prompts import ChatPromptTemplate
 from langchain.prompts import (
     # 消息模板
     ChatMessagePromptTemplate,
     HumanMessagePromptTemplate,
     AIMessagePromptTemplate,
     SystemMessagePromptTemplate,
 )
 # FewShotPrompt
 from langchain.prompts import FewShotPromptTemplate
 # PipelinePrompt
 from langchain.prompts import PromptTemplate

接下来会着重讲解FewShotTemplate,前两种简单介绍,PipelinePrompt与自定义模板参考LangChain文档自学。


PromptTemplate

使用模板就是将指令转化为PromptTemplate对象,然后可以向该对象中传入提示输入(format方法)、上下文和输出指示器从而形成一个完整的请求问题。这里有两种方法构造PromptTemplate对象。

  1. from_template方法:

    给定字符串形式的template,然后使用from_template方法构造PromptTemplate对象。

    例子:

     from langchain import PromptTemplate
     ​
     template = """\
     你是业务咨询顾问。
     你给一个销售{product}的电商公司,起一个好的名字?
     """
     prompt = PromptTemplate.from_template(template)
     ​
     print(prompt.format(product="鲜花"))
    
  2. PromptTemplate构造函数:

    可以直接使用PromptTemplate的构造函数得到PromptTemplate对象。参数需要两个: input_variables和template,前者是一个列表,存template中的变量;后者是字符串形式的template。

    例子:

     prompt = PromptTemplate(
         input_variables=["product", "market"], 
         template="你是业务咨询顾问。对于一个面向{market}市场的,专注于销售{product}的公司,你会推荐哪个名字?"
     )
     print(prompt.format(product="鲜花", market="高端"))
    

ChatPromptTemplate

这种模板的特点就是它们有对应的角色。ChatPromptTemplate将消息模板组合形成一个message,消息模板上面已经说过,这里用 SystemMessagePromptTemplate和 HumanMessagePromptTemplate作为例子。

  • SystemMessagePromptTemplate构造角色为system的对象,同理HumanMessagePromptTemplate也构造一个对象。然后通过ChatPromptTemplate的from_messages方法组合这两个对象(传入列表)从而行成一个模板。
  • 然后通过ChatPromptTemplate的format_prompt传入变量得到一个ChatPromptValue对象,最后通过ChatPromptValue的to_message方法得到一个以消息列表形式的提示。

样本概念

样本就是示例,通过提供给大模型样本,大模型会更好地回答问题。

Few-Shot(少样本)、One-Shot(单样本)和与之对应的 Zero-Shot(零样本)的概念都起源于机器学习。One-Shot可以看作Few-Shot的一个情况。Zero-Shot也称为“顿悟”,在比较聪明的模型中是能够做到的。

在提示工程中:

  • 在Few-Shot学习设置中,模型会被给予几个示例,以帮助模型理解任务,并生成正确的响应。
  • 在Zero-Shot学习设置中,模型只根据任务的描述生成响应,不需要任何示例。

FewShotTemplate

如上所述,FewShotTemplate就是少样本提示模板。包含创建示例样本、创建提示模板、创建FewShotTemplate对象和调用模型四个步骤。如果示例过多,这时还需要用示例选择器选择最合适的样例。

1. 创建示例样本

示例样本是一个列表,其中的每个示例都是一个字典,其中键是输入变量,值是这些输入变量的值。示例样本并不是完整的示例,只是输入变量和其示例值。

2. 创建提示模板

有了样本示例,我们还需要一个提示模板从而得到完整的示例。提示模板是PromptTemplate对象。

3. 创建 FewShotPromptTemplate 对象

先在有了示例样本以及对应的提示模板,我们就可以再创建FewShotPromptTemplate对象。FewShotPromptTemplate是一个更复杂的提示模板,它包含了多个示例和一个提示。这种模板可以使用多个示例来指导模型生成对应的输出。创建FewShotPromptTemplate对象是用其构造方法,传入参数有:examples(示例样本)、example_prompt(提示模板)、suffix(最后提问的问题模板,一般就是和提示模板差不多,少一个或多个参数而已)、input_variables(变量列表)。

少样本提示模板就是给出一些样本示例,再给出一个提示,让模型推理出与样本类似的结果。

4. 调用大模型创建新文案

通过FewShotTemplate对象的format方法得到具体的提问,传给大模型。

 # 4. 把提示传递给大模型
 import os
 os.environ["OPENAI_API_KEY"] = '你的Open AI Key'
 from langchain.llms import OpenAI
 model = OpenAI(model_name='gpt-3.5-turbo-instruct')
 result = model(prompt.format(flower_type="野玫瑰", occasion="爱情"))
 print(result)

示例选择器

如果给的示例很多,那么一次性全发给模型是不现实并且低效的,而且还会消耗大量的Token。这时就可以使用示例选择器来选择最合适的样本(通过向量相似度,因此需要向量数据库)。

通过SemanticSimilarityExampleSelector的from_examples方法构造一个示例选择器,其传入的参数为示例样本列表、嵌入模型、向量数据库、指定选择最相似的示例数量k。

然后创建 FewShotPromptTemplate对象时,传入example_selector、example_prompt、suffix、input_variables等参数。


思维链与思维树

思维链即Chain of Thought,CoT。CoT的概念来源于学术界,它提出,如果生成一系列的中间推理步骤,就能够显著提高大型语言模型进行复杂推理的能力。LangChain的核心组件Agent的本质就是进行好的提示工程,并大量地使用预置的FewShot和CoT模板。

Few-Shot CoT就是简单的在提示中提供了一些链式思考示例,在Zero-Shot CoT中,你只要简单地告诉模型“让我们一步步的思考(Let's think step by step)”,模型就能够给出更好的答案!简单来说,Few-Shot CoT,指的就是在带有示例的提示过程中,加入思考的步骤,从而引导模型给出更好的结果。而Zero-Shot CoT,就是直接告诉模型要一步一步地思考,慢慢地推理。

CoT这种思想,为大模型带来了更好的答案,然而,对于需要探索或预判战略的复杂任务来说,传统或简单的提示技巧是不够的。基于CoT的思想,进一步提出了思维树(Tree of Thoughts,ToT)框架,该框架基于思维链提示进行了总结,引导语言模型探索把思维作为中间步骤来解决通用问题。

ToT框架的核心思想是:让模型生成和评估其思维的能力,并将其与搜索算法(如广度优先搜索和深度优先搜索)结合起来,进行系统性地探索和验证。通过引入强化学习、集束搜索等技术,可以进一步提高搜索策略的性能,并让模型在解决新问题或面临未知情况时有更好的表现。

ToT简单来说就是让模型解决一个问题的时候,把这个问题拆解为多个思维步骤,而每个思维步骤中又有多个方案,这样就像是形成了一个“树”,然后在多条思维路径中搜寻最优的解决方案。

image-20241115103755418 img