链的实现和使用:
- 通过LangChain实现一个链,链可以接受输入,使用PromptTemplate对其进行格式化,然后将格式化的响应传递给LLM。
- 实现链的具体功能后,可以通过将多个链组合在一起,或者将链与其他组件组合起来构建更复杂的链。
-
LLMChain
最简单最基本的链。对输入格式化、传入模型、等待LLM响应,同时解析输出。
-
SequentialChain(顺序链)
当想要获取一个调用的输出并将其用作另一个调用的输入时,顺序链就特别有用。
其中每个步骤都有一个单一的输入/输出,并且一个步骤的输出是下一步的输入。
-
TransformChain(转换链)4
通过设置转换函数,对输入文本进行一系列的格式转换。
例如,可以用它就收一个很长的衔环相关的文档,给文档分割成句子,仅仅保留前面N句,以满足LLM的令牌数量的限制。
-
RouterChain(路由链)
包含条件判断和一系列的目标链。通过调用LLM,路由链能动态判断条件,以确定调用后续哪一个目标Chain
-
其他工具链
一、LLMChain——最基础的链
LLMChain整合了PromptTemplate、语言模型和Output Parser,相当于把Model I/O放在一个链中整体操作。它使用提示模板格式化输入,将格式化的字符传递给LLM,并返回LLM输出。
import os
from langchain import PromptTemplate,OpenAI,LLMChain
template = "{flower}的花语是什么?"
os.environ["OPENAI_API_KEY"] = 'sk-mduGNGc05FuHrfR5URGnAY9Ir9Rbho24186WfLBfKvNUYioS'
LLM = OpenAI(temperature=0,base_url='<https://api.openai-proxy.org/v1>')
llm_chain = LLMChain(
llm=LLM,
prompt = PromptTemplate.from_template(template)
)
result = llm_chain("玫瑰")
print(result)
from langchain import PromptTemplate,OpenAI,LLMChain
prompt = PromptTemplate(
input_variables = ["flower","scene"],
template = "{flower}在{scene}场景下的花语是?"
)
llm_chain = LLMChain(llm=LLM,prompt = prompt)
print(llm_chain({
'flower':'玫瑰',
'scene':'商务'
}))
几个小方法
llm_chain({'flower':"玫瑰",'scene':'采矿'}) # 等价于llm_chain.run()
# predict方法类似于run,知识输入键北指定为关键字参数而不受Python字典
result = llm_chain.predict(flower="玫瑰",scene="爱情")
print(result)
# apply方法,可以一次处理多个输入
input_list = [
{"flower": "玫瑰",'scene': "夏季"},
{"flower": "百合",'scene': "春季"},
{"flower": "郁金香",'scene': "秋季"}
]
result = llm_chain.apply(input_list)
print(result)
# generate方法类似于apply,只不过它返回一个LLMResult对象,而不是字符串.里面有许多生成信息
result = llm_chain.generate(input_list)
print(result)
二、 顺序链
import os
os.environ["OPENAI_API_KEY"] = 'sk-mduGNGc05FuHrfR5URGnAY9Ir9Rbho24186WfLBfKvNUYioS'
LLM = OpenAI(temperature=0,base_url='<https://api.openai-proxy.org/v1>')
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chains import SequentialChain
#%%
# 添加第一个llmchain
template = """
你是一个植物学家。给定花的名称和类型,你需要为这种话协议额200字左右的介绍
花名:{name}
颜色:{color}
植物学家:这是关于上述花的介绍:
"""
prompt_template = PromptTemplate(input_variables=["name","color"],template=template)
introduction_chain = LLMChain(llm=LLM,prompt=prompt_template,output_key="introduction")
#%%
# 添加第二个chain
LLM = OpenAI(temperature=0.7,base_url='<https://api.openai-proxy.org/v1>')
template = """
你是一位鲜花评论家。给定一种花的介绍,你需要为这种花写一篇200字左右的评论。
鲜花介绍:
{introduction}
花评人对上述花的评论:"""
prompt_template = PromptTemplate(input_variables=["introduction"],template=template)
review_chain = LLMChain(llm=LLM,prompt=prompt_template,output_key="review")
#%%
# 第三个Chain
template = """
你是一家花店的社交媒体经理。给定一种花的介绍和评论,你需要为这种花写一篇社交媒体的帖子,300字左右。
鲜花介绍:
{introduction}
花评人对上述花的评论:
{review}
社交媒体帖子:
"""
prompt_template = PromptTemplate(input_variables=["introduction", "review"], template=template)
social_post_chain = LLMChain(llm=LLM, prompt=prompt_template, output_key="social_post_text")
#%%
overall_chain = SequentialChain(
chains=[introduction_chain,review_chain,social_post_chain],
input_variables = ["name","color"],
output_variables = ["introduction","review","social_post_text"],
verbose=True
)
result = overall_chain({"name":"玫瑰","color":"黑色"})
print(result)
链——下
首先,还是先看一下今天要完成一个什么样的任务。
这里假设咱们的鲜花运营智能客服ChatBot通常会接到两大类问题。
- 鲜花养护(保持花的健康、如何浇水、施肥等)
- 鲜花装饰(如何搭配花、如何装饰场地等)
需求是,如果接到的是第一类问题,你要给ChatBot A指示;如果接到第二类的问题,你要给ChatBot B指示。
整体框架
RouterChain,也叫路由链,能动态选择用于给定输入的下一个链。我们会根据用户的问题内容,首先使用路由器链确定问题更适合哪个处理模板,然后将问题发送到该处理模板进行回答。如果问题不适合任何已定义的处理模板,它会被发送到默认链。
在这里,我们会用LLMRouterChain和MultiPromptChain(也是一种路由链)组合实现路由功能,该MultiPromptChain会调用LLMRouterChain选择与给定问题最相关的提示,然后使用该提示回答问题。
具体步骤如下:
- 构建处理模板:为鲜花护理和鲜花装饰分别定义两个字符串模板
- 提示信息:使用一个列表来组织和存储这两个处理模板的关键信息
- 初始化语言模型
- 构建目标链:根据提示信息种的每个模板构建了对应的LLMChain,并存储在一个字典中
- 构建LLM路由链:首先,它根据提示信息构建了一个路由模板,然后使用这个模板创建了一个LLMRouterChain
- 构建默认链:如果输入不符合任何已定义的处理模板,则这个默认链会被触发
- 构建多提示链:使用MultiPromptChain将LLM路由链、目标链和默认链组合在一起
路由模板
# 构建路由链
from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE as RouterTemplate
destinations = [f"{p['key']}: {p['description']}" for p in prompt_infos]
router_template = RouterTemplate.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.
<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
```json
{{
"destination": string \ name of the prompt to use or "DEFAULT"
"next_inputs": string \ a potentially modified version of the original input
}}
REMEMBER: "destination" MUST be one of the candidate prompt names specified below OR it can be "DEFAULT" if the input is not well suited for any of the candidate prompts. REMEMBER: "next_inputs" can just be the original input if you don't think any modifications are needed.
<< CANDIDATE PROMPTS >> flower_care: 适合回答关于鲜花护理的问题 flower_decoration: 适合回答关于鲜花装饰的问题
<< INPUT >> {input}
<< OUTPUT (must include json at the start of the response) >> << OUTPUT (must end with ) >>
路由提示: input_variables=['input'] output_parser=RouterOutputParser() template='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.\n\n<< FORMATTING >>\nReturn a markdown code snippet with a JSON object formatted to look like:\njson\n{{\n "destination": string \\ name of the prompt to use or "DEFAULT"\n "next_inputs": string \\ a potentially modified version of the original input\n}}\n\n\nREMEMBER: "destination" MUST be one of the candidate prompt names specified below OR it can be "DEFAULT" if the input is not well suited for any of the candidate prompts.\nREMEMBER: "next_inputs" can just be the original input if you don't think any modifications are needed.\n\n<< CANDIDATE PROMPTS >>\nflower_care: 适合回答关于鲜花护理的问题\nflower_decoration: 适合回答关于鲜花装饰的问题\n\n<< INPUT >>\n{input}\n\n<< OUTPUT (must include json at the start of the response) >>\n<< OUTPUT (must end with ) >>\n'
组成:
1. 引言
```python
Given a raw text input to a language model select the model prompt best suited for the input.
这是一个简单的引导语句,告诉模型你将给它一个输入,它需要根据这个输入选择最适合的模型提示。
- 格式说明<< FORMATTING >>
指导模型如何格式化其输出,使其以特定的方式返回结果。
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"...
-
输入/输出部分
<< INPUT >>\n{input}\n\n<< OUTPUT >>\n:
-
路由提示的解释
路由提示 (router_prompt)则根据路由模板,生成了具体传递给LLM的路由提示信息。
- 其中input_variables 指定模板接收的输入变量名,这里只有
"input"。 - output_parser 是一个用于解析模型输出的对象,它有一个默认的目的地和一个指向下一输入的键。
- template 是实际的路由模板,用于给模型提供指示。这就是刚才详细解释的模板内容。
- template_format 指定模板的格式,这里是
"f-string"。 - validate_template 是一个布尔值,如果为 True,则会在使用模板前验证其有效性。
简而言之,这个构造允许你将用户的原始输入送入路由器,然后路由器会决定将该输入发送到哪个具体的模型提示,或者是否需要对输入进行修订以获得最佳的响应。
- 其中input_variables 指定模板接收的输入变量名,这里只有
构建默认链
除了处理目标链和路由链之外,我们还需要准备一个默认链。如果路由链没有找到适合的链,那么,就以默认链进行处理。
# 构建默认链
from langchain.chains import ConversationChain
default_chain = ConversationChain(llm=llm,
output_key="text",
verbose=True)
构建多提示链
最后,我们使用MultiPromptChain类把前几个链整合在一起,实现路由功能。这个MultiPromptChain类是一个多路选择链,它使用一个LLM路由器链在多个提示之间进行选择。
MultiPromptChain中有三个关键元素。
- router_chain(类型RouterChain):这是用于决定目标链和其输入的链。当给定某个输入时,这个router_chain决定哪一个destination_chain应该被选中,以及传给它的具体输入是什么。
- destination_chains(类型Mapping[str, LLMChain]):这是一个映射,将名称映射到可以将输入路由到的候选链。例如,你可能有多种处理文本输入的方法(或“链”),每种方法针对特定类型的问题。destination_chains可以是这样一个字典:
{'weather': weather_chain, 'news': news_chain}。在这里,weather_chain可能专门处理与天气相关的问题,而news_chain处理与新闻相关的问题。 - default_chain(类型LLMChain):当 router_chain 无法将输入映射到destination_chains中的任何一个链时,LLMChain 将使用此默认链。这是一个备选方案,确保即使路由器不能决定正确的链,也总有一个链可以处理输入。
它的工作流程如下:
- 输入首先传递给router_chain。
- router_chain根据某些标准或逻辑决定应该使用哪一个destination_chain。
- 输入随后被路由到选定的destination_chain,该链进行处理并返回结果。
- 如果router_chain不能决定正确的destination_chain,则输入会被传递给default_chain。