4、LangChain —— 提示工程 (上) fewshottemplate 和 exampleselector


一、什么是提示词工程

 其实,在上一章中就提到了提示词工程,输出解析器的原理实际上就是通过提示词明确地告诉 llm 应该做什么。
 之前有说过吴恩达老师说过的提示词两大原则:清晰具体的指令、给模型思考的时间。实际上,在 Open AI 的官方文档 GPT 最佳实践中,也给出了和上面这两大原则一脉相承的 6大策略,分别是:

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

二、提示的结构

在这里插入图片描述
 当然了,从大原则到实践,还是有一些具体工作需要说明,上面是一个实用的提示框架。在这个提示框架中:

  1. 指令 instruction:
     告诉模型这个任务大概要做什么、怎么做。这通常是一个提示模板中比较固定的部分。一个常见用例是告诉模型“你是一个有用的 XX 助手”。
  2. 上下文 context:
     模型的额外知识来源。一个常见的用例时是把从向量数据库查询到的知识作为上下文传递给模型。
  3. 提示输入 prompt input:
     具体的问题或者需要大模型做的具体事情。这个部分和“指令”部分其实也可以合二为一。但是拆分出来成为一个独立的组件,就更加结构化,便于复用模板。
     这通常是作为变量,在调用模型之前传递给提示模板,以形成具体的提示。
  4. 输出指示器 output indicator:
     标记​​要生成的文本的开始。这就像我们小时候的数学考卷,先写一个“解”,就代表你要开始答题了。如果生成 Python 代码,可以使用 “import” 向模型表明它必须开始编写 Python 代码 (因为大多数 Python 脚本以 import 开头) 。
     这部分在我们和 ChatGPT 对话时往往是可有可无的,当然 LangChain 中的代理在构建提示模板时,经常性的会用一个“Thought:”作为引导词,指示模型开始输出自己的推理 Reasoning。

三、LangChain 提示模板的类型

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

  1. PromptTemplate —— 这是最常用的 string 提示模板,我们已经使用过 PromptTemplate 语句导入这个模板。
  2. ChatPromptTemplate —— 常用的 Chat 提示模板,用于组合各种角色的消息模板,传入 聊天模型 (Chat Model),具体消息模板包括:ChatMessagePromptTemplate、HumanMessagePromptTemplate、AIMessagePromptTemplate、SystemMessagePromptTemplate
  3. FewShotPromptTemplate —— 少样本提示模板,通过示例的展示来 “教” 模型如何回答。
  4. PiplinePrompt —— 用于把几个提示组合在一起使用。
  5. 自定义模板 —— LangChain 还允许你基于其他模板类来定制自己的提示模板。

 这些模板的导入方式如下:

from langchain.prompts.prompt import PromptTemplate
from langchain.prompts import ChatPromptTemplate
from langchain.prompts import FewShotPromptTemplate
from langchain.prompts.pipeline import PipelinePromptTemplate
from langchain.prompts import ChatMessagePromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate

 下面我们通过示例来介绍上面这些模版,前两个我们简单了解就好,其中最典型的 FewShotPromptTemplate 会重点讲。至于 PipelinePrompt 和自定义模板,使用起来比较简单,请你 参考 LangChain 文档自己学习


四、使用 PromptTemplate

 下面通过示例简单说明一下 PromptTemplate 的使用。

from langchain import PromptTemplate

template = """\
你是业务咨询顾问。
你给一个销售{product}的电商公司,起一个好的名字?
"""
prompt = PromptTemplate.from_template(template)

print(prompt.format(product="鲜花"))
print(prompt)
"""
你是业务咨询顾问。
你给一个销售鲜花的电商公司,起一个好的名字?
input_variables=['product'] template='你是业务咨询顾问。\n你给一个销售{product}的电商公司,起一个好的名字?\n'
"""

 在这里,“你是业务咨询顾问。你给一个销售{product}的电商公司,起一个好的名字?” 就是原始提示模板,其中 {product} 是占位符。
 然后通过 PromptTemplate 的 from_template 方法,我们创建了一个提示模板对象,并通过 prompt.format 方法将模板中的 {product} 替换为 “鲜花”。
 在上面这个过程中,LangChain 中的模板的一个方便之处是 from_template 方法可以从传入的字符串中 自动提取变量名称,如 product,而无需刻意指定。上面程序中的 product 自动成为了 format 方法中的一个参数

 当然,也可以通过 提示模板类的构造函数,在 创建模板时 手工指定 input_variables,示例如下:

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

五、使用 ChatPromptTemplate

 对于 聊天模型 Chat Model,LangChain 也提供了一系列的模板,这些模板的不同之处是它们有对应的 角色。下面代码展示了 OpenAI 的 Chat Model 中的各种消息角色。

import openai
openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
        {"role": "user", "content": "Where was it played?"}
    ]
)

 OpenAI 对传输到 gpt-3.5-turbo 和 GPT-4 的 messsage 格式说明如下:

