LangChain中我们已经讲解了其中模型的概念,以及相关的提示工程,以及相关的结构化解析功能。
但是在LangChain中,Chain 链这个概念一直没有提到。
其主要是可以将多个组件相互组合,组合成一个连贯的应用程序。
就好比我们可以将多个链节点串联起来,将前面节点的输出作为下一个节点的输入,重新进行使用。
那么链的节点内部,则封装之前我们了解的诸如提示工程,模型等组件,也就是说在一个大型的程序之中,链的节点是最小的功能单元。
在LangChain中,提供一些预置Chain,方便我们的使用
LLMChain,最简单的链,主要充当节点这个概念,可以对用户的输入进行格式化,将格式化的提示传入模型,然后返回LLM的响应,
SequentialChain 顺序链,将多个简单链组合,上一步骤的输入作为下一步骤的输出。
TransformChain 转换链,通过设置转换函数,对输入文本进行一系列的格式转换。比如可以根据输入的文档,进行相关的分词
RouterChain 路由链,包含判断等一系列的目标链,可以由LLM 动态选择目标Chain
其他的工具链比如 LLMMathChain 可以调用大模型作为数学工具进行构建链。
那么我们依次看下上面链的使用。
首先是LLMChain,最简单的链的使用
其基本上就是将提示工程,语言模型,输出解析器放在了一个节点进行运行。
基本的使用为
# 导入所需的库
from langchain import PromptTemplate, OpenAI, LLMChain # 原始字符串模板 template = “{flower}的花语是?” # 创建模型实例 llm = OpenAI(temperature=0) # 创建LLMChain llm_chain = LLMChain( llm=llm, prompt=PromptTemplate.from_template(template)) # 调用LLMChain,返回结果 result = llm_chain(“玫瑰”) print(result) |
调用其就比较简单,只需要llm_chain就可以了,这本质上是调用其内部的__call__方法
当然也可以调用其run方法,等同于调用__call__方法
或者调用predict方法,其等于升级版的run,只不过支持输入键值
result = llm_chain.predict(flower=”玫瑰”)
利用apply方法,可以一次性处理多个输入
input_list = [
{“flower”: “玫瑰”, ‘season’: “夏季”},
{“flower”: “百合”, ‘season’: “春季”},
{“flower”: “郁金香”, ‘season’: “秋季”}
]
result = llm_chain.apply(input_list)
同时得到的输出也是一个列表。
通过generate方法
是一个原始版的apply方法,返回一个LLMResult对象,而不是字符串。能够得到更多的元数据信息。
在简单介绍完LLMChain之后,我们看下Sequential Chain 顺序链。
其支持将多个Chain进行串联
我们可以如下举例
首先假设模型是一个鲜花学家,可以给出某些鲜花的知识介绍
然后假设模型是一个花店店主,根据上面的知识产出运营文案。
首先是第一个LLMChain
llm = OpenAI(temperature=.7)
template = “”” 你是一个植物学家。给定花的名称和类型,你需要为这种花写一个200字左右的介绍。 花名: {name} 颜色: {color} 植物学家: 这是关于上述花的介绍:””” prompt_template = PromptTemplate( input_variables=[“name”, “color”], template=template ) introduction_chain = LLMChain( llm=llm, prompt=prompt_template, output_key=”introduction” ) |
其次是花店店主
template = “””
你是一家花店的社交媒体经理。给定一种花的介绍和评论,你需要为这种花写一篇社交媒体的帖子,300字左右。 鲜花介绍: {introduction} 社交媒体帖子: “”” prompt_template = PromptTemplate( input_variables=[“introduction”], template=template ) social_post_chain = LLMChain( llm=llm, prompt=prompt_template, output_key=”social_post_text” ) |
之后是组装这些链路
overall_chain = SequentialChain(
chains=[introduction_chain, social_post_chain], input_variables=[“name”, “color”], output_variables=[“introduction”, “social_post_text”], verbose=True ) |
最后是运行
result = overall_chain({
“name”: “玫瑰”,
“color”: “黑色”
})
这样我们就利用两个LLM链和一个顺序链,生成了一个文案
{‘name’: ‘玫瑰’, ‘color’: ‘黑色’, ‘introduction’: ‘nn黑色玫瑰,这是一种对传统玫瑰花的独特颠覆,它的出现挑战了我们对玫瑰颜色的固有认知。它的花瓣如煤炭般黑亮,反射出独特的微光,而花蕊则是金黄色的,宛如夜空中的一颗星,强烈的颜色对比营造出一种前所未有的视觉效果。在植物学中,黑色玫瑰的出现无疑提供了一种新的研究方向,对于我们理解花朵色彩形成的机制有着重要的科学价值。’, ‘social_post_text’: ‘n欢迎来到我们的自媒体平台,今天,我们要向您展示的是我们的全新产品——黑色玫瑰。这不仅仅是一种花,这是一种对传统观念的挑战,一种视觉艺术的革新,更是一种生活态度的象征。这种别样的玫瑰花,其黑色花瓣宛如漆黑夜空中闪烁的繁星,富有神秘的深度感,给人一种前所未有的视觉冲击力。这种黑色,它不是冷酷、不是绝望,而是充满着独特的魅力和力量。而位于黑色花瓣之中的金黄色花蕊,则犹如星星中的灵魂,默默闪烁,给人带来无尽的遐想,充满活力与生机。黑色玫瑰的存在,不仅挑战了我们对于玫瑰传统颜色的认知,它更是一种生动的生命象征,象征着那些坚韧、独特、勇敢面对生活的人们。黑色的花瓣中透露出一种坚韧的力量,而金黄的花蕊则是生活中的希望,二者的结合恰好象征了生活中的喜怒哀乐,体现了人生的百态。’}
这样我们先介绍了大致链的作用和一些预置链实例。
并展示了LLMChain和SequentialChain的使用。
那么我们继续
我们接下来讲下其中核心的链,RouterChain
这里我们以一个示例举例,比如我们是一个鲜花平台的客服,主要分为两类
鲜花养护,鲜花装饰
对应的就是如何培养花朵和如何挑选花朵并装饰。
那么我们就需要根据用户的输入,选择不同的链,乃至于选取不同的大模型进行回答。
那么我们就需要先定义一个RouterChain,一个路由链,可以动态根据模型输入决定选择哪个节点作为下一个输入,如果没有合适的,会被发送到默认链路。
整体的格式为
先定义不同的LLMChain,用于应对鲜花养护和鲜花装饰
然后定义一个RouterChain,用户进行决策
之后定义一个默认链,输入不合适的的处理模板,就会触发默认的链
最后利用MultiPromptChain将LLMChain,RouterChain进行整合。
那么我们就按照上面所说,逐步构建一个路由链。
首先定义两个LLMChain
flower_care_template = “””
你是一个经验丰富的园丁,擅长解答关于养花育花的问题。 下面是需要你来回答的问题: {input} “”” flower_deco_template = “”” 你是一位网红插花大师,擅长解答关于鲜花装饰的问题。 下面是需要你来回答的问题: {input} “”” |
之后定义对应的LLMChain,并存储在dict之中
prompt_infos = [
{ “key”: “flower_care”, “description”: “适合回答关于鲜花护理的问题”, “template”: flower_care_template, }, { “key”: “flower_decoration”, “description”: “适合回答关于鲜花装饰的问题”, “template”: flower_deco_template, } ] from langchain.llms import OpenAI llm = OpenAI() # 构建目标链 from langchain.chains.llm import LLMChain from langchain.prompts import PromptTemplate chain_map = {} for info in prompt_infos: prompt = PromptTemplate( template=info[‘template’], input_variables=[“input”] ) print(“目标提示:\n”, prompt) chain = LLMChain( llm=llm, prompt=prompt, verbose=True ) chain_map[info[“key”]] = chain |
这样我们就构建了两个LLMChain,并进行了存入.
之后就是关于路由链的构建。
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE as RounterTemplate destinations = [f”{p[‘key’]}: {p[‘description’]}” for p in prompt_infos] router_template = RounterTemplate.format(destinations=”\n”.join(destinations)) print(“路由模板:\n”, router_template) router_prompt = PromptTemplate( template=router_template, input_variables=[“input”], output_parser=RouterOutputParser(), ) print(“路由提示:\n”, router_prompt) router_chain = LLMRouterChain.from_llm( llm, router_prompt, verbose=True ) |
那么我们打印一下模板
并看下模板如何构建的提示信息
Given a raw text input to a language model select the model prompt best suited for the input.
You will be given the names of the available prompts and a description of what the prompt is best suited for.
You may also revise the original input if you think that revising it will ultimately lead to a better response from the language model.
上面告诉模型应该为我们挑选一个模型,而且期望其做的更好
然后是告诉模型应该返回的格式
Return a markdown code snippet with a JSON object formatted to look like:
之后是一些补充信息,比如
REMEMBER: “destination” MUST be one of the candidate prompt names specified below OR it can be “DEFAULT”…
告诉模型,destination这个字段的值应该是如下几个之一。
这就是利用RouterTeimplate做到的提示。
然后构造一个默认Chain节点。
from langchain.chains import ConversationChain
default_chain = ConversationChain( llm=llm, output_key=”text”, verbose=True ) |
最后是利用MultiPromptChain将上面的几个链整合在一起。
其中需要传入的值有
router_chain 用于决定目标链和输入的链
destination_chains 一个dict,包含key和对应的chain节点
default_chain
其处理逻辑为
现将输入传递给router_chain
然后router_chain决定使用哪个destination_chain
然后路由到destination_chain来处理并返回结果
其代码如下
from langchain.chains.router import MultiPromptChain
chain = MultiPromptChain(
router_chain=router_chain,
destination_chains=chain_map,
default_chain=default_chain,
verbose=True
)
这样就可以通过简单的chain.run进行调用了。