一、报错
在运行03_FewShotPrompt.py时候报错:
当按照AI提示:“pip install --upgrade protobuf”之后还是报相同的错误。最后,我发现:在 chromadb 库的导入过程中,具体是因为 protobuf 版本不兼容导致的。因此,尝试将 protobuf 版本降级到 3.20.x 或更低版本,可以通过以下命令完成:
pip install protobuf==3.20.0
然后,再次运行03_FewShotPrompt.py,发现没有报错,图片如下。
二、思考题
2.1 思考题1
题目:如果你观察LangChain中的prompt.py中的PromptTemplate的实现代码,你会发现除了我们使用过的input_variables、template等初始化参数之外,还有template_format、validate_template等参数。举例来说,template_format可以指定除了f-string之外,其它格式的模板,比如jinja2。请你查看LangChain文档,并尝试使用这些参数。
解答:(1)对于template_format而言,有f-string和jinjia2两种格式。通过以下四个例子,可以帮助你更深入了解二者的区别:
# 导入 PromptTemplate 类
from langchain.prompts.prompt import PromptTemplate
# 区分f-string和jinja2模板格式
# 1.f-string 模板格式
# 1-1.默认为f-string模板
prompt_fstring_1 = PromptTemplate(
input_variables=["name", "age"], # 输入变量列表
template="Hello, my name is {name} and I am {age} years old."
)
# 1-2.使用 f-string 模板格式
prompt_fstring_2 = PromptTemplate(
input_variables=["name", "age"], # 输入变量列表
template="Hello, my name is {name} and I am {age} years old.", # 模板字符串,使用 f-string 格式
template_format="f-string" # 指定模板格式为 f-string
)
# 2-1.使用 Jinja2 模板格式,基本示例
prompt_jinja2_1 = PromptTemplate(
input_variables=["name", "age"], # 输入变量列表
template="Hello, my name is {{name}} and I am {{age}} years old.", # 模板字符串,使用 Jinja2 格式
template_format="jinja2" # 指定模板格式为 Jinja2
)
# 2-2.使用 Jinja2 模板格式,包含方法调用和算术运算
prompt_jinja2_2 = PromptTemplate(
input_variables=["name", "age"], # 输入变量列表
template="Hello, my name is {{name.upper()}} and I am {{age + 5}} years old.", # 模板字符串,使用 Jinja2 格式,包含方法调用和算术运算
template_format="jinja2" # 指定模板格式为 Jinja2
)
# 2-3.使用 Jinja2 模板格式,包含条件语句
prompt_jinja2_3 = PromptTemplate(
input_variables=["name", "age"], # 输入变量列表
template="""
Hello, my name is {{ name }} and I am {{ age }} years old.
{% if age > 25 %}
You are an adult.
{% endif %}
""", # 模板字符串,使用 Jinja2 格式,包含条件语句
template_format="jinja2" # 指定模板格式为 Jinja2
)
# 渲染各个模板
print('prompt_fstring_1.format(name="Alice", age=30):\n', prompt_fstring_1.format(name="Alice", age=30))
print('prompt_fstring_2.format(name="Alice", age=30):\n', prompt_fstring_2.format(name="Alice", age=30))
print('prompt_jinja2_1.format(name="Alice", age=30):\n', prompt_jinja2_1.format(name="Alice", age=30))
print('prompt_jinja2_2.format(name="Alice", age=30):\n', prompt_jinja2_2.format(name="Alice", age=30))
print('prompt_jinja2_3.format(name="Alice", age=30):\n', prompt_jinja2_3.format(name="Alice", age=30))
依据上面代码,运行结果如下。
可以总结:
①f-string适用于:使用单括号{},简单、高效,适合简单的字符串插值和表达式计算。②jinja2适用于:使用双括号{{}},强大、灵活,支持复杂的模板逻辑和控制结构,适合需要更多功能的场景。
(2)对于validate_template而言,主要目的是在初始化 PromptTemplate 对象时验证模板的有效性。具体来说,它会检查以下几点:
-
变量名匹配:
- 模板中使用的变量名必须与
input_variables列表中的变量名完全匹配。如果模板中包含了input_variables列表中未声明的变量名,或者缺少某些必需的变量名,那么当validate_template为True时,将抛出ValueError异常。
- 模板中使用的变量名必须与
-
模板格式正确:
- 模板的格式必须符合指定的模板格式(例如
f-string或jinja2)。如果模板格式不正确(例如,在jinja2模板中使用了错误的变量标记),同样会抛出ValueError异常。
- 模板的格式必须符合指定的模板格式(例如
from langchain.prompts.prompt import PromptTemplate
# validate_template参数的使用
# 本示例展示了如何使用 validate_template 参数来验证模板的有效性
print('******************1**********************')
try:
prompt_valid1 = PromptTemplate(
input_variables=["name", "age"],
template="Hello, my name is {name} and I am {age} years old.",
validate_template=True
)
print("prompt_valid1 initialized successfully.")
result1 = prompt_valid1.format(name="Alice", age=30)
print(result1) # 输出: Hello, my name is Alice and I am 30 years old.
except ValueError as e:
print(f"Error initializing prompt_valid1: {e}")
print('******************2**********************')
try:
prompt_valid2 = PromptTemplate(
input_variables=["name", "age"],
template="Hello, my name is {arr}.",
validate_template=True
)
print("prompt_valid2 initialized successfully.")
result2 = prompt_valid2.format(name="Alice")
print(result2) # 输出: Hello, my name is Alice and I am 30 years old.
except ValueError as e:
print(f"Error initializing prompt_valid2: {e}")
print('******************3**********************')
try:
prompt_valid3 = PromptTemplate(
input_variables=["name", "age"],
template="Hello, my name is {name}.",
template_format="jinja2",
validate_template=True
)
print("prompt_valid3 initialized successfully.")
result3 = prompt_valid3.format(name="Alice", age=30)
print(result3) # 输出: Hello, my name is Alice and I am 30 years old.
except ValueError as e:
print(f"Error initializing prompt_valid3: {e}")
# 禁用验证
print('******************4**********************')
try:
prompt_valid4 = PromptTemplate(
input_variables=["name", "age"],
template="Hello, my name is {arr}.",
validate_template=False
)
print("prompt_valid4 initialized successfully.")
result4 = prompt_valid4.format(name="Alice", age=30)
print(result4) # 输出: Hello, my name is Alice and I am 30 years old.
except ValueError as e:
print(f"Error initializing prompt_valid4: {e}")
依据上面代码,运行结果如下。
通过这四个示例,可以更全面地了解
validate_template参数的作用和重要性。在实际应用中,建议根据具体需求启用或禁用该参数,以确保模板的正确性和代码的健壮性。
2.2 思考题2
题目:2. 请你尝试使用PipelinePromptTemplate和自定义Template。
ipelinePromptTemplate 是 langchain 库中的一种高级模板类,用于构建复杂的多阶段提示生成流程。它允许你定义多个子模板,并在最终渲染时按顺序应用这些子模板。这样可以逐步构建最终的提示文本,使得提示生成更加灵活和强大。参考链接
PipelinePromptTemplate 的作用
- 多阶段提示生成:
PipelinePromptTemplate允许你定义多个子模板,每个子模板负责生成一部分最终提示的一部分。这些子模板可以按顺序应用,逐步构建最终的提示文本。 - 动态变量生成: 子模板可以生成动态变量,这些变量可以在后续的子模板或最终模板中使用。这样可以实现更复杂的逻辑,例如根据某个输入生成另一个输入,再基于新的输入生成最终提示。
- 灵活的提示结构: 通过组合多个子模板,可以构建复杂的提示结构,而不需要在一个模板中处理所有逻辑。这使得提示生成更加模块化和可维护。
from langchain.prompts import PromptTemplate, PipelinePromptTemplate
from langchain_openai import ChatOpenAI
import os
# 第一步:定义和配置提示模板
# 定义最终的完整模板
# 输入变量包括 "公司名称" 和 "产品"
# 模板字符串为 "为{公司名称}写一个标语,这家公司生产{产品}。"
full_template = PromptTemplate(
input_variables=["公司名称", "产品"],
template="为{公司名称}写一个标语,这家公司生产{产品}。"
)
# 定义生成公司名称的子模板
# 输入变量包括 "产品"
# 模板字符串为 "一家生产{产品}的公司的好名字是: "
name_template = PromptTemplate(
input_variables=["产品"],
template="一家生产{产品}的公司的好名字是: "
)
# 创建 PipelinePromptTemplate
# final_prompt 指定最终的完整模板
# pipeline_prompts 是一个列表,包含 (变量名, 子模板) 对
# 这里我们指定 "公司名称" 变量由 name_template 子模板生成
pipeline_template = PipelinePromptTemplate(
final_prompt=full_template,
pipeline_prompts=[
("公司名称", name_template),
]
)
# 第二步:渲染 PipelinePromptTemplate 并调用模型
# 渲染 PipelinePromptTemplate
# 提供 "产品" 变量的值为 "智能家居设备"
# PipelinePromptTemplate 会先使用 name_template 生成 "公司名称",然后将其传递给 full_template
prompt = pipeline_template.format(产品="智能家居设备")
print('prompt:\n', prompt) # 输出生成的最终提示
#第三步:调用模型
# 初始化 ChatOpenAI 客户端,使用环境变量 LLM_MODELEND 获取模型名称
model = ChatOpenAI(
model=os.environ.get("LLM_MODELEND"),
)
# 调用 ChatOpenAI 的模型,传入生成的提示,获取模型的响应
result = model(prompt)
print('result:\n', result) # 输出模型的响应
依据上面代码,运行结果如下。
希望通过上面的例子,可以帮助你理解PipelinePromptTemplate的作用。
2.3 思考题3
题目:请你构想一个关于鲜花店运营场景中客户服务对话的少样本学习任务。在这个任务中,模型需要根据提供的示例,学习如何解答客户的各种问题,包括询问花的价格、推荐鲜花、了解鲜花的保养方法等。最好是用ChatModel完成这个任务。 通过使用少样本学习技术,我们可以更高效地训练模型,使其在面对客户的实际问题时,能够给出准确且有用的回答。这不仅有助于提升鲜花店的客户服务质量,还能增强客户的购物体验,从而增加客户的忠诚度和回头率。以下是实现这一任务的代码部分:
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
AIMessagePromptTemplate
)
from langchain.chat_models import ChatOpenAI
import os
# 定义单个示例的模板
example_template = PromptTemplate(
input_variables=["question", "answer"],
template="客户: {question}\n客服: {answer}"
)
# 定义示例数据
examples = [
{
"question": "你好,我想知道玫瑰花的价格是多少?",
"answer": "您好!我们的玫瑰花价格是每支10元。如果您购买一束(12支),价格是120元。还有其他需要咨询的吗?"
},
{
"question": "我想买一些适合送给妈妈的花,有什么推荐吗?",
"answer": "当然可以!我们推荐康乃馨,它象征着母爱和感恩。另外,百合花也很适合,它代表着纯洁和美好。您可以考虑这两款花。还有其他需要帮助的吗?"
},
{
"question": "我刚买的百合花怎么保养才能让它开得更久?",
"answer": "您好!百合花的保养方法如下:\n1. 将花瓶清洗干净,加入清水。\n2. 每天更换一次水,保持水质清洁。\n3. 剪去花茎底部约1厘米,以促进水分吸收。\n4. 避免阳光直射和高温环境,放在阴凉处。\n5. 可以在水中加入少量的糖或维生素C片,有助于延长花期。"
}
]
# 创建 FewShotPromptTemplate
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_template,
prefix="这是一个关于鲜花店客户服务的对话示例:",
suffix="现在轮到你了,请回答以下问题:\n客户: {question}\n客服:",
input_variables=["question"]
)
# 创建 ChatPromptTemplate
system_message = SystemMessagePromptTemplate.from_template("你是一位专业的鲜花店客服,负责回答客户的问题。")
human_message = HumanMessagePromptTemplate.from_template("{question}")
ai_message = AIMessagePromptTemplate.from_template("{answer}")
chat_prompt = ChatPromptTemplate.from_messages([
system_message,
human_message,
ai_message
])
# 将 FewShotPromptTemplate 和 ChatPromptTemplate 结合
def create_few_shot_chat_prompt(question):
few_shot_example = few_shot_prompt.format(question=question)
return chat_prompt.format_messages(
question=few_shot_example,
answer=""
)
# 初始化 ChatModel
chat_model = ChatOpenAI(model=os.environ.get("LLM_MODELEND"))
# 测试模型
questions = [
"你好,我想知道向日葵的价格是多少?",
"我想买一些适合送给朋友的花,有什么推荐吗?",
"我刚买的玫瑰花怎么保养才能让它开得更久?"
]
for question in questions:
prompt = create_few_shot_chat_prompt(question)
response = chat_model(prompt)
print(f"客户: {question}\n客服: {response.content}\n")
依据上面代码,运行结果:
通过运行上述代码,我们可以看到模型在接收到客户的各种问题后,能够基于提供的少量示例,生成准确且有用的回答。