消息必须是 消息对象的数组,其中 每个对象 都有 一个角色 (系统、用户或助理)内容。对话可以短至一条消息,也可以来回多次。
通常,对话首先由 系统消息 格式化,然后是交替的 用户消息助理消息
系统消息 有助于设置助手的行为。例如,你可以 修改助手的个性 或提供 有关其在整个对话过程中应如何表现的具体说明。但请注意,系统消息是可选的,并且没有系统消息的模型的行为可能类似于使用通用消息,例如“你是一个有用的助手”。
用户消息 提供助理响应的请求或评论。
助理消息 存储以前的助理响应,但也可以由你编写以给出所需行为的示例。

 LangChain 的 ChatPromptTemplate 这一系列的模板,就是跟着这一系列角色而设计的。下面给出一个示例:

# 导入聊天消息类模板
from langchain.prompts import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

# 模板的构建
template="你是一位专业顾问,负责为专注于{product}的公司起名。"
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
print(system_message_prompt,"\n")

human_template="公司主打产品是{product_detail}。"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
print(human_message_prompt,"\n")

prompt_template = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
print(prompt_template,"\n")

# 格式化提示消息生成提示
prompt = prompt_template.format_prompt(product="鲜花装饰", product_detail="创新的鲜花设计").to_messages()
print(prompt,"\n")

# 下面调用模型,把提示传入模型,生成结果
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI Key'
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
result = chat(prompt)
print(result)
"""
prompt=PromptTemplate(input_variables=['product'], template='你是一位专业顾问,负责为专注于{product}的公司起名。') 

prompt=PromptTemplate(input_variables=['product_detail'], template='公司主打产品是{product_detail}。')

input_variables=['product', 'product_detail'] messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=['product'], template='你是一位专业顾问,负责为专注于{product}的公 
司起名。')), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['product_detail'], template='公司主打产品是{product_detail}。'))]

[SystemMessage(content='你是一位专业顾问,负责为专注于鲜花装饰的公司起名。'), HumanMessage(content='公司主打产品是创新的鲜花设计。')]

content='1. 花语创意\n2. 花韵设计\n3. 花艺创新\n4. 花漾装饰\n5. 花语装点\n6. 花翩翩\n7. 花语之美\n8. 花馥馥\n9. 花语时尚\n10. 花之魅力' 
additional_kwargs={} 
example=False
"""

 从上面的输出可以看出,各个语句的具体作用。


六、FewShot 的起源

 如果某个人第一次听说某个概念,却能马上知道是什么意思,这就叫 Zero-Shot,表明这个人的天赋不是一般的高,从知识积累和当前语境中就能够推知新词的涵义。有时候我们把 Zero-Shot 翻译为“顿悟”,聪明的大模型,某些情况下也是能够做到的。
 Few-Shot(少样本)、One-Shot(单样本)和与之对应的 Zero-Shot(零样本)的概念都起源于机器学习。如何让机器学习模型在极少量甚至没有示例的情况下学习到新的概念或类别,对于许多现实世界的问题是非常有价值的,因为我们往往无法获取到大量的标签化数据。


七、使用 FewShotPromptTemplate

1、创建示例样本

 首先,创建一些示例,作为 提示的样本。其中 每个示例 都是 一个字典,其中 输入变量 是这些 输入变量的值

# 1. 创建一些示例
samples = [
  {
    "flower_type": "玫瑰",
    "occasion": "爱情",
    "ad_copy": "玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。"
  },
  {
    "flower_type": "康乃馨",
    "occasion": "母亲节",
    "ad_copy": "康乃馨代表着母爱的纯洁与伟大,是母亲节赠送给母亲的完美礼物。"
  },
  {
    "flower_type": "百合",
    "occasion": "庆祝",
    "ad_copy": "百合象征着纯洁与高雅,是你庆祝特殊时刻的理想选择。"
  },
  {
    "flower_type": "向日葵",
    "occasion": "鼓励",
    "ad_copy": "向日葵象征着坚韧和乐观,是你鼓励亲朋好友的最好方式。"
  }
]

 samples 这个 列表,它包含了 四个字典每个字典 代表了 一种花的类型、适合的场合,以及对应的广告文案。 这些示例样本,就是构建 FewShotPrompt 时,作为例子传递给模型的参考信息。

2、创建提示模板

 配置一个提示模板,将一个 samples 格式化为字符串。这个格式化程序应该是一个 PromptTemplate 对象

# 2. 创建一个提示模板
from langchain.prompts.prompt import PromptTemplate

template="鲜花类型: {flower_type}\n场合: {occasion}\n文案: {ad_copy}"
prompt_sample = PromptTemplate(input_variables=["flower_type", "occasion", "ad_copy"], 
                               template=template)
print(prompt_sample.format(**samples[0]))
"""
鲜花类型: 玫瑰
场合: 爱情
文案: 玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。
"""

 在这个步骤中,我们创建了一个 PromptTemplate 对象。这个对象 根据 指定的输入变量 和 模板字符串 来生成提示。在这里,输入变量包括 “flower_type”、“occasion”、“ad_copy”,模板是一个字符串,其中包含了用大括号包围的变量名,它们会被对应的变量值替换。
 到这里,我们就把 字典中的示例格式 转换成了 提示模板,可以形成一个个具体可用的 LangChain 提示。比如我用 samples[0] 中的数据替换了模板中的变量,生成了一个完整的提示。

