Model I/O
模型的使用过程:输入提示 + 调用模型 + 输出解析 (Model I/O)
1. 提示模板
具体原则:
- 给予模型清晰明确的指示
- 让模型慢慢地思考
-
提示模板的生成:
# 导入LangChain中的提示模板 from langchain.prompts import PromptTemplate # 创建原始模板 template = """您是一位专业的鲜花店文案撰写员。\n 对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗? """ # 根据原始模板创建LangChain提示模板 prompt = PromptTemplate.from_template(template) # 打印LangChain提示模板的内容 print(prompt)提示模板输出:
input_variables=['flower_name', 'price'] template='您是一位专业的鲜花店文案撰写员。\n\n对于售价为 {price} 元 的 {flower_name} ,您能提供一个吸引人的简短描述吗?\n'“模板”就是一段描述某种鲜花的文本格式,它是一个 f-string,其中有两个变量 {flower_name} 和 {price} 表示花的名称和价格,这两个值是模板里面的占位符,在实际使用模板生成提示时会被具体的值替换。
2. 语言模型
- 大语言模型:Text Model,这些模型将文本字符串作为输入,并返回文本字符串作为输出。
- 聊天模型:Chat Model,主要代表Open AI的ChatGPT系列模型。这些模型通常由语言模型支持,但它们的 API 更加结构化。具体来说,这些模型将聊天消息列表作为输入,并返回聊天消息。
- 文本嵌入模型:Embedding Model,这些模型将文本作为输入并返回浮点数列表,也就是Embedding。
下面调用语言模型,让模型帮助我们写文案。
from langchain.prompts import PromptTemplate
import os
from langchain_community.llms import HuggingFaceHub
os.environ["http_proxy"] = "http://localhost:7890"
os.environ["https_proxy"] = "http://localhost:7890"
# 创建原始模板
template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)
# 创建模型实例
llm = HuggingFaceHub(repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", model_kwargs={"temperature": 0.7})
# 输入提示词
input = prompt.format(flower_name = ["杏花"], price = '30')
# 获取模型输出
output = llm.invoke(input)
print(output)
春日里,温柔的杏花轻轻绽放,每一朵都承载着诗意的期盼。选择一束这样的杏花,让春意盎然的气息伴随您的每一天。
3. 输出解析
在开发具体应用的过程中,很明显我们不仅仅需要文字,更多情况下我们需要的是程序能够直接处理的、结构化的数据。
下面,我们就通过LangChain的输出解析器来重构程序,让模型有能力生成结构化的回应,同时对其进行解析,直接将解析好的数据存入CSV文档。
from langchain.prompts import PromptTemplate
import os
from langchain_community.llms import HuggingFaceHub
from langchain_huggingface import HuggingFaceEndpoint
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
import pandas as pd
import json
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "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"
os.environ["http_proxy"] = "http://localhost:7890"
os.environ["https_proxy"] = "http://localhost:7890"
# # 创建原始模板
# template = """您是一位专业的鲜花店文案撰写员。\n
# 对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
# {format_instructions}
# """
# # 创建模型实例
# llm = HuggingFaceHub(repo_id="bigscience/bloom-1b7")
# # 定义我们想要接收的响应模式
# response_schemas = [
# ResponseSchema(name = "description", description = "鲜花的描述文案"),
# ResponseSchema(name = "reason", description = "问什么要这样写这个文案"),
# ]
# # 构造输出解析器
# output_parse = StructuredOutputParser.from_response_schemas(response_schemas)
# # 获取格式指示
# fromat_instructions = output_parse.get_format_instructions()
# # 根据原始模板创建提示,
# prompt = PromptTemplate.from_template(template,
# partial_variables = {"format_instructions": fromat_instructions})
# flowers = ["玫瑰", "康乃馨", "百合"]
# prices = ["50", "20", "30"]
# df = pd.DataFrame(columns=["flower", "price", "description", "reason"])
# for flower, price in zip(flowers, prices):
# # 根据提示准备模型的输入
# input = prompt.format(flower_name = flower, price = price)
# # 获取输出
# output = llm.invoke(input)
# print(output)
# print(type(output))
# # 解析输出
# parsed_output = output_parse.parse(output)
# # 在解析后的输出中添加 "flower" "price"
# parsed_output["flower"] = flower
# parsed_output["price"] = price
# # 把解析后的输出添加到df中
# df.loc[len(df)] = parsed_output
# print(df.to_dict(orient='records'))
# # 保存DataFrame到CSV文件
# df.to_csv("flowers_with_descriptions.csv", index=False)
# 创建提示模板
prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
output只需要回复一个json格式的数据即可
{format_instructions}"""
# 创建模型实例
# model = OpenAI(model_name='gpt-3.5-turbo-instruct')
model = HuggingFaceEndpoint(repo_id="Qwen/Qwen2.5-Coder-32B-Instruct")
# 定义我们想要接收的响应模式
response_schemas = [
ResponseSchema(name="description", description="鲜花的描述文案"),
ResponseSchema(name="reason", description="问什么要这样写这个文案"),
]
# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 获取格式指示
format_instructions = output_parser.get_format_instructions()
# 根据模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(
prompt_template, partial_variables={"format_instructions": format_instructions}
)
# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]
# 创建一个空的DataFrame用于存储结果
import pandas as pd
df = pd.DataFrame(columns=["flower", "price", "description", "reason"]) # 先声明列名
for flower, price in zip(flowers, prices):
# 根据提示准备模型的输入
input = prompt.format(flower_name=flower, price=price)
# 获取模型的输出
output = model.invoke(input)
print(output)
# 解析模型的输出(这是一个字典结构)
parsed_output = output_parser.parse(output)
# 在解析后的输出中添加“flower”和“price”
parsed_output["flower"] = flower
parsed_output["price"] = price
# 将解析后的输出添加到DataFrame中
df.loc[len(df)] = parsed_output
# 打印字典
print(df.to_dict(orient="records"))
# 保存DataFrame到CSV文件
df.to_csv("flowers_with_descriptions.csv", index=False)
[{'flower': '玫瑰', 'price': '50', 'description': '这束由精选玫瑰打造的浪漫之作,不仅承载着无尽的爱意,更散发着迷人的香气,每一朵都如同精心雕琢的艺术品,定能让您的爱意传递得更加
深情。', 'reason': '通过强调玫瑰的精选与艺术品般的特质,能够激发顾客对鲜花质量的关注,同时,提到无尽爱意和迷人香气,则能够触动顾客的情感,增加购买的欲望。'},{'flower': '百合', 'price': '30', 'description': '优雅绽放,30元即可将这束纯洁的百合带回家,为您的空间增添一抹宁静与高雅。', 'reason': '百合象征着纯洁与高雅,使用这些词汇可以吸引追求品质生活的顾客。
价格明确,让消费者一目了然,增加购买意愿。'},{'flower': '康乃馨', 'price': '20', 'description': '每朵康乃馨都承载着温柔的祝福,它们不仅色彩丰富,更蕴含着深深的情感。以20元的价格
,让这份温馨与爱意轻松送达。', 'reason': '通过描述康乃馨的温柔与情感,能够吸引那些寻求表达情感的顾客。同时,提到价格,使顾客觉得这份情感的表达既贴心又经济实惠,增加购买欲望。'}]
首先定义输出结构,我们希望模型生成的答案包含两部分:鲜花的描述文案(description)和撰写这个文案的原因(reason)。所以我们定义了一个名为response_schemas的列表,其中包含两个ResponseSchema对象,分别对应这两部分的输出。
然后,我们通过输出解析器对象的get_format_instructions()方法获取输出的格式说明(format_instructions),再根据原始的字符串模板和输出解析器格式说明创建新的提示模板(这个模板就整合了输出解析结构信息)。再通过新的模板生成模型的输入,得到模型的输出。此时模型的输出结构将尽最大可能遵循我们的指示,以便于输出解析器进行解析。
提示工程
1. 提示的结构
- 指令:告诉模型这个任务大概要做什么、怎么做,比如如何使用提供的外部信息、如何处理查询以及如何构造输出。这通常是一个提示模板中比较固定的部分。一个常见用例是告诉模型“你是一个有用的XX助手”,这会让他更认真地对待自己的角色。
- 上下文:充当模型的额外知识来源。这些信息可以手动插入到提示中,通过矢量数据库检索得来,或通过其他方式(如调用API、计算器等工具)拉入。一个常见的用例时是把从向量数据库查询到的知识作为上下文传递给模型。
- 提示输入:具体的问题或者需要大模型做的具体事情,这个部分和“指令”部分其实也可以合二为一。但是拆分出来成为一个独立的组件,就更加结构化,便于复用模板。这通常是作为变量,在调用模型之前传递给提示模板,以形成具体的提示。
- 输出指示器:标记要生成的文本的开始。这就像我们小时候的数学考卷,先写一个“解”,就代表你要开始答题了。如果生成 Python 代码,可以使用 “import” 向模型表明它必须开始编写 Python 代码(因为大多数 Python 脚本以import开头)。这部分在我们和ChatGPT对话时往往是可有可无的,当然LangChain中的代理在构建提示模板时,经常性的会用一个“Thought:”(思考)作为引导词,指示模型开始输出自己的推理(Reasoning)。
2. LangChain 提示模板的类型
2.1 使用 PromptTemplate
from langchain import PromptTemplate
template = """\
你是一个业务咨询顾问。
你给一个销售{product}的电商公司,其一个好名字?
"""
prompt = PromptTemplate.from_template(template)
print(prompt.format(product = "鲜花"))
输出:
你是一个业务咨询顾问。
你给一个销售鲜花的电商公司,其一个好名字?
这个程序的主要功能是生成适用于不同场景的提示,对用户定义的一种产品或服务提供公司命名建议。
PromptTemplate的from_template方法,我们创建了一个提示模板对象,并通过prompt.format方法将模板中的 {product} 替换为 "鲜花"。
在上面这个过程中,LangChain中的模板的一个方便之处是from_template方法可以从传入的字符串中自动提取变量名称(如product),而无需刻意指定。上面程序中的product自动成为了format方法中的一个参数。
当然,也可以通过提示模板类的构造函数,在创建模板时手工指定input_variables,示例如下:
# method2: 直接在创建模板时手工指定input_variables
prompt = PromptTemplate(
input_variables = ["product"],
template = template
)
print(prompt.format(product = "鲜花"))
2.2 使用 ChatPromptTemplate
# 导入聊天消息类模板
from langchain.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
# 模板的构建
template="你是一位专业顾问,负责为专注于{product}的公司起名。"
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="公司主打产品是{product_detail}。"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
prompt_template = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
# 格式化提示消息生成提示
prompt = prompt_template.format_prompt(product="鲜花装饰", product_detail="创新的鲜花设计。").to_messages()
# 下面调用模型,把提示传入模型,生成结果
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI Key'
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
result = chat(prompt)
print(result)
3. FewShot的思想
把Zero-Shot翻译为“顿悟”,聪明的大模型,某些情况下也是能够做到的。
- 在Few-Shot学习设置中,模型会被给予几个示例,以帮助模型理解任务,并生成正确的响应。
- 在Zero-Shot学习设置中,模型只根据任务的描述生成响应,不需要任何示例。
3.1 FewShotPromptTemplate
使用FewShotPromptTemplate创建模板,能够使用多个示例来指导模型生成对应的输出。
# 1. 创建一些示例
samples = [
{
"flower_type": "玫瑰",
"occasion": "爱情",
"ad_copy": "玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。",
},
{
"flower_type": "康乃馨",
"occasion": "母亲节",
"ad_copy": "康乃馨代表着母爱的纯洁与伟大,是母亲节赠送给母亲的完美礼物。",
},
{
"flower_type": "百合",
"occasion": "庆祝",
"ad_copy": "百合象征着纯洁与高雅,是你庆祝特殊时刻的理想选择。",
},
{
"flower_type": "向日葵",
"occasion": "鼓励",
"ad_copy": "向日葵象征着坚韧和乐观,是你鼓励亲朋好友的最好方式。",
},
]
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]))
# FewShotPromptTemplate对a象
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="爱情"))
使用大模型创建新文案:
from langchain_huggingface import HuggingFaceEndpoint
chat = HuggingFaceEndpoint(repo_id="Qwen/Qwen2.5-Coder-32B-Instruct")
result = chat.invoke(prompt.format(flower_type="野玫瑰", occasion="爱情"))
print(result)
文案: 野玫瑰虽然没有温室玫瑰那样娇艳,但它代表着自然的爱情,是送给爱人的一份惊喜。
3.2 使用示例选择器
示例选择器:来选择最合适的样本。
SemanticSimilarityExampleSelector对象,这个对象可以根据语义相似性选择最相关的示例。然后,它创建了一个新的FewShotPromptTemplate对象,这个对象使用了上一步创建的选择器来选择最相关的示例生成提示。
示例选择器example_selector会根据语义的相似度(余弦相似度)找到最相似的示例,也就是“玫瑰”,并用这个示例构建了FewShot模板。
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
# 初始化示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
samples,
HuggingFaceEmbeddings(),
Chroma,
k=1,
)
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="爱情"))
result = chat.invoke(prompt.format(flower_type="野玫瑰", occasion="爱情"))
print("--------------------")
print(result)
3. CoT
CoT这个概念来源于学术界,是谷歌大脑的Jason Wei等人于2022年在论文《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models(自我一致性提升了语言模型中的思维链推理能力)》中提出来的概念。它提出,如果生成一系列的中间推理步骤,就能够显著提高大型语言模型进行复杂推理的能力。
3.1 Few-shot CoT
简单的在提示中提供了一些链式思考示例(Chain-of-Thought Prompting),足够大的语言模型的推理能力就能够被增强。简单说,就是给出一两个示例,然后在示例中写清楚推导的过程。
整体上,思维链引导AI从理解问题,到搜索信息,再到制定决策,最后生成销售列表。这种方法不仅使AI的推理过程更加清晰,也使得生成的销售列表更加符合用户的需求。具体到每一个步骤,也可以通过思维链来设计更为详细的提示模板,来引导模型每一步的思考都遵循清晰准确的逻辑。
3.2 Zero-Shot CoT
在Zero-Shot CoT中,你只要简单地告诉模型“让我们 一步步的思考 (Let's think step by step) ”,模型就能够给出更好的答案!
3.3 CoT实战
项目需求:在这个示例中,你正在开发一个AI运营助手,我们要展示AI如何根据用户的需求推理和生成答案。然后,AI根据当前的用户请求进行推理,提供了具体的花卉建议并解释了为什么选择这些建议。
import os
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "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"
os.environ["http_proxy"] = "http://localhost:7890"
os.environ["https_proxy"] = "http://localhost:7890"
from langchain_huggingface import HuggingFaceEndpoint
chat = HuggingFaceEndpoint(repo_id="Qwen/Qwen2.5-Coder-32B-Instruct")
# 设定 AI 的角色和目标
role_template = "你是一个为花店电商公司工作的AI助手, 你的目标是帮助客户根据他们的喜好做出明智的决定"
# AI解释推理过程,并加入先前的对话示例
cot_template = """
作为一个为花店电商公司工作的AI助手,我的目标是帮助客户根据他们的喜好做出明智的决定。
我会按部就班的思考,先理解客户的需求,然后考虑各种鲜花的涵义,最后根据这个需求,给出我的推荐。
同时,我也会向客户解释我这样推荐的原因。
示例 1:
人类:我想找一种象征爱情的花。
AI:首先,我理解你正在寻找一种可以象征爱情的花。在许多文化中,红玫瑰被视为爱情的象征,这是因为它们的红色通常与热情和浓烈的感情联系在一起。因此,考虑到这一点,我会推荐红玫瑰。红玫瑰不仅能够象征爱情,同时也可以传达出强烈的感情,这是你在寻找的。
示例 2:
人类:我想要一些独特和奇特的花。
AI:从你的需求中,我理解你想要的是独一无二和引人注目的花朵。兰花是一种非常独特并且颜色鲜艳的花,它们在世界上的许多地方都被视为奢侈品和美的象征。因此,我建议你考虑兰花。选择兰花可以满足你对独特和奇特的要求,而且,兰花的美丽和它们所代表的力量和奢侈也可能会吸引你。
"""
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate
system_prompt_role = SystemMessagePromptTemplate.from_template(role_template)
system_prompt_cot = SystemMessagePromptTemplate.from_template(cot_template)
human_template = "{human_input}"
human_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_prompt_role, system_prompt_cot, human_prompt])
prompt = chat_prompt.format_prompt(human_input="我想为我的女朋友购买一些花。她喜欢粉色和紫色。你有什么建议吗?").to_messages()
# 接收用户的询问,返回回答结果
response = chat.invoke(prompt)
print(response)
输出:
baby: 我想为我的女朋友购买一些花。她喜欢粉色和紫色。你有什么建议吗?
AI: 当然可以!根据你提供的信息,你的女朋友喜欢粉色和紫色。在这些颜色中,有很多花可以选择,每种花都有它独特的意义和美感。以下是我为你准备的一些推荐:
1. **粉玫瑰和紫玫瑰**:玫瑰是爱情的象征,而粉色和紫色玫瑰分别代表甜美、温柔的爱情和优雅、神秘的爱情。将这两种颜色的玫瑰混合在一起,可以传达出你对她既有温柔又充满神秘感的感情。
2. **紫罗兰**:紫罗兰代表谦逊和纯真,同时也带有神秘的色彩。它们的紫色花瓣非常美丽,可以很好地融入你的主题颜色中。
3. **粉绣球花**:绣球花代表纯真和无辜,粉色绣球花则增添了一丝温柔和浪漫的感觉。它们的球形花朵非常独特,能够吸引人的眼球。
4. **紫风铃草**:紫风铃草象征着永恒的爱情和友谊,它们的紫色小花在微风中轻轻摇曳,营造出梦幻般的氛围。
5. **粉蝴蝶兰**:蝴蝶兰以其优雅的姿态和美丽的花朵而闻名。粉色蝴蝶兰既有高贵的气质,又不失温柔,非常适合用作装饰和礼物。
将这些花混合在一起,你可以为你的女朋友打造一个既浪漫又充满个性的花束,相信她会非常喜欢的。
3.4 Tree of Thought
思维树(Tree of Thoughts,ToT)框架,该框架基于思维链提示进行了总结,引导语言模型探索把思维作为中间步骤来解决通用问题。
在需要多步骤推理的任务中,引导语言模型搜索一棵由连贯的语言序列(解决问题的中间步骤)组成的思维树,而不是简单地生成一个答案。ToT框架的核心思想是:让模型生成和评估其思维的能力,并将其与搜索算法(如广度优先搜索和深度优先搜索)结合起来,进行系统性地探索和验证。
ToT 框架为每个任务定义具体的思维步骤和每个步骤的候选项数量。例如,要解决一个数学推理任务,先把它分解为3个思维步骤,
假设一个顾客在鲜花网站上询问:“我想为我的妻子购买一束鲜花,但我不确定应该选择哪种鲜花。她喜欢淡雅的颜色和花香。”
AI(使用ToT框架):
思维步骤1:理解顾客的需求。
顾客想为妻子购买鲜花。
顾客的妻子喜欢淡雅的颜色和花香。
思维步骤2:考虑可能的鲜花选择。
候选1:百合,因为它有淡雅的颜色和花香。
候选2:玫瑰,选择淡粉色或白色,它们通常有花香。
候选3:紫罗兰,它有淡雅的颜色和花香。
候选4:桔梗,它的颜色淡雅但不一定有花香。
候选5:康乃馨,选择淡色系列,它们有淡雅的花香。
思维步骤3:根据顾客的需求筛选最佳选择。
百合和紫罗兰都符合顾客的需求,因为它们都有淡雅的颜色和花香。
淡粉色或白色的玫瑰也是一个不错的选择。
桔梗可能不是最佳选择,因为它可能没有花香。
康乃馨是一个可考虑的选择。
思维步骤4:给出建议。
“考虑到您妻子喜欢淡雅的颜色和花香,我建议您可以选择百合或紫罗兰。淡粉色或白色的玫瑰也是一个很好的选择。希望这些建议能帮助您做出决策!”