链是 LangChain 框架的核心功能之一,它为组合多个组件提供了强大且灵活的方式。在 LangChain 里,“链”(Chains)是一种将多个组件或工具,模型或处理步骤组合起来,形成特定工作流程的机制。借助链,能够把简单的组件组合成一个整体,完成复杂的任务。
有时更新不及时,最新的文章和动态请关注公众号:我和 AI 的成长
一、链类型介绍
LangChain 的链类型丰富多样,可根据具体需求灵活组合,类型包括基础链(LLMChain、SequentialChain)、路由链(RouterChain)、检索链(RetrievalQA、VectorDBQA)、记忆链(ConversationChain)、对话链(ChatVectorDBChain)、工具链(TransformChain、LLMCheckerChain)和自定义链等。
二、链实战
1. LLMChain
最基础的链,它把提示模板(PromptTemplate)和大语言模型(LLMs)结合在一起。其工作流程是,先根据提示模板生成输入文本,再将该文本传递给大语言模型,最后得到输出结果。如上一篇提示词文章中的示例,通过链(Chain)动态生成提示,可结合不同组件的输出。通过前置链生成上下文,再结合主提示提升准确性。代码示例如下:
from langchain.chains import LLMChainfrom langchain.llms import OpenAIfrom langchain.prompts import PromptTemplate
# 第一个链:生成主题概述overview_prompt = PromptTemplate( input_variables=["topic"], template="简要介绍{topic}的核心概念:")overview_chain = LLMChain(llm=OpenAI(), prompt=overview_prompt)
# 第二个链:基于概述生成详细提示detail_prompt = PromptTemplate( input_variables=["topic", "overview"], template="基于以下概述,详细解释{topic}的应用场景:\n{overview}")detail_chain = LLMChain(llm=OpenAI(), prompt=detail_prompt)
# 执行链topic = "区块链"overview = overview_chain.run(topic)result = detail_chain.run(topic=topic, overview=overview)print("概述:", overview)print("详细应用:", result)
复制代码
代码运行结果如下:
2. SequentialChain(顺序链)
顺序链形式,将多个链按顺序连接起来,每个步骤都有输入和输出,前一个链的输出会作为后一个链的输入。顺序链包括:SimpleSequentialChain(单输入单输出,所有链必须匹配输入 / 输出格式)和 SequentialChain(多输入多输出,可指定特定的输入 / 输出变量)
2.1 SimpleSequentialChain
最简单的顺序链形式,如以下步骤:
步骤 1:输入 A → 输出 B
步骤 2:输入 B → 输出 C
步骤 3:输入 C → 输出 D
代码示例如下:
# ------------ SimpleSequentialChain 示例 ------------# 第一个链:生成产品描述product_template = """为以下产品生成一个吸引人的描述:产品: {product}"""product_prompt = PromptTemplate(input_variables=["product"], template=product_template)product_chain = LLMChain(llm=llm, prompt=product_prompt, output_key="description")# 第二个链:基于描述生成广告标语slogan_template = """为以下产品描述生成一个简短的广告标语:描述: {description}"""slogan_prompt = PromptTemplate(input_variables=["description"], template=slogan_template)slogan_chain = LLMChain(llm=llm, prompt=slogan_prompt, output_key="slogan")# 组装SimpleSequentialChainsimple_chain = SimpleSequentialChain(chains=[product_chain, slogan_chain], verbose=True)# 执行链simple_result = simple_chain.run("无线蓝牙耳机")print("\nSimpleSequentialChain结果:")print(simple_result)
复制代码
代码运行结果如下:
2.2 SequentialChain
更灵活的顺序链形式,当链需要多个输入变量时,可以指定完整的输入输出变量映射。需要访问中间步骤的输出结果时可保留所有中间结果。支持更复杂的数据流模式。如以下步骤:
步骤 1:输入 A、输入 B → 输出 C
步骤 2:输入 C、输入 D → 输出 E
步骤 3:输入 E、输入 F → 输出 G
代码示例如下:
# ------------ SequentialChain 示例(单参数) ------------
# 第一个链:分析产品特点features_template = """分析以下产品的主要特点:产品: {product}"""features_prompt = PromptTemplate(input_variables=["product"], template=features_template)features_chain = LLMChain(llm=llm, prompt=features_prompt, output_key="features")# 第二个链:基于特点生成描述desc_template = """基于以下产品特点,写一个吸引人的产品描述:特点: {features}"""desc_prompt = PromptTemplate(input_variables=["features"], template=desc_template)desc_chain = LLMChain(llm=llm, prompt=desc_prompt, output_key="description")
# 第三个链:基于描述生成广告标语ad_template = """为以下产品描述创作一个朗朗上口的广告标语:描述: {description}"""ad_prompt = PromptTemplate(input_variables=["description"], template=ad_template)ad_chain = LLMChain(llm=llm, prompt=ad_prompt, output_key="slogan")
# 组装SequentialChainsequential_chain = SequentialChain( chains=[features_chain, desc_chain, ad_chain], input_variables=["product"], output_variables=["features", "description", "slogan"], verbose=True)
# 执行链sequential_result = sequential_chain({"product": "智能手表"})print("\nSequentialChain结果:")print(f"特点: {sequential_result['features']}")print(f"描述: {sequential_result['description']}")print(f"标语: {sequential_result['slogan']}")
复制代码
代码运行结果如下(单参数):
代码示例如下(多参数):
# ------------ SequentialChain 示例(多参数) ------------
# 第一个链:分析产品特点features_template = """分析以下产品的主要特点:产品: {product}"""features_prompt = PromptTemplate(input_variables=["product"], template=features_template)features_chain = LLMChain(llm=llm, prompt=features_prompt, output_key="features")
# 第二个链:基于特点生成描述desc_template = """基于以下产品特点,写一个吸引人的产品描述:特点: {features}目标用户: {user_type}"""desc_prompt = PromptTemplate(input_variables=["features", "user_type"], template=desc_template)desc_chain = LLMChain(llm=llm, prompt=desc_prompt, output_key="description")
# 第三个链:基于描述和预算生成广告标语ad_template = """为以下产品描述创作一个朗朗上口的广告标语,并根据预算说明推广渠道建议:描述: {description}预算: {budget}"""ad_prompt = PromptTemplate(input_variables=["description", "budget"], template=ad_template)ad_chain = LLMChain(llm=llm, prompt=ad_prompt, output_key="ad_content")
# 第四个链:提取广告标语和推广渠道extract_template = """从以下广告内容中提取广告标语和推广渠道建议:广告内容: {ad_content}"""extract_prompt = PromptTemplate(input_variables=["ad_content"], template=extract_template)extract_chain = LLMChain(llm=llm, prompt=extract_prompt, output_key="extracted_result")
# 组装SequentialChainsequential_chain = SequentialChain( chains=[features_chain, desc_chain, ad_chain, extract_chain], input_variables=["product", "user_type", "budget"], output_variables=["features", "description", "ad_content", "extracted_result"], verbose=True)
# 执行链sequential_result = sequential_chain({ "product": "智能手表", "user_type": "健身爱好者", "budget": "5000元"})
print("\nSequentialChain结果:")print(f"产品特点: {sequential_result['features']}")print(f"产品描述: {sequential_result['description']}")print(f"广告内容: {sequential_result['ad_content']}")print(f"提取结果: {sequential_result['extracted_result']}")
复制代码
代码运行结果如下:
3.RouterChain
路由链(Router Chain)是一种特殊的链结构,能够依据输入内容,把请求导向不同的子链,动态地选择合适的子链来处理任务。适用于多领域问答系统(如区分科学、历史、技术问题等)。路由链工作原理和步骤包括:接收用户的输入、运用路由逻辑(可以是基于规则的,也可以是由 LLMs 驱动的)来分析输入、依据分析结果,选择对应的子链、将输入传递给选中的子链进行处理、返回子链的处理结果。常用的类型包括:
A. RouterChain
它是路由链的核心抽象类,定义了基本接口,负责接收输入并将其路由到合适的子链。通常需要和下游的 destination chain(目标链)一起使用,形成 “一个网关路由 + 多个下子链” 的架构。该类不提供具体的路由逻辑,子类需要自己实现来决定如何将输入路由到不同的子链,实际使用时需要结合具体的路由逻辑来实现。
B. MultiPromptChain
用于在多个提示词之间路由输入,内部维护着一个提示选择器(PromptSelector),它包含一个提示列表和一个路由逻辑,它根据输入内容挑选出最匹配的提示模板,能够将输入映射到对应的提示和链上进行处理。
C. MultiRouteChain
提供多路由能力的基类,实现了基本的路由逻辑框架,但需要子类提供具体的路由策略。
D. LLMRouterChain
它利用语言模型(LLM)来生成路由决策。使用时需要传入作为基底的大语言模型和用作路由的 prompt,包含对用户输入的解析、对路由的指引。通过对输入进行分析,预测出合适的子链或者工具。
3.1 MultiPromptChain
代码示例如下:
# 定义不同类型问题的提示模板prompt_infos = [ { "name": "science", "description": "适合回答科学相关的问题", "prompt_template": "请用科学知识回答以下问题:{input}" }, { "name": "history", "description": "适合回答历史相关的问题", "prompt_template": "请用历史知识回答以下问题:{input}" }, { "name": "general", "description": "适合回答一般性的问题", "prompt_template": "请回答以下问题:{input}" },]
# 创建子链chains = []for info in prompt_infos: prompt = PromptTemplate(template=info["prompt_template"], input_variables=["input"]) chain = LLMChain(llm=llm, prompt=prompt) chains.append((info["name"], chain))
# 创建路由器destination_chains = {name: chain for name, chain in chains}default_chain = chains[2][1] # 默认使用general链
# 创建RouterChainrouter_chain = MultiPromptChain.from_prompts(llm, prompt_infos, default_chain, verbose=True)
# 运行链science_answer = router_chain.run("什么是量子纠缠?")history_answer = router_chain.run("谁发现了美洲大陆?")general_answer = router_chain.run("如何做蛋糕?")
print("科学问题回答:", science_answer)print("历史问题回答:", history_answer)print("一般性问题回答:", general_answer)
复制代码
代码运行结果如下:
3.2 MultiRouteChain
代码示例如下:
# 创建各个领域的链destination_chains = {}for p_info in prompt_infos: prompt = PromptTemplate( template=p_info["prompt_template"], input_variables=["input"] ) chain = LLMChain(llm=llm, prompt=prompt) destination_chains[p_info["name"]] = chain
# 默认链,当无法匹配到特定领域时使用default_prompt = PromptTemplate( template="""你是一个通用助手,能够回答各种类型的问题。 请回答以下问题: {input}""", input_variables=["input"])default_chain = LLMChain(llm=llm, prompt=default_prompt)
# 构建路由链router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format( destinations="\n".join([f"{p['name']}: {p['description']}" for p in prompt_infos]), destination_names=", ".join([p["name"] for p in prompt_infos]))router_prompt = PromptTemplate( template=router_template, input_variables=["input"], output_parser=RouterOutputParser())router_chain = LLMRouterChain.from_llm( llm, router_prompt)
# 组合MultiRouteChainchain = MultiRouteChain( router_chain=router_chain, destination_chains=destination_chains, default_chain=default_chain, verbose=True)
# 测试不同领域的问题questions = [ "什么是量子纠缠?", "如何证明勾股定理?", "第一次世界大战的主要原因是什么?", "如何做蛋糕?"]
for question in questions: print(f"\n问题: {question}") answer = chain.invoke({"input":question}) print(f"回答: {answer}")
复制代码
代码运行结果如下:
3.3 LLMRouterChain
LLMRouterChain 通常与 MultiRouteChain 结合使用,形成完整的动态路由系统,具体示例如上边代码。
关键区别总结
三、总结
LangChain 提供了丰富的链类型,从简单的 LLM 调用到复杂的代理系统,覆盖了各种应用场景。在实际开发中,应根据任务需求选择合适的链类型,遵循 "从简单到复杂" 的原则,合理组合现有组件,并在必要时自定义链以满足特定需求。通过遵循最佳实践,可以构建出高效、可维护、更强大且安全的 LLM 应用。
评论