3、创建 FewShotPromptTemplate 对象

 然后,通过使用上一步骤中创建的 prompt_sample,以及 samples 列表中的所有示例, 创建一个 FewShotPromptTemplate 对象,生成更复杂的提示。

# 3. 创建一个FewShotPromptTemplate对象
from langchain.prompts.few_shot import FewShotPromptTemplate

prompt = FewShotPromptTemplate(
    examples=samples,
    example_prompt=prompt_sample,
    suffix="鲜花类型: {flower_type}\n场合: {occasion}",
    input_variables=["flower_type", "occasion"]
)
print(prompt.format(flower_type="野玫瑰", occasion="爱情"))
"""
鲜花类型: 玫瑰
场合: 爱情
文案: 玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。

鲜花类型: 康乃馨
场合: 母亲节
文案: 康乃馨代表着母爱的纯洁与伟大,是母亲节赠送给母亲的完美礼物。

鲜花类型: 百合
场合: 庆祝
文案: 百合象征着纯洁与高雅,是你庆祝特殊时刻的理想选择。

鲜花类型: 向日葵
场合: 鼓励
文案: 向日葵象征着坚韧和乐观,是你鼓励亲朋好友的最好方式。

鲜花类型: 野玫瑰
场合: 爱情
"""

 可以看到,FewShotPromptTemplate 是一个更复杂的提示模板,它包含了多个示例和一个提示。

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

 最后,把这个对象输出给大模型,就可以根据提示,得到我们所需要的文案了!

# 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。
 LangChain 给我们提供了 示例选择器,来选择最合适的样本 (注意,因为示例选择器使用 向量相似度比较 的功能,此处需要安装 向量数据库,如 Chroma)。

# 5. 使用示例选择器
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# 初始化示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
    samples,
    OpenAIEmbeddings(),
    Chroma,
    k=1
)

# 创建一个使用示例选择器的FewShotPromptTemplate对象
prompt = FewShotPromptTemplate(
    example_selector=example_selector, 
    example_prompt=prompt_sample, 
    suffix="鲜花类型: {flower_type}\n场合: {occasion}", 
    input_variables=["flower_type", "occasion"]
)
print(prompt.format(flower_type="红玫瑰", occasion="爱情"))
"""
鲜花类型: 玫瑰
场合: 爱情
文案: 玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。

鲜花类型: 红玫瑰
场合: 爱情
"""

 在这个步骤中,它首先创建了一个 SemanticSimilarityExampleSelector 对象,这个对象可以 根据语义相似性 选择最相关的示例。
 然后,它创建了一个新的 FewShotPromptTemplate 对象,这个对象使用了上一步创建的选择器来选择最相关的示例生成提示。然后,我们又用这个模板生成了一个新的提示,因为我们的提示中需要创建的是红玫瑰的文案,所以,示例选择器 example_selector 会根据 语义的相似度 (余弦相似度) 找到最相似的示例,也就是“玫瑰”,并用这个示例构建了 FewShot 模板。这样,我们就避免了把过多的无关模板传递给大模型,以节省 Token 的用量。

### RAG 架构与 LangChain 框架的关系及区别 #### 关系 LangChain 提供了一个强大的框架用于开发基于语言模型的应用程序,特别适合简化与大型预训练模型的交互过程、数据检索以及将不同的功能模块连接起来以执行复杂的任务[^1]。RAG(Retrieval-Augmented Generation),即检索增强生成技术,在此框架内扮演着重要角色。该技术融合了传统的信息检索方法现代的语言生成能力,从而提高了自然语言处理任务的效果。 具体来说,当利用 LangChain 实现 RAG 时,可以构建一个高效的问答系统或其他类型的 NLP 应用程序。这种组合不仅能够快速定位相关的信息片段,还能在此基础上生成连贯且上下文一致的回答或文本输出[^2]。 #### 区别 尽管两者紧密相连并共同服务于提升NLP性能的目标,但从本质上讲: - **LangChain** 是一种通用型工具集/平台,支持多种应用场景下的开发工作,除了实现像 RAG 这样的特定机制外,还可以做很多其他事情,比如对话管理、提示工程等。 - **RAG** 则更侧重于解决如何有效地结合检索生成两个方面的问题,是一种专门针对某些类型的任务设计的技术方案。它可以在 LangChain 或者其他的平台上被实施,但本身并不是一个独立的产品或服务[^4]。 ```python from langchain import Rag, PromptTemplate, LLMChain rag = Rag( retriever=..., generator=... ) prompt_template = PromptTemplate(input_variables=["context", "question"], template="...") llm_chain = LLMChain(prompt=prompt_template, llm=...) ``` 上述代码展示了如何在 Python 中使用 `langchain` 库创建一个简单的 RAG 流程实例。这表明虽然二者有联系但也存在明显差异——一个是用来搭建整个应用生态的基础组件;另一个是在此基础上进一步优化特定环节的方法论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值