当前位置: 首页 > news >正文

LangChain大模型应用开发:提示词工程应用与实践

介绍

大家好,博主又来给大家分享知识了。今天给大家分享的内容是LangChain提示词工程应用与实践。

在如今火热的大语言模型应用领域里,LangChain可是一个相当强大且实用的工具。而其中的提示词(Prompt),更是我们与语言模型进行有效沟通的关键桥梁。简单来说,提示词就是我们输入给语言模型的文本内容,通过精心设计这些文本,我们能够引导模型输出符合我们特定需求的结果。无论是完成一项任务、解答一个问题,还是获取特定信息,都离不开它的重要作用。

更值得一提的是,LangChain为我们提供了丰富多样且灵活高效的方式来构建和管理提示词。这使得我们在不同的应用场景中,都能轻松地复用和调整提示词,以达到最佳的交互效果。

好了,话不多说,我们直接进入正题。

Prompt Template

提示词模板。语言模型以文本作为输入-这个文本通常被称为提示词(Prompt)。在开发过程中,对于提示词通常不能直接硬编码, 不利于提示词管理,而是通过提示词模板进行维护,类似开发过程中遇到的短信模板、邮件模板等等。

如上图展示了LangChain的Model I/O流程。先通过提示词模板(如 “Does {x} like {y}, and why?” 这种形式)对输入(x = "foo", y = "bar" )进行格式化处理形成具体提示词 “Does foo like bar, and why?” ,接着传递给大模型(LLM或Chat Model),最后将大模型返回的文本结果解析成结构化数据(如 {"likes": True, "reason": "Because ..."} )。

什么是提示词模板

提示词模板本质上跟平时大家使用的邮件模板、短信模板没什么区别,就是一个字符串模板,模板可以包含一组模板参数,通过模板参数值可以替换模板对应的参数。

博主笔记:建议大家在使用提示词模板的格式化中使用f-strings而不是Jinja2,因为使用不受信任的源可能存在安全风险。f-strings是一种将变量直接嵌入字符串的安全方法

一个提示词模板可以包含下面内容:

  • 发给大语言模型(LLM)的指令。
  • 一组问答示例,以提醒大模型以什么格式返回请求。
  • 发送给语言模型的问题。

创建一个提示词模板

完整代码

from langchain.prompts import PromptTemplate

# 使用PromptTemplate类的from_template方法创建一个提示模板对象
# 其中{content}和{noun}是模板变量,后续可以用实际的值进行替换
prompt_template = PromptTemplate.from_template(
    "给我讲解一下{content}中{noun}的知识。"
)

# 将模板中的变量替换为实际的值,生成一个完整的提示字符串
prompt = prompt_template.format(content="线性代数", noun="特征值和特征向量")
# 打印生成的提示字符串
print(prompt)
运行结果
给我讲解一下线性代数中特征值和特征向量的知识。

进程已结束,退出代码为 0

使用提示词模板与大模型交互

完整代码
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage

# 使用PromptTemplate类的 from_template 方法创建一个提示模板对象
# 其中{content}和{noun}是模板变量,后续可以用实际的值进行替换
prompt_template = PromptTemplate.from_template(
    "帮我讲解一下{content}中{noun}的知识。"
)

# 将模板中的变量替换为实际的值,生成一个完整的提示字符串
prompt = prompt_template.format(content="线性代数", noun="特征值和特征向量")
# 打印生成的提示字符串
print(result)

# 初始化ChatOpenAI模型,指定使用gpt-3.5-turbo模型
chat_model = ChatOpenAI(model_name="gpt-3.5-turbo")

# 构建消息列表,将生成的提示字符串封装为HumanMessage对象
messages = [HumanMessage(content=prompt)]

# 与大模型进行交互,获取模型的回复
response = chat_model.invoke(messages)

# 打印模型的回复内容
print(response.content)
运行结果
帮我讲解一下线性代数中特征值和特征向量的知识。
在线性代数中,特征值和特征向量是矩阵的两个重要性质。给定一个矩阵A,如果存在一个数λ和一个非零向量v,使得满足以下方程:

