LangChain核心构建模块:链(Chain)详解
LangChain核心构建模块:链(Chain)详解
链(Chain)是LangChain中一个非常核心的构建模块,它能够将大语言模型与提示词结合在一起,并支持多个构建模块的组合操作。本文将详细介绍三种不同类型的链:LLMChain、Sequential Chains和Router Chain,并通过代码示例展示它们的使用方法。
LLMChain
这是一个简单但非常强大的链,后面介绍的许多链都能够支持。
from langchain.chat_models import ChatOpenAI # 导入OpenAI模型,LLM
from langchain.prompts import ChatPromptTemplate # 提示词相关
from langchain.chains import LLMChain
首先初始化我们的语言模型。我们先用一个比较高的temperature值初始化ChatOpenAI。
llm = ChatOpenAI(temperature=0.9)
通过初始化提示词模板,接收名为product的变量。要求LLM根据产品名称,为制作该产品的公司取一个最佳的名字。
prompt = ChatPromptTemplate.from_template(
"What is the best name to describe a company that makes {product}? "
)
最后,我们把二者结合成为一条链,就是LLM和提示词模板的结合,将提示词模版和LLM按顺序连接起来。
chain = LLMChain(llm = llm, prompt = prompt)
如果我们有一个名为“双人床床单套装”的产品,我们可以通过使用“chain.run”将它传入链,并运行链。
product = "Queen Size Sheet Set"
chain.run(product)
它会在后台格式化提示词,并将格式化后的提示词传给LLM。可以看到已经起了一个名字。LLM是最基本的链类型,以后会经常用到。
Sequential Chains(顺序链)
顺序链是另一种类型的链。将多个链组合在一起,其中一个链的输出就是下个链的输入。
有两种类型的顺序链:
- SimpleSequentialChain:单个输入/输出
- SequentialChain:多个输入/输出
简单顺序链,每条链都有一个输入、一个输出,一条接一条。顺序链,链中的任意环节可以接收多个输入变量。当有复杂的下游链需要和多个上游链组合,会非常有用。顺序链是将一系列链一个一个地运行。
首先,导入顺序链。
from langchain.chains import SimpleSequentialChain
当我们的子链都只需要一个输入并且只返回一个输出时,这个方法很有用。创建一条链,使用LLM和提示词模板。提示词模版将接受输入一个产品参数,并返回最佳的产品所属公司描述。
llm = ChatOpenAI(temperature=0.9)
# prompt template 1
first_prompt = ChatPromptTemplate.from_template(
"What is the best name to describe a company that makes {product}? "
)
# chain 1
chain_one = LLMChain(llm=llm, prompt=first_prompt)
我们创建第二条链。
# prompt template 2
second_prompt = ChatPromptTemplate.from_template(
"Write a 20 words description for the following company company: {company_name} "
)
# chain 2
chain_two = LLMChain(llm=llm, prompt=second_prompt)
通过创建一个SimpleSequentialChain,可以很容易实现这些链一条接一条运行的效果。第一条链会输出公司名称,会将它传递给第二条链。
overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two], verbose=True)
现在可以在任何产品上描述运行这条链了。
overall_simple_chain.run(product)
简单顺序链(SimpleSequentialChain)在只有一个输入和输出时表现非常好。但当有多个输入或多个输出该怎么办呢?可以使用SequentialChain来实现。
首先导入SequentialChain。
from langchain.chains import SequentialChain
然后可以创建一系列链,后面我们将一次调用这些链。用第一条链将评论翻译成英语,用第二条链总结这篇评论,用第三条链识别最初的评论是什么语言,用第四条链接收多个输入,即第二条链的摘要及第三条链的语言,要求对摘要进行回复,使用其特定语言。
llm = ChatOpenAI(temperature = 0.9)
# prompt template 1: translate to english
first_prompt = ChatPromptTemplate.from_template(
"Translate the following review to english:"
"\n\n{Review}"
)
# chain 1
chain_one = LLMChain(llm=llm, prompt=first_prompt, output_key = "English_Review")
# prompt template 2: summarize the review
second_prompt = ChatPromptTemplate.from_template(
"Can you summarize the following review in 1 sentence:"
"\n\n{English_Review}"
)
# chain 2
chain_two = LLMChain(llm=llm, prompt=second_prompt, output_key = "summary")
# prompt template 3: find what language
second_prompt = ChatPromptTemplate.from_template(
"What language is the following review:\n\n{Review}"
)
# chain 3
chain_three = LLMChain(llm=llm, prompt=third_prompt, output_key = "language")
# prompt template 4: follow up message
second_prompt = ChatPromptTemplate.from_template(
"Write a follow up response to the following "
"summary in the specified language:"
"\n\nSummary: {summary}\n\nLanguage: {language}"
)
# chain 3
chain_three = LLMChain(llm=llm, prompt=third_prompt)
关于所有这些子链,需要注意,输入名和输出名要非常精确。如果出现任何错误,一定要检查下变量名是否一致。然后,我们可以轻松地将它们组合在顺序链(SequentialChain)中。
overall_chain = SequentialChain(
chains=[chain_one, chain_two, chain_three, chain_four],
input_variables=["Review"],
output_variables=["English_Review", "summary", "followup_message"],
verbose = True
)
我们选择一条评论并传递给整条链,
review = df.Review[5]
overall_chain(review)
如果更加复杂的操作呢?
Router Chain(路由链)
根据输入内容路由到某条链来处理你的输入。如果有多条子链,每条子链专门负责处理某种特定类型的输入,这种情况下可以使用路由链(Router Chain)。首先判断应该使用哪条子链,然后将输入传递到相应的子链中。我们来看个例子:第一个提示词回答物理问题,第二个提示词回答数学问题,第三个提示词回答历史问题,第四个提示词回答计算机问题。我们可以给每个模版起名字,然后写描述。接下来导入其他需要的链类型。
from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.prompts import PromptTemplate
MultiPromptChain可以在多个不同提示词模版之间路由。RouterOutputParser可以将LLM输出解析成一个字典,根据字典内容可以在下游确定使用哪条链,以及该链的输入应该是什么。首先导入并定义语言模型。
llm = ChatOpenAI(temperature = 0)
然后创建目标链。
destination_chains = {}
for p_info in prompt_infos:
name = p_info["name"]
prompt_template = p_info["prompt_template"]
prompt = ChatPromptTemplate.from_template(template = prompt
chain = LLMChain(llm = llm, prompt = prompt)
destination_chains[name] = chain
destinations = [f"{p['name']}:{p['description']}" for p in
destinations_str = "\n".join(destinations)
每个目标链本身就是一个语言模型,即LLMChain。除了目标链,我们还需要一个默认链。默认链是在路由找不到合适的子链调用时,用来备用的一条链路。上述问题中,若与物理、数学、历史或计算机无关,就会调用这条链路。
default_prompt = ChatPromptTemplate.from_template(
default_chain = LLMChain(llm = llm, prompt = default_prompt)
我们定义一个提示词模版,让LLM根据提示词内容在不同链之间路由。包含了完成任务的说明及输出内容的格式。接下来构建路由链。这个模版适用于许多不同类型的目标。我们从这个模版创阿金提示词,传入LLM和整个路由器提示词,创建路由链。最后,把所有内容汇集,可以创建整条链。
chain = MultiPromptChain(router_chain=router_chain, destination_chains=destination_chains, default_chain = default_chain, verbose = True)
接下来就可以向他提问了。
chain.run("What is black body radiation?")
None的时候,就是直接当做一个通用的问题,去问语言模型了。我们可以尝试将这些链组合在一起,创建有趣的应用。