(15-3)langchain模型I/O与数据增强:聊天提示模板

3.3  聊天提示模板

提示模板是在使用语言模型时用于生成输入文本的结构化模板,通常用于指导模型生成符合特定格式要求的文本。在 LangChain 中,提示模板是一个灵活的工具,可以用于各种场景,包括聊天对话、问题回答、任务指导等。提示模板的主要特征和组成部分如下所示。

  1. 模板字符串(Template String):这是提示模板的核心,它定义了生成的文本的基本结构。模板字符串中通常包含占位符或格式化标记,用于插入变量值或执行特定的文本格式化操作。
  2. 输入变量(Input Variables):这些是在模板字符串中使用的占位符,用于表示输入的变量。在生成文本时,输入变量将被替换为实际的数值或文本。例如,一个聊天对话的提示模板可能包含名为“user_message”的输入变量,用于表示用户的输入消息。
  3. 部分变量(Partial Variables):这些是模板的一部分,在生成文本时可以被预先填充为特定的值。部分变量通常用于那些在模板使用之前就已经确定了值的情况。例如,如果模板中需要包含当前日期,那么可以使用部分变量将日期预先填充进模板中。
  4. 模板方法(Template Methods):这些是一些用于对模板执行操作的方法。例如,格式化模板字符串、执行部分填充、生成最终的文本等。模板方法使得可以在模板的基础上执行各种操作,以满足具体的需求。
  5. 格式化(Formatting):格式化是将模板字符串中的占位符替换为实际数值或文本的过程。这一过程通常由模板方法或模板引擎自动完成,但有时也可以手动执行。

提示模板在自然语言生成任务中具有广泛的应用,可以帮助开发者快速构建符合要求的文本生成系统,并且使得文本生成过程更加灵活和可控。

3.3.1  BaseChatPromptTemplate介绍

在LangChain中,langchain_core.prompts.chat.BaseChatPromptTemplate 是一个基类,用于创建和管理聊天提示模板。类BaseChatPromptTemplate提供了构建聊天机器人对话系统的基础结构和方法,可以被继承和扩展以满足不同的应用场景。BaseChatPromptTemplate可以被子类化以创建不同类型的聊天模型提示,其主要成员方法如下所示。

  1. abatch 和 abatch_as_completed:这些方法用于并行处理多个输入,适用于提高聊天系统的吞吐量。
  2. aformat 和 aformat_messages:这些方法用于格式化聊天模板和消息,将变量插入到模板中以生成最终的聊天消息。
  3. aformat_prompt 和 invoke:这些方法用于创建提示值和调用聊天模型,生成基于模板的聊天回复。
  4. assign:允许为这个可运行对象分配新的字段,返回一个新的可运行对象。
  5. astream 和 astream_events:这些方法用于生成关于聊天模型执行进度的实时信息流。
  6. partial:返回提示模板的部分实例,这在不需要完整输入时非常有用。
  7. save:将提示模板保存到文件中,便于后续使用或分享。

3.3.2  少量示例提示模板

在LangChain中,FewShotChatMessagePromptTemplate 是用于在聊天模型中执行少量示例提示的模板。类FewShotChatMessagePromptTemplate允许创建包含前缀消息、示例消息和后缀消息的聊天提示模板,这些消息可以用于构建包含中间示例的对话,例如展示一系列的问答对。

FewShotChatMessagePromptTemplate的主要特点如下所示。

  1. 少数示例支持:能够根据输入动态选择示例,或者从固定列表中生成示例。
  2. 灵活的结构:生成的提示模板具有高度的结构化,包括系统消息、人类消息和 AI 消息。
  3. 示例格式化:可以使用 example_prompt 对每个示例进行格式化,以便将其插入到聊天提示中。
  4. 元数据和追踪:支持使用元数据和标签来追踪和记录聊天提示的详细信息。