Av = λv

其中,λ为矩阵A的特征值,v为对应的特征向量。特征向量可以通过乘以矩阵A得到一个只是缩放而不改变方向的向量。特征值告诉我们特征向量在变换中的放缩比例。

在线性代数中,我们可以通过求解以下方程来找到特征值λ和特征向量v:

det(A - λI) = 0

其中,I是单位矩阵。解这个方程得到的λ就是特征值,将特征值代入方程(A - λI)v = 0,解这个方程得到的非零解v就是对应的特征向量。

特征值和特征向量在很多数学和工程问题中都有重要的应用,例如在求解微分方程、图像处理、数据降维等领域。通过研究一个矩阵的特征值和特征向量,可以更好地理解矩阵的性质和行为。

进程已结束,退出代码为 0

上面的完整代码中,我们使用了HumanMessage类,它位于langchain.schema模块中。它继承自BaseMessage类,主要用于封装用户输入的文本信息,以一种规范的方式表示用户向大语言模型提出的问题、请求或对话内容

聊天消息提示词模板

ChatPromptTemplate。聊天模型(Chat Model)以聊天消息列表作为输入,这个聊天消息列表的消息内容也可以通过提示词模板进行管理。 这些聊天消息与原始字符串不同,因为每个消息都与“角色(Role)”相关联。

例如,在OpenAlChat Completion API中,OpenAI的聊天模型,给不同的聊天消息定义了三种角色类型分别是User(用户)、Assistant(助手)、System(系统)角色:

  • User(用户角色):代表向模型发送请求或提问的用户。用户消息是输入的核心部分,用于传达具体的问题、指令或信息。
  • Assistant(助手角色):即模型自身,用于生成回复内容。模型根据接收到的系统消息和用户消息进行分析处理,然后以助手的身份给出相应的回答。
  • System(系统角色):用于设定助手的行为和角色基调,提供高层次的指令和背景信息。通过系统(System)角色的消息,可以描述模型的身份、提供背景信息、规定回答的风格或给出特定的约束条件。

创建聊天消息模板

完整代码
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_openai import ChatOpenAI

# 创建ChatPromptTemplate实例
chat_prompt_template = ChatPromptTemplate.from_messages([
    # 系统消息,设定模型的角色
    ("system", "你是一位专业智能助理提供信息和帮助,你的名字是{name}"),
    # 用户消息,包含占位符,后续会填充具体内容
    ("user", "你好,{name}"),
    # 模拟助手的回复(可作为对话历史)
    ("assistant", "您好,我是{name},请问有什么可以帮助到您的吗"),
    # 用户再次提出需求
    ("user", "请介绍一下{country}的特色美食。")
])

# 初始化 ChatOpenAI 模型
chat_model = ChatOpenAI(model_name="gpt-3.5-turbo")

# 准备输入数据,填充占位符
input_data = {
    "name": "小助手",
    "country": "中国"
}

# 格式化提示词模板,生成具体的提示消息
formatted_prompt = chat_prompt_template.format_messages(**input_data)
print(formatted_prompt)

# 与大模型进行交互,获取回复
response = chat_model.invoke(formatted_prompt)

# 输出模型的回复内容
print(response.content)
运行结果
[SystemMessage(content='你是一位专业智能助理提供信息和帮助,你的名字是小助手', additional_kwargs={}, response_metadata={}), HumanMessage(content='你好,小助手', additional_kwargs={}, response_metadata={}), AIMessage(content='您好,我是小助手,请问有什么可以帮助到您的吗', additional_kwargs={}, response_metadata={}), HumanMessage(content='请介绍一下中国的特色美食。', additional_kwargs={}, response_metadata={})]
当然可以!中国有许多美味的特色美食,以下是一些比较知名的:

1. 麻婆豆腐:一道来自四川的家常菜,以豆腐、肉末、豆瓣酱和花椒等为主要材料,口味麻辣,香气四溢。

