一、Models IO 组成及其说明
与语言模型的交互,比如在线GPT系列,或各种离线模型 任何语言模型应用程序的核心元素都是XXX模型。LangChain 提供了与任何语言模型交互的构建块。
从案例理解prompt,下面是一个内容,占位字符串为 foo 跟 bar,在python中可以根据format,将需要传入的内容代入
我最喜欢的运动是{args1},平时最喜欢去{args2}
"""
template = template.format(args1='foo',args2='bar')
我最喜欢的运动是foo,平时最喜欢去bar
langchain,提供了prompt工程,可以通过规定风格,将提示内容代入到各类模型,以便告知模型,你的想法或执行内容;
对于LLM的输出,我们也能进行解析,比如,要求输出为json格式,等等格式要求
其主要交互组件如下图
注意 内容所出现的代码,我都忽略了key的配置,你们可以自己加
os.environ["OPENAI_API_KEY"] = ''
二、Prompt 提示工程
语言模型的提示是用户提供的一组指令或输入,用于指导模型的响应,帮助模型理解上下文并生成相关且连贯的基于语言的输出,例如回答问题、完成句子或参与某项活动。对话。 LangChain 提供了几个类和函数来帮助构建和使用提示。
1、提示模板:参数化模型输入
2、示例选择器:动态选择要包含在提示中的示例
1、关于模板的使用 (1)基础模板 PromptTemplate (1.1)使用预设值实例化
from langchain.prompts.prompt import PromptTemplate
prompt_template = PromptTemplate(input_variables=["content"], template="告诉我一个笑话关于 {content}")
prompt = prompt_template.format(content="兔子")
print(prompt_template)
print(type(prompt_template))
print(prompt)
print(type(prompt))
--------打印结果----------
input_variables=['content'] template='告诉我一个笑话关于 {content}'
<class 'langchain.prompts.prompt.PromptTemplate'>
告诉我一个笑话关于 兔子
<class 'str'>
(1.2)使用from_template实例化
from langchain.prompts.prompt import PromptTemplate
prompt_template = PromptTemplate.from_template(
template="告诉我一个笑话 {adjective} 关于 {content}."
)
prompt = prompt_template.format(adjective="funny", content="chickens")
print(prompt_template)
print(type(prompt_template))
print(prompt)
print(type(prompt))
--------打印结果----------
input_variables=['adjective', 'content'] template='告诉我一个笑话 {adjective} 关于 {content}.'
<class 'langchain.prompts.prompt.PromptTemplate'>
告诉我一个笑话 funny 关于 chickens.
<class 'str'>
from langchain import PromptTemplate
from langchain.llms import OpenAI
invalid_prompt = PromptTemplate(
input_variables=["adjective"],
template="Tell me a {adjective} joke about cat. 中文回复我"
)
# llm = ChatOpenAI()
llm = OpenAI()
# 定义一个函数来生成回答
def generate_joke(adjective, content):
prompt = invalid_prompt.format(adjective=adjective)
response = llm(prompt)
print(response)
# return response.choices[0].text.strip()
# 调用函数生成一个笑话
joke = generate_joke("funny", "cats")
print(joke)
"""
这只猫真有趣:它把自己看作是一只狗!
"""
(1.4)源码
从源码层来说,都是源自这边,并且函数也说明了,是所有模板的基础,建议去看看源码 这里不过多说明
从源码可以看继承于StringPromptTemplate 字符串模板
而它又继承于 BasePromptTemplate,拥有如下功能函数
往往有时候,提供的基础模板不够我们使用场景,就需要我们自己创建自定义模板
(2) 自定义模板
举例使用场景:
用于某些业务实现 在自定义模板中,我们可以实现很多功能,比如加上日志记录 要创建自定义字符串提示模板,有两个要求:
1、它有一个 input_variables 属性,该属性公开提示模板所需的输入变量。 2、定义了一个 format 方法,该方法接受与预期的 input_variables 相对应的关键字参数并返回格式化的提示。
通过如下案例说明:
第一步,创建一个获取函数源码的函数
import inspect
def get_source_code(function_name):
return inspect.getsource(function_name)
第二步,构建自定义提示模板
from langchain.prompts import StringPromptTemplate
from pydantic import BaseModel, validator
PROMPT = """
给定函数名称和源代码,生成该函数的中文解释。.
函数名称: {function_name}
源代码:
{source_code}
解释:
"""
class CustomPromptTemplate(StringPromptTemplate, BaseModel):
""" 自定义提示模板,
将函数名称作为输入,
并格式化提示模板以提供函数的源代码。
"""
@validator("input_variables")
def validate_input_variables(cls, v):
"""验证输入变量是否正确。"""
if len(v) != 1 or "function_name" not in v:
raise ValueError("function_name must be the only input_variable.")
return v
def format(self, **kwargs) -> str:
# 获取源码
source_code = get_source_code(kwargs["function_name"])
# 生成要发送到语言模型的提示
prompt = PROMPT.format(
function_name=kwargs["function_name"].__name__, source_code=source_code
)
return prompt
def _prompt_type(self):
return "function-explainer"
第四步,使用它
fn_explainer = CustomPromptTemplate(input_variables=["function_name"])
prompt = fn_explainer.format(function_name=get_source_code)
print(prompt)
(3)基础可选模板
可以实现从一组示例或示例选择器对象构建少量提示模板。 在实现这个前,先补充一下知识
Few-shot和zero-shot是机器学习中常用的术语,用于描述模型在处理新任务或新类别时的能力。
Few-shot(少样本学习):Few-shot学习是指在面对只有很少样本的新任务或新类别时,模型能够通过利用有限的样本进行学习和泛化。这意味着模型可以从少量的训练样本中快速学习,并在面对新任务时进行适应。
Zero-shot(零样本学习):Zero-shot学习是指在面对完全没有见过的新任务或新类别时,模型能够进行推理和泛化。这意味着模型可以在没有任何训练样本的情况下,通过利用先验知识或外部信息来进行预测和分类。
这些概念在自然语言处理、计算机视觉和强化学习等领域中被广泛应用,旨在提高模型的泛化能力和适应性,使其能够处理新领域、新任务或新类别的数据。
为此langchain也提供了,few-shot模板操作
from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
examples = [
{
"question": "你是谁?",
"answer":
"""
我是wenwenc9
"""
},
{
"question": "爸爸叫什么",
"answer":
"""
叫爷爷
"""
},
{
"question": "朱自清是谁",
"answer":
"""
朱自清是文学家
"""
}
]
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="Question: {question}\n{answer}")
prompt = FewShotPromptTemplate(
examples=examples, # 少量示例
example_prompt=example_prompt, # 用户格式化单个示例
suffix="Question: {input}", # 前缀,也有后缀prefix
input_variables=["input"]
)
example_selector = SemanticSimilarityExampleSelector.from_examples(
# 可供选择的示例模板
examples,
# 用于生成用于测量语义相似性的嵌入的嵌入类。
OpenAIEmbeddings(),
# 向量数据库
Chroma,
# 这是要生成的实例数目
k=1
)
构建问题,基于用户问题,选择合适的提示模板
# 创建一个问题
question = "朱自清"
# 根据向量引擎从中选择一个符合
selected_examples = example_selector.select_examples({"question": question})
print(selected_examples)
执行输出结果
[{'answer': '\n 朱自清是文学家\n ', 'question': '朱自清是谁'}]
1
(4)聊天模板 ChatPromptTemplate
from_messages from_template 在langchain中,ChatPromptTemplate是一个模版方法,它具有两个功能:from_messages和from_template。
from_messages:这个功能用于从一系列对话消息中创建聊天模版。您可以提供多个消息作为输入,并将它们转换为聊天模版,以便用于后续的对话生成。
from_template:这个功能用于从现有的聊天模版中创建新的聊天模版。您可以基于现有的模版进行修改或扩展,以便生成更多的对话内容。
from_messages用于从消息创建模版,而from_template用于基于现有模版创建新的模版。
(4.1) 二元数组方式
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
template = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的助手. 你的名字是 {name}."),
("human", "你好,你最近过的好嘛?"),
("ai", "最近过的不错"),
("human", "{user_input}"),
])
messages = template.format_messages(
name="小爱同学",
user_input="你的名字是什么?"
)
# 实例化AI对象
llm = ChatOpenAI()
# 响应
res = llm(messages)
print(res)
content='我的名字是小爱同学。有什么我可以帮助你的吗?'
(4.2)BaseMessage 或者 MessagePromptTemplate
from langchain.callbacks import get_openai_callback
from langchain.prompts import ChatPromptTemplate
from langchain.prompts.chat import SystemMessage, HumanMessagePromptTemplate, HumanMessage
from langchain.chat_models import ChatOpenAI
template = ChatPromptTemplate.from_messages(
[
SystemMessage(
content=(
"你是一个乐于助人的助手,可以将用户的文本重新写入"
"听起来更乐观"
"用中文回复我"
)
),
# HumanMessagePromptTemplate.from_template("{text}"), # 这里对应本小节前面,所示的from_template可以从已有模板进行修改
HumanMessage(
content=(
"{text}"
)
),
]
)
llm = ChatOpenAI()
# 使用上下文管理器获取 token 使用情况
with get_openai_callback() as cb:
res = llm(template.format_messages(text='我很难过'))
print(res)
# 获取 token 使用总数
total_tokens = cb.total_tokens
print(f"Total tokens used: {total_tokens}")
content='亲爱的用户,你的文本让我感到有些沮丧。但是,无论遇到什么困难,我们都应该保持积极乐观的态度。相信自己,相信明天会更好。让我们一起努力,面对挑战,充满希望地前进吧!加油!'
Total tokens used: 155
(5)聊天Few-shot模板
关于few-shot的含义本文基础可选模板已经提到过
前面的few-shot 并没有带上chat二字
创建多个提示案例
from langchain.prompts import (
FewShotChatMessagePromptTemplate,
ChatPromptTemplate,
)
# 生成具体回复
examples = [
{"input": "2+2", "output": "4"},
{"input": "2+3", "output": "5"},
]
example_prompt = ChatPromptTemplate.from_messages(
[ ("human", "{input}"), ("ai", "{output}"), ]
)
few_shot_prompt = FewShotChatMessagePromptTemplate(
example_prompt=example_prompt,
examples=examples,
)
final_prompt = ChatPromptTemplate.from_messages(
[
("system", "You are a wondrous wizard of math."),
few_shot_prompt,
("human", "{input}"),
]
)
查看一下final_prompt 内容,可以看到下图,由3个消息提示模板
SystemMessagePromptTemplateFewShotChatMessagePromptTemplateHumanMessagePromptTemplate
展开FewShotChatMessagePromptTemplate ,可以看到是通过2,实例出2个ChatPromptTemplate
进行使用
方式一:
from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
# 创建LLM模型
llm = ChatOpenAI()
# 创建执行链
chain = LLMChain(
llm=llm,
prompt=final_prompt
)
res = chain.invoke({"input": "2+2 等于多少"})
res2 = chain.invoke({"input": "2+6 等于多少"})
print(res)
print(res2)
方式二:
from langchain.chat_models import ChatOpenAI
# 创建执行链
chain = final_prompt | ChatOpenAI()
res = chain.invoke({"input": "2+2 等于多少"})
res2 = chain.invoke({"input": "2+2 等于多少"})
print(res)
{'input': '2+2 等于多少', 'text': '2+2等于4。'}
{'input': '2+6 等于多少', 'text': '2 + 6 等于 8。'}
Model I/O 的template以及批量运用
这段代码演示了如何使用一个预定义的文案模板,结合OpenAI的GPT-3模型,为不同的水果和它们的价格生成吸引人的描述。以下是对代码的逐行注释和解释model_io_for_loop.py:
from langchain.llms import OpenAI
# 导入Langchain库中的PromptTemplate模块,用于创建和管理提示模板
from langchain.prompts import PromptTemplate
# 导入Langchain库中的LLMChain模块,它允许构建基于大型语言模型的处理链
from langchain.chains import LLMChain
# 导入dotenv库,用于从.env文件加载环境变量,这对于管理敏感数据如API密钥很有用
from dotenv import load_dotenv
# 调用load_dotenv函数来加载.env文件中的环境变量
load_dotenv()
# 定义一个文案模板,用于生成关于水果的描述。
# {price} 和 {fruit_name} 是占位符,稍后将被具体的价格和水果名称替换。
template = """您是一位专业的水果店文案撰写员。\n
对于售价为 {price} 元的 {fruit_name} ,您能提供一个吸引人的简短描述吗?
"""
# 使用PromptTemplate类的from_template方法创建一个基于上述模板的prompt对象。
# 这个对象可以用来格式化具体的水果名称和价格。
prompt = PromptTemplate.from_template(template)
print(prompt)
# 使用OpenAI类创建一个名为llm的实例。
# 这个实例配置了用于生成文本的模型参数:"text-davinci-003"是一个高级的GPT-3模型。
# temperature设置为0.5,用于控制生成文本的随机性和创造性。
# max_tokens设置为60,用于限制生成文本的最大长度。
llm = OpenAI(
model="text-davinci-003",
temperature=0.5,
max_tokens=60
)
# 定义两个列表:fruits包含不同的水果名称,prices包含相应的价格。
fruits = ["葡萄", "草莓", "樱桃"]
prices = ["10", "20", "30"]
# 使用zip函数将fruits和prices中的元素配对,并在每一对元素上迭代。
for fruit, price in zip(fruits, prices):
# 使用format方法和prompt模板生成具体的输入文本。
# 这里将占位符替换为具体的水果名称和价格。
input_prompt = prompt.format(price=price, fruit_name=fruit)
# 使用llm实例生成文案描述。
response = llm(input_prompt)
# 打印生成的文案描述。
print(response)
这里LLM也可以替换为别的,比如HuggingFaceHub
# 导入LangChain中的OpenAI模型接口
from langchain import HuggingFaceHub
# 创建模型实例
llm= HuggingFaceHub(repo_id="google/flan-t5-large")
运行结果
input_variables=['fruit_name', 'price'] template='您是一位专业的水果店文案撰写员。\n\n对于售价为 {price} 元的 {fruit_name} ,您能提供一个吸引人的简短描述吗?\n'
「精选葡萄,香甜多汁,仅 10 元,让你尝遍天下美味!」
草莓:甜美多汁,满口芬芳,令人回味无穷,20元即可
精选樱桃,甜蜜爽口,香甜可口,仅售30元!