FewShotChatMessagePromptTemplate包含的主要成员方法如下所示。

  1. __init__:这是FewShotChatMessagePromptTemplate的构造方法,用于初始化 FewShotChatMessagePromptTemplate 实例。它接受参数,如示例数据、用于格式化每个示例的提示模板等。
  2. format:将输入变量格式化为字符串,使用提供的示例和 example_prompt 来构建最终的聊天提示字符串。
  3. format_messages:与 format 类似,但返回的是一个消息列表,每个消息都是格式化后的聊天消息的一部分。
  4. aformat_prompt:异步方法,用于创建 PromptValue 对象,这可以用于进一步的处理或传递给语言模型。
  5. abatch:异步方法,使用 asyncio.gather 并行处理一批输入,适用于 I/O 绑定的任务。
  6. abatch_as_completed:异步方法,异步地并行处理一批输入,并在每个结果完成时生成它们。
  7. assign:允许为这个可运行对象分配新的字段,并返回一个新的可运行对象。
  8. save:将提示模板保存到文件中,便于后续使用或分享。
  9. json:生成模型的 JSON 表示,包括包含和排除参数的选项。
  10. to_json:序列化可运行对象到 JSON。
  11. pretty_print:提供一个人类可读的表示形式。
  12. schema 和 schema_json:生成模型的 JSON 模式定义。

例如下面是一个使用 FewShotChatMessagePromptTemplate 的例子,实现了一个少量示例提示的模板。