2. 北京烤鸭:源自北京的传统名菜,以鸭子皮脆肉嫩、香味浓郁而著称,通常搭配薄饼、葱丝和甜面酱食用。

3. 小笼包:来自上海的著名点心,外皮薄如纸、内馅鲜汁丰富,以鲜肉为主,清蒸后油润可口。

4. 湖南辣椒炒肉:湖南菜系的代表菜品之一,以鲜嫩的猪肉片与香辣的湖南辣椒搭配,味道鲜美。

5. 干煸四季豆:广东菜系的经典菜品,以四季豆煸炒至微焦,搭配蒜蓉、辣椒等调味料,口感爽脆、香气诱人。

以上只是中国众多美食中的几种代表,每个地区都有独特的特色美食,欢迎您尝试更多不同口味的美味佳肴!您对哪种美食感兴趣呢?

进程已结束,退出代码为 0

通常我们不会直接使用format_messages()方法格式化提示词模板(Prompt Template)内容, 而是交给LangChain框架自动处理。下面我们演示用另一种方式来实现:

修改后完整代码
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate
from langchain_openai import ChatOpenAI

# 创建ChatPromptTemplate实例
chat_prompt_template = ChatPromptTemplate.from_messages([
    # 系统消息,设定模型的角色
    SystemMessagePromptTemplate.from_template("你是一位专业智能助理提供信息和帮助,你的名字是{name}"),
    # 用户消息,包含占位符,后续会填充具体内容
    HumanMessagePromptTemplate.from_template("你好,{name}"),
    # 模拟助手的回复(可作为对话历史)
    AIMessagePromptTemplate.from_template("您好,我是{name},请问有什么可以帮助到您的吗"),
    # 用户再次提出需求
    HumanMessagePromptTemplate.from_template("{input}"),
])

# 初始化 ChatOpenAI 模型
chat_model = ChatOpenAI(model_name="gpt-3.5-turbo")

# 构建链,将提示模板和模型连接起来
chain = chat_prompt_template | chat_model

# 与大模型进行交互,获取回复
response = chain.invoke({"name": "小助手", "input": "请介绍一下中国的特色美食。"})

# 输出模型的回复内容
print(response.content)
修改后运行结果
中国有许多美味的特色菜肴,其中一些最著名的包括:

1. 北京烤鸭:烤鸭以其酥脆的皮和嫩滑的肉闻名于世,是北京的特色美食之一。

2. 麻婆豆腐:这是一道来自四川的经典川菜,混合了豆腐、肉末和辣椒,味道麻辣鲜香。

3. 小笼包:来自上海的小笼包是一种以肉馅为馅料,包裹在薄面皮里面蒸制而成的一种传统中式面食。

4. 麻辣火锅:火锅是一种流行的中国美食,麻辣火锅是一种以辣椒和花椒为主料的火锅,味道浓郁,香气四溢。

5. 干煸四季豆:这是一道来自川菜的经典菜肴,以四季豆为主要原料,炒制后香脆可口。

以上是一些中国的特色美食,您可以尝试其中一些来体验中国独特的美食文化。

进程已结束,退出代码为 0

MessagesPlaceholder

直译过来叫消息占位符。这个提示模板负责在特定位置添加消息列表。在上面的ChatPromptTemplate中,我们看到了自动格式化消息,每条消息都是一个字符串。但是,如果我们希望用户传入一个消息列表并将其插入到特定位置, 该怎么办?这时就需要用到MessagesPlaceholder的方式。

完整代码
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate, HumanMessagePromptTemplate
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, AIMessage

# 初始化 ChatOpenAI 模型
chat_model = ChatOpenAI(model_name="gpt-3.5-turbo")

# 创建ChatPromptTemplate实例
chat_prompt_template = ChatPromptTemplate.from_messages([
    # 系统消息,设定模型的角色
    SystemMessagePromptTemplate.from_template("你是一位专业智能助理提供信息和帮助,你的名字是{name}"),
    # 使用MessagesPlaceholder插入消息记录
    MessagesPlaceholder(variable_name="chat_history"),
    # 用户再次提出需求
    HumanMessagePromptTemplate.from_template("{input}"),
])

# 设置助手名称
assistant_name = "小助手"

# 模拟对话历史
chat_history = [
    HumanMessage(content=f"你好,{assistant_name}"),
    AIMessage(content=f"您好,我是{assistant_name},请问有什么可以帮助到您的吗")
]

# LangChain链式调用,构建链,将提示模板和模型连接起来
chain = chat_prompt_template | chat_model

# 与模型交互获取回复
response = chain.invoke({"name": assistant_name, "chat_history": chat_history, "input": "请介绍一下中国的特色美食。"})

# 输出模型回复
print(response.content)
运行结果
中国有许多地方特色的美食,以下是一些比较典型的中国特色美食:

1. 北京烤鸭:北京烤鸭是中国传统名菜之一,以其酥脆的皮和鲜嫩的肉闻名。通常搭配薄饼、葱丝、甜面酱等食用。

2. 川菜:川菜以其麻辣鲜香而著名,典型菜品包括宫保鸡丁、水煮鱼等。

3. 粤菜:粤菜以清鲜爽口、健康营养著称,例如广东的著名菜品有糖醋排骨、白切鸡等。

4. 湖南菜:湖南菜以其鲜辣香滑而著称,典型菜品包括东坡肉、剁椒鱼头等。

5. 鲁菜:鲁菜是山东菜系,以其浓郁的味道和大菜品块闻名,如红烧肉、煎饼、鱼香肉丝等。

这些都是中国地方特色的美食,每种菜系都有其独特的风味和文化背景。欢迎您尝试品尝这些美食!如果您对某种菜系或具体菜品有更感兴趣的话,我也可以为您提供更详细的信息。

进程已结束,退出代码为 0

从上面的运行结果我们看到,在设计聊天机器人或者基于聊天的应用程序时,我们可能需要在对话流程里动态添加多条消息,比如历史对话记录等。MessagesPlaceholder就可以帮助我们在提示模板中预留一个位置,后续再将这些动态消息填充进去。 通过使用MessagesPlaceholder,我们可以灵活地管理和插入动态消息,使聊天提示模板更加灵活和强大。

少样本提示模板

FewShotPromptTemplate。在LangChain中,FewShotPromptTemplate(少样本提示模板)是一种用于构建提示的强大工具,能有效引导语言模型生成更精准、符合特定格式或任务要求的输出。

提示词中包含交互样本的作用是为了帮助模型更好地理解用户的意图,从而更好地回答问题或执行任务。少样本提示模板是指使用一组少量的示例来指导模型处理新的输入。这些示例可以用来训练模型,以便模型可以更好地理解和回答类似的问题。

使用示例集

LangChain里,示例集(Examples)是少样本学习(Few - shot learning)中至关重要的元素,主要用于辅助大语言模型更好地理解任务需求并生成更精准的输出。

示例集是一组包含输入和对应输出的示例组合。在向大语言模型下达任务时,仅仅给出抽象的任务描述,模型可能难以准确把握任务意图和输出格式。而通过提供示例集,模型能够从这些具体的输入 - 输出对中学习任务的模式、规则以及期望的输出样式,进而更有效地完成任务。

创建示例集

我们定义一个examples示例数组,里面包含一组问答样例。

演示代码
# 定义示例集,包含多个问题及对应答案的详细推理过程
examples = [
    {
        "question": "《哈利·波特》和《指环王》的原著作者都是女性吗?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:《哈利·波特》的原著作者是谁?
            中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
            跟进:J.K.罗琳是男性还是女性?
            中间答案:女性。
            跟进:《指环王》的原著作者是谁?
            中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
            跟进:J.R.R.托尔金是男性还是女性?
            中间答案:男性。
            所以最终答案是:不是
            """
    },
    {
        "question": "李白和杜甫谁出生得更早?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:李白出生于哪一年?
            中间答案:李白出生于701年。
            跟进:杜甫出生于哪一年?
            中间答案:杜甫出生于712年。
            所以最终答案是:李白
            """
    },
    {
        "question": "苹果公司和微软公司,哪个先成立?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:苹果公司是哪一年成立的?
            中间答案:苹果公司成立于1976年。
            跟进:微软公司是哪一年成立的?
            中间答案:微软公司成立于1975年。
            所以最终答案是:微软公司
            """
    },
    {
        "question": "埃菲尔铁塔和自由女神像哪个建造时间更晚?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:埃菲尔铁塔是什么时候建造完成的?
            中间答案:埃菲尔铁塔于1889年建造完成。
            跟进:自由女神像是何时建成的?
            中间答案:自由女神像于1886年建成。
            所以最终答案是:埃菲尔铁塔
            """
    }
]