实例3-10实现了一个少量示例提示的模板(源码路径:codes\3\PromptTemplate01.py

实例文件PromptTemplate01.py的具体实现代码如下所示。

from langchain.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate

# 定义示例列表
examples = [
    {"input": "猫的叫声是什么?", "output": "喵喵"},
    {"input": "狗的叫声是什么?", "output": "汪汪"},
]

# 定义每个示例的模板
example_prompt = ChatPromptTemplate.from_messages(
    [
        ("human", "{input}"),
        ("ai", "{output}"),
    ]
)

# 创建 FewShotChatMessagePromptTemplate 对象
few_shot_prompt = FewShotChatMessagePromptTemplate(
    example_prompt=example_prompt,
    examples=examples,
)

# 格式化输入值并生成最终的提示文本
formatted_prompt = few_shot_prompt.format(input="猫的叫声是什么?")

print(formatted_prompt)

在上述代码中,创建了一个 FewShotChatMessagePromptTemplate 对象,其中包含了一些关于猫和狗的示例。然后,它使用输入值 "猫的叫声是什么?" 格式化了最终的提示文本,并打印出来。执行后会输出:

Human: 猫的叫声是什么?

AI: 喵喵

Human: 狗的叫声是什么?

AI: 汪汪

再看下面的例子,使用了一个包含多个问题和答案的样本集合。每个样本都是一个字典,包含了一个问题和相应的答案。

实例3-1创建一个基于少量样本的对话提示模板(源码路径:codes\3\PromptTemplate02.py

本实例使用 FewShotPromptTemplate 创建了一个基于少量样本的对话提示模板,实例文件PromptTemplate02.py的具体实现代码如下所示。

from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.few_shot import FewShotPromptTemplate

# 定义 few-shot 示例
examples = [
    {
        "question": "马云的公司是什么?",
        "answer": "马云的公司是阿里巴巴。",
    },
    {
        "question": "成龙的代表作是哪部电影?",
        "answer": "成龙的代表作是《警察故事》。",
    },
    {
        "question": "李嘉诚是哪个国家的企业家?",
        "answer": "李嘉诚是中国的企业家。",
    },
]

# 定义格式化器
example_prompt = PromptTemplate(
    input_variables=["question", "answer"], template="问题:{question}\n答案:{answer}"
)

# 创建 FewShotPromptTemplate 对象
prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    suffix="问题:{input}",
    input_variables=["input"],
)

# 使用输入来格式化最终的提示文本
print(prompt.format(input="成龙的代表作是哪部电影?"))

上述代码的实现流程如下所示:

  1. 首先,创建了样本集合,包含了一些常见问题和它们的答案,例如马云的公司是什么,成龙的代表作是哪部电影等等。
  2. 接下来,创建了一个 PromptTemplate 对象,用于将每个样本格式化成一个问题和答案的字符串。然后,我们使用这个样本集合和格式化器创建了一个 FewShotPromptTemplate 对象。
  3. 最后,使用这个 FewShotPromptTemplate 对象来格式化一个特定的输入,并输出相应的问题和答案。在这个例子中,我们使用了问题“成龙的代表作是哪部电影?”作为输入,程序输出了相应的答案。执行后会输出:
问题:马云的公司是什么?
答案:马云的公司是阿里巴巴。

问题:成龙的代表作是哪部电影?
答案:成龙的代表作是《警察故事》。

问题:李嘉诚是哪个国家的企业家?
答案:李嘉诚是中国的企业家。

问题:成龙的代表作是哪部电影?

3.3.3  部分填充模板

部分提示模板(Partial prompt templates)是一种在创建提示模板时,可以传入部分变量值的技术。这种技术使得在提示模板中只需要传入部分变量值,而不是所有变量值,从而提供了更灵活的使用方式。

LangChain 支持两种部分提示模板的创建方式,一种是通过字符串值进行部分格式化,另一种是通过返回字符串值的函数进行部分格式化。

1. 使用字符串值进行部分格式化

这种方式的常见用法是当获取到某些变量值,但还没有获取到全部变量值时。假设有一个提示模板,需要两个变量 foo 和 baz。如果早先获取到了 foo 的值,但稍后才获取到 baz 的值,那么等待直到两个变量都获取到再传入模板可能会有些麻烦。相反,可以使用 foo 的值部分化提示模板,然后继续传递部分化的提示模板,只需传入剩余的变量即可。例如下面的演示代码:

from langchain.prompts import PromptTemplate

# 创建一个完整的提示模板
prompt = PromptTemplate.from_template("{foo}{bar}")
# 使用 foo 的值部分化提示模板
partial_prompt = prompt.partial(foo="foo")
# 格式化部分化的提示模板并传入剩余的变量
print(partial_prompt.format(bar="baz"))

输出结果为:

foobaz

也可以直接初始化提示模板时就传入部分化的变量,例如下面的演示代码:

prompt = PromptTemplate(
    template="{foo}{bar}", input_variables=["bar"], partial_variables={"foo": "foo"}
)
print(prompt.format(bar="baz"))

输出结果为:

foobaz

2. 使用函数进行部分格式化

另一种常见的用例是使用函数进行部分格式化。在某些情况下,可能会希望在创建提示模板时,某些变量的值是由特定的方法或函数动态获取的,而不是由用户手动输入或者固定的值。一个典型的例子是日期或时间。假设有一个提示模板,总是希望其中包含当前日期。不能直接在模板中硬编码日期,而将它与其他输入变量一起传递有点麻烦。在这种情况下,使用函数进行部分格式化非常方便,这个函数总是返回当前日期。例如下面的演示代码:

from datetime import datetime

# 获取当前日期时间的函数
def _get_datetime():
    now = datetime.now()
    return now.strftime("%m/%d/%Y, %H:%M:%S")

# 创建提示模板
prompt = PromptTemplate(
    template="Tell me a {adjective} joke about the day {date}",
    input_variables=["adjective", "date"],
)
# 使用函数对日期进行部分化
partial_prompt = prompt.partial(date=_get_datetime)
# 格式化部分化的提示模板并传入其他变量
print(partial_prompt.format(adjective="funny"))

输出结果为:

Tell me a funny joke about the day 8/27/2024, 10:45:22

在这种工作流程中,直接初始化提示模板时传入部分化的变量更加合理。例如下面的演示代码:

prompt = PromptTemplate(
    template="Tell me a {adjective} joke about the day {date}",
    input_variables=["adjective"],
    partial_variables={"date": _get_datetime},
)
print(prompt.format(adjective="funny"))

输出结果为:

Tell me a funny joke about the day 8/27/2024, 10:45:36

部分提示模板提供了一种灵活的方式,使得你可以在创建提示模板时只传入部分变量值,从而更好地适应不同的使用场景。

下面是一个使用部分提示模板(Partial prompt templates)的例子,假设我们正在为一个在线教育平台开发一个智能问答系统,该系统可以回答有关课程内容、作业帮助和学习资源的问题。我们想要创建一个提示模板,该模板能够根据用户的具体问题动态生成回答。

实例3-1:简易智能问答系统(源码路径:codes\3\PromptTemplate03.py

实例文件PromptTemplate03.py的具体实现代码如下所示。

from langchain.prompts import PromptTemplate

# 完整的提示模板
full_prompt_template = PromptTemplate.from_template(
    """您的问题: {user_question}
系统回答: {system_answer}
推荐阅读: {resource_link}"""
)

# 部分提示模板,预先填充系统回答
partial_prompt_with_system_answer = full_prompt_template.partial(
    system_answer="这个问题的答案可以在课程讲义的第三章找到。",
    resource_link="https://www.example.com/chapter3"
)

# 另一个部分提示模板,针对作业帮助的问题
partial_prompt_for_homework_help = full_prompt_template.partial(
    system_answer="关于作业的帮助,您可以查看附加的习题解答文档。",
    resource_link="https://www.example.com/homework-help"
)

# 假设我们收到了用户的以下问题
user_questions = [
    "课程讲义第三章的内容是什么?",
    "我需要一些关于作业的帮助,有解答文档吗?",
    "有没有好的学习资源推荐?"
]

# 为每个问题生成提示
for question in user_questions:
    if "课程讲义" in question:
        prompt = partial_prompt_with_system_answer.format(user_question=question)
    elif "作业帮助" in question:
        prompt = partial_prompt_for_homework_help.format(user_question=question)
    else:
        # 对于其他问题,我们可以提供一个通用的回答和资源链接
        prompt = full_prompt_template.format(
            user_question=question,
            system_answer="对不起,我们没有找到您问题的答案。",
            resource_link="https://www.example.com/resources"
        )

    print(prompt)

上述代码的实现流程如下所示:

  1. 首先,定义了一个完整的提示模板 full_prompt_template,它包含用户问题、系统回答和推荐阅读三个部分。
  2. 接着,创建了两个部分提示模板 partial_prompt_with_system_answer 和 partial_prompt_for_homework_help,它们分别针对特定类型的问题预先填充了系统回答和资源链接。
  3. 然后,定义了一个用户问题列表 user_questions,包含三种不同类型的问题。
  4. 最后,通过一个循环,根据用户问题的内容选择合适的部分提示模板,并填充剩余的信息(用户问题),然后打印输出完整的提示。执行后会输出:
您的问题: 课程讲义第三章的内容是什么?

系统回答: 这个问题的答案可以在课程讲义的第三章找到。

推荐阅读: https://www.example.com/chapter3

您的问题: 我需要一些关于作业的帮助,有解答文档吗?

系统回答: 对不起,我们没有找到您问题的答案。

推荐阅读: https://www.example.com/resources

您的问题: 有没有好的学习资源推荐?

系统回答: 对不起,我们没有找到您问题的答案。

推荐阅读: https://www.example.com/resources

在这个例子中,format 方法用于将占位符替换为实际的值。例如,{user_question} 被替换为用户的具体问题,{system_answer} 被替换为预先定义好的系统回答,{resource_link} 被替换为相关的资源链接。

如果在用户问题中包含 "课程讲义",那么使用 partial_prompt_with_system_answer 模板;如果包含 "作业帮助",则使用 partial_prompt_for_homework_help 模板。对于其他问题,使用完整的提示模板 full_prompt_template 并提供一个通用的回答和资源链接。

这种方法允许系统灵活地处理不同类型的用户问题,并提供个性化的回复,从而提高用户体验。同时,通过部分化提示模板,可以减少代码重复,并简化模板管理。

3.3.4  模板的组合(Composition)

模板的组合(Composition)是指将多个模板结合在一起,以创建更复杂、更完整的提示模板。在LangChain中,可以使用不同的方法来实现模板的组合,包括字符串模板的组合和聊天模板的组合。

在LangChain中,可以使用PipelinePromptTemplate实现模板的组合(Composition)。PipelinePromptTemplate是一个抽象提示模板,用于组合多个子模板以创建更复杂的提示结构。PipelinePromptTemplate 提供了一种方便的方式来定义模板的组合,并允许在组合的过程中传递变量。

类PipelinePromptTemplate主要用于组合多个子模板,并提供了 format() 方法来格式化最终的提示模板。这个类并没有额外的成员方法,因为它的主要功能是组合和格式化子模板。类PipelinePromptTemplate的主要成员方法如下所示:

  1. __init__():类的构造函数,用于初始化 PipelinePromptTemplate 对象。需要传入最终的提示模板(final_prompt)以及一组子模板(pipeline_prompts)。
  2. format():用于格式化 PipelinePromptTemplate。接受一组变量值作为参数,并使用这些值来填充子模板中的变量,然后返回最终的提示字符串。

1. 字符串模板的组合

在LangChain中,可以使用类PromptTemplate来创建字符串模板。这个类允许定义模板字符串,其中可以包含变量,并使用.format()方法将变量填充到模板中。在组合时,使用加号(+)操作符将多个字符串模板连接在一起来创建一个完整的提示模板。例如下面是一个使用字符串模板组合的例子,创建了一个 PipelinePromptTemplate 对象,其中包含多个子模板,并演示如何使用它们来格式化最终的提示字符串。

实例3-1:实现字符串模板的组合(源码路径:codes\3\PromptTemplate04.py

实例文件PromptTemplate04.py的具体实现代码如下所示。

from langchain.prompts import PromptTemplate
from langchain.prompts.pipeline import PipelinePromptTemplate

# 创建子模板
introduction_template = "欢迎您来到我们的网站!"
introduction_prompt = PromptTemplate.from_template(introduction_template)

question_template = "请问有什么可以帮助您的?"
question_prompt = PromptTemplate.from_template(question_template)

response_template = "感谢您的访问,祝您生活愉快!"
response_prompt = PromptTemplate.from_template(response_template)

# 创建 PipelinePromptTemplate
pipeline_prompts = [
    ("introduction", introduction_prompt),
    ("question", question_prompt),
    ("response", response_prompt)
]

final_template = "这是最终的提示模板。"
final_prompt = PromptTemplate.from_template(final_template)

pipeline_prompt = PipelinePromptTemplate(final_prompt=final_prompt, pipeline_prompts=pipeline_prompts)

# 格式化并输出组合后的模板
formatted_prompt = pipeline_prompt.format()
print(formatted_prompt)

在上述代码中,创建了三个单独的字符串模板(introduction_template、question_template 和 response_template),然后将它们作为子模板传递给 PipelinePromptTemplate。最终的模板 final_template 也是一个字符串模板。执行后会输出:

这是最终的提示模板。

2. 聊天模板的组合

在LangChain中,可以使用类ChatPromptTemplate创建聊天模板,这个类允许创建由多个消息组成的对话。ChatPromptTemplate可以将多个消息组合在一起来创建一个聊天模板,每个消息可以是系统消息、人类消息或AI消息,它们按照特定的顺序组合在一起。假设要创建一个简单的对话,其中包含一条系统消息、一条人类消息和一条AI消息,然后将它们组合在一起。下面的代码将创建一个包含系统消息、人类消息和AI消息的对话,并将它们组合在一起以创建一个聊天模板。然后,它将格式化并打印出这个聊天模板。

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain.prompts.chat import ChatPromptTemplate

# 创建系统消息、人类消息和AI消息
system_msg = SystemMessage(content="系统消息:欢迎来到聊天室!")
human_msg = HumanMessage(content="我:你好,大家!")
ai_msg = AIMessage(content="AI:大家好,我是聊天室的机器人。")

# 使用ChatPromptTemplate创建聊天模板,并将消息组合在一起
chat_template = ChatPromptTemplate(messages=[system_msg, human_msg, ai_msg])

# 格式化并打印聊天模板
print(chat_template.format_messages())

执行后会输出:

[SystemMessage(content='系统消息:欢迎来到聊天室!'), HumanMessage(content='我:你好,大家!'), AIMessage(content='AI:大家好,我是聊天室的机器人。')]

未完待续

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值