格式化示例集内容

演示代码
# 定义示例提示词模板,指定输入变量和模板格式
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\\n{answer}")

# 格式化并打印示例集中第一个示例的内容
print(example_prompt.format(**examples[0]))

将示例集和格式化程序提供给FewShotPromptTemplate

演示代码
# 创建少样本提示模板,结合示例集、示例提示词模板及后缀等信息
prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    suffix="问题:{input}",
    input_variables=["input"]
)

# 格式化少样本提示模板并打印,传入新的问题作为输入
print(prompt.format(input="牛顿和爱因斯坦谁提出重要理论的时间更早?"))

使用示例集完整代码

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

# 定义示例集,包含多个问题及对应答案的详细推理过程
examples = [
    {
        "question": "《哈利·波特》和《指环王》的原著作者都是女性吗?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:《哈利·波特》的原著作者是谁?
            中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
            跟进:J.K.罗琳是男性还是女性?
            中间答案:女性。
            跟进:《指环王》的原著作者是谁?
            中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
            跟进:J.R.R.托尔金是男性还是女性?
            中间答案:男性。
            所以最终答案是:不是
            """
    },
    {
        "question": "李白和杜甫谁出生得更早?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:李白出生于哪一年?
            中间答案:李白出生于701年。
            跟进:杜甫出生于哪一年?
            中间答案:杜甫出生于712年。
            所以最终答案是:李白
            """
    },
    {
        "question": "苹果公司和微软公司,哪个先成立?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:苹果公司是哪一年成立的?
            中间答案:苹果公司成立于1976年。
            跟进:微软公司是哪一年成立的?
            中间答案:微软公司成立于1975年。
            所以最终答案是:微软公司
            """
    },
    {
        "question": "埃菲尔铁塔和自由女神像哪个建造时间更晚?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:埃菲尔铁塔是什么时候建造完成的?
            中间答案:埃菲尔铁塔于1889年建造完成。
            跟进:自由女神像是何时建成的?
            中间答案:自由女神像于1886年建成。
            所以最终答案是:埃菲尔铁塔
            """
    }
]

# 定义示例提示词模板,指定输入变量和模板格式
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\\n{answer}")

# 格式化并打印示例集中第一个示例的内容
print(example_prompt.format(**examples[0]))

# 创建少样本提示模板,结合示例集、示例提示词模板及后缀等信息
prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    suffix="问题:{input}",
    input_variables=["input"]
)

# 格式化少样本提示模板并打印,传入新的问题作为输入
print(prompt.format(input="牛顿和爱因斯坦谁提出重要理论的时间更早?"))

使用示例集运行结果

问题:《哈利·波特》和《指环王》的原著作者都是女性吗?\n
这里需要跟进问题吗:是的。
跟进:《哈利·波特》的原著作者是谁?
中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
跟进:J.K.罗琳是男性还是女性?
中间答案:女性。
跟进:《指环王》的原著作者是谁?
中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
跟进:J.R.R.托尔金是男性还是女性?
中间答案:男性。
所以最终答案是:不是

问题:《哈利·波特》和《指环王》的原著作者都是女性吗?\n
这里需要跟进问题吗:是的。
跟进:《哈利·波特》的原著作者是谁?
中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
跟进:J.K.罗琳是男性还是女性?
中间答案:女性。
跟进:《指环王》的原著作者是谁?
中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
跟进:J.R.R.托尔金是男性还是女性?
中间答案:男性。
所以最终答案是:不是


问题:李白和杜甫谁出生得更早?\n
这里需要跟进问题吗:是的。
跟进:李白出生于哪一年?
中间答案:李白出生于701年。
跟进:杜甫出生于哪一年?
中间答案:杜甫出生于712年。
所以最终答案是:李白


问题:苹果公司和微软公司,哪个先成立?\n
这里需要跟进问题吗:是的。
跟进:苹果公司是哪一年成立的?
中间答案:苹果公司成立于1976年。
跟进:微软公司是哪一年成立的?
中间答案:微软公司成立于1975年。
所以最终答案是:微软公司


问题:埃菲尔铁塔和自由女神像哪个建造时间更晚?\n
这里需要跟进问题吗:是的。
跟进:埃菲尔铁塔是什么时候建造完成的?
中间答案:埃菲尔铁塔于1889年建造完成。
跟进:自由女神像是何时建成的?
中间答案:自由女神像于1886年建成。
所以最终答案是:埃菲尔铁塔


问题: 牛顿和爱因斯坦谁提出重要理论的时间更早?

进程已结束,退出代码为 0

使用ExampleSelector

将示例提供给ExampleSelector(示例选择器)

这里重用前一部分中的示例集和提示词模板(Prompt Template)。但是,我们不会将示例直接提供给 FewShotPromptTemplate对象并把全部示例插入到提示词中,而是将它们提供给一个ExampleSelector对象,插入部分示例。

这里我们使用SemanticSimilarityExampleSelector类。该类根据与输入的相似性选择小样本示例。它使用嵌入模型计算输入和小样本示例之间的相似性,然后使用向量数据库执行相似搜索,获取跟输入相似的示例。

  • 提示:这里涉及向量计算、向量数据库,在AI领域这两个主要用于数据相似度搜索。例如:查询相似文章内容、 相似的图片、视频等等,这里先简单了解下就行。

演示代码

from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import LengthBasedExampleSelector
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

# 定义示例集,包含多个问题及对应答案的详细推理过程
examples = [
    {
        "question": "《哈利·波特》和《指环王》的原著作者都是女性吗?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:《哈利·波特》的原著作者是谁?
            中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
            跟进:J.K.罗琳是男性还是女性?
            中间答案:女性。
            跟进:《指环王》的原著作者是谁?
            中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
            跟进:J.R.R.托尔金是男性还是女性?
            中间答案:男性。
            所以最终答案是:不是
            """
    },
    {
        "question": "李白和杜甫谁出生得更早?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:李白出生于哪一年?
            中间答案:李白出生于701年。
            跟进:杜甫出生于哪一年?
            中间答案:杜甫出生于712年。
            所以最终答案是:李白
            """
    },
    {
        "question": "苹果公司和微软公司,哪个先成立?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:苹果公司是哪一年成立的?
            中间答案:苹果公司成立于1976年。
            跟进:微软公司是哪一年成立的?
            中间答案:微软公司成立于1975年。
            所以最终答案是:微软公司
            """
    },
    {
        "question": "埃菲尔铁塔和自由女神像哪个建造时间更晚?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:埃菲尔铁塔是什么时候建造完成的?
            中间答案:埃菲尔铁塔于1889年建造完成。
            跟进:自由女神像是何时建成的?
            中间答案:自由女神像于1886年建成。
            所以最终答案是:埃菲尔铁塔
            """
    }
]

# 定义示例提示词模板,指定输入变量和模板格式
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\n{answer}")

# 创建基于长度的示例选择器,根据输入长度选择合适数量的示例
example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=200  # 可根据实际情况调整最大长度
)

将示例选择器提供给FewShotPromptTemplate

最后,创建一个FewShotPromptTemplate对象。根据前面的example_selector示例选择器,选择一个跟问题相似的例子。

代码演示

from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import LengthBasedExampleSelector
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

# 定义示例集,包含多个问题及对应答案的详细推理过程
examples = [
    {
        "question": "《哈利·波特》和《指环王》的原著作者都是女性吗?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:《哈利·波特》的原著作者是谁?
            中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
            跟进:J.K.罗琳是男性还是女性?
            中间答案:女性。
            跟进:《指环王》的原著作者是谁?
            中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
            跟进:J.R.R.托尔金是男性还是女性?
            中间答案:男性。
            所以最终答案是:不是
            """
    },
    {
        "question": "李白和杜甫谁出生得更早?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:李白出生于哪一年?
            中间答案:李白出生于701年。
            跟进:杜甫出生于哪一年?
            中间答案:杜甫出生于712年。
            所以最终答案是:李白
            """
    },
    {
        "question": "苹果公司和微软公司,哪个先成立?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:苹果公司是哪一年成立的?
            中间答案:苹果公司成立于1976年。
            跟进:微软公司是哪一年成立的?
            中间答案:微软公司成立于1975年。
            所以最终答案是:微软公司
            """
    },
    {
        "question": "埃菲尔铁塔和自由女神像哪个建造时间更晚?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:埃菲尔铁塔是什么时候建造完成的?
            中间答案:埃菲尔铁塔于1889年建造完成。
            跟进:自由女神像是何时建成的?
            中间答案:自由女神像于1886年建成。
            所以最终答案是:埃菲尔铁塔
            """
    }
]

# 定义示例提示词模板,指定输入变量和模板格式
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\n{answer}")

# 创建基于长度的示例选择器,根据输入长度选择合适数量的示例
example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=200  # 可根据实际情况调整最大长度
)

# 创建少样本提示模板,结合示例选择器、示例提示词模板及后缀等信息
prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    suffix="问题:{input}",
    input_variables=["input"]
)

使用示例提示词模板与大模型交互

通过将示例集提供给示例选择器,然后再将示例选择器提供给少样本提示模板,最后我们将最终提示词模板于大模型进行交互。

完整代码

from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import LengthBasedExampleSelector
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

# 定义示例集,包含多个问题及对应答案的详细推理过程
examples = [
    {
        "question": "《哈利·波特》和《指环王》的原著作者都是女性吗?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:《哈利·波特》的原著作者是谁?
            中间答案:《哈利·波特》的原著作者是J.K.罗琳(J.K. Rowling)。
            跟进:J.K.罗琳是男性还是女性?
            中间答案:女性。
            跟进:《指环王》的原著作者是谁?
            中间答案:《指环王》的原著作者是J.R.R.托尔金(J.R.R. Tolkien)。
            跟进:J.R.R.托尔金是男性还是女性?
            中间答案:男性。
            所以最终答案是:不是
            """
    },
    {
        "question": "李白和杜甫谁出生得更早?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:李白出生于哪一年?
            中间答案:李白出生于701年。
            跟进:杜甫出生于哪一年?
            中间答案:杜甫出生于712年。
            所以最终答案是:李白
            """
    },
    {
        "question": "苹果公司和微软公司,哪个先成立?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:苹果公司是哪一年成立的?
            中间答案:苹果公司成立于1976年。
            跟进:微软公司是哪一年成立的?
            中间答案:微软公司成立于1975年。
            所以最终答案是:微软公司
            """
    },
    {
        "question": "埃菲尔铁塔和自由女神像哪个建造时间更晚?",
        "answer":
            """
            这里需要跟进问题吗:是的。
            跟进:埃菲尔铁塔是什么时候建造完成的?
            中间答案:埃菲尔铁塔于1889年建造完成。
            跟进:自由女神像是何时建成的?
            中间答案:自由女神像于1886年建成。
            所以最终答案是:埃菲尔铁塔
            """
    }
]

# 定义示例提示词模板,指定输入变量和模板格式
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="问题:{question}\n{answer}")

# 创建基于长度的示例选择器,根据输入长度选择合适数量的示例
example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=200  # 可根据实际情况调整最大长度
)

# 创建少样本提示模板,结合示例选择器、示例提示词模板及后缀等信息
prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    suffix="问题:{input}",
    input_variables=["input"]
)

# 初始化 ChatOpenAI 语言模型
chat_model = ChatOpenAI(model_name="gpt-3.5-turbo")

# 该解析器用于将模型的输出结果解析为字符串类型
output_parser = StrOutputParser()

# 使用管道操作符|将提示模板、聊天模型和输出解析器连接起来,形成一个处理链
chain = prompt | chat_model | output_parser

# 用户新的问题
new_question = "牛顿和爱因斯坦谁提出重要理论的时间更早?"

# 与大模型交互,获取回答
response = chain.invoke({"input": new_question})

print(f"问题: {new_question}")
print(f"回答: {response}")

运行结果

问题: 牛顿和爱因斯坦谁提出重要理论的时间更早?
回答: 这里需要跟进问题吗:是的。
跟进:牛顿是什么时候提出重要理论的?
中间答案:牛顿在17世纪提出了万有引力定律和运动定律等重要理论。
跟进:爱因斯坦是什么时候提出重要理论的?
中间答案:爱因斯坦在20世纪提出了相对论等重要理论。
所以最终答案是:牛顿的理论提出时间更早。

进程已结束,退出代码为 0

结束

好了,以上就是本次分享的全部内容了。不知道大家是否理解并掌握今天的知识,我希望大家都能充分理解并熟练掌握今天所分享的知识要点,毕竟这些知识在实际应用中有着相当重要的作用。

Prompt提示词在LangChain中是连接用户和语言模型的桥梁,对于实现准确、高效、定制化的语言模型应用起着不可或缺的作用。

Prompt提示词本质上是一段精心构造的文本,它被提供给语言模型(如GPT系列等),以明确告知模型需要完成的任务。例如,当你希望模型进行文本摘要时,Prompt可能是 “请对以下文章进行简洁的摘要,突出关键信息”,然后附上具体的文章内容。

最后,博主还是那句话:请大家多去大胆的尝试和使用,成功总是在不断的失败中试验出来的,敢于尝试就已经成功了一半。那么本次分享就到这了。如果大家对博主分享的内容感兴趣或有帮助,请点赞和关注。大家的点赞和关注是博主持续分享的动力🤭,博主也希望让更多的人学习到新的知识。

相关文章:

  • PHP 面向对象编程
  • win32汇编环境,对话框中使用月历控件示例一
  • vLLM专题(三)-快速开始
  • 二叉搜索树的实现(C++)
  • SSL 连接
  • 网剧《一念逍遥》正式启动筹备
  • 1. 对比 LVS 负载均衡群集的 NAT 模式和 DR 模式,比较其各自的优势 。2. 基于 openEuler 构建 LVS-DR 群集。
  • DeepSeek 教我 C++ (3) : Optional / Variant 使用的应该注意的细节
  • Java 中的 HashSet 和 HashMap 有什么区别?
  • [操作系统] 基础IO:系统文件I/O
  • 基于springboot的留学服务管理平台的设计与开发(源码+文档)
  • 【deepseek与chatGPT辩论】辩论题: “人工智能是否应当具备自主决策能力?”
  • BGP分解实验·18——BGP选路原则之权重
  • 网络安全:挑战、技术与未来发展
  • Amazon S3导入Salesforce对象的ETL设计和导入状态日志管理
  • 领域驱动设计(DDD)是什么?——从理论到实践的全方位解析
  • Java gc完整认识和常见问题
  • 【Bluedroid】 BLE连接源码分析(一)
  • 每日OJ_牛客_剪花布条(string内置函数)
  • es6箭头函数和普通函数的区别
  • 4台肺癌手术,2名“90后”患者,这届年轻人的肺怎么了?
  • “80后”德州市接待事务中心副主任刘巍“拟进一步使用”
  • 宝通科技:与宇树合作已签约,四足机器人在工业场景落地是重点商业化项目
  • 北京航空航天大学首个海外创新研究院落户巴西
  • 董军同法国国防部长举行会谈
  • “降息潮”延续,多家民营银行下调存款利率