LangChain 系列教程(五):Chain
介绍
在 LangChain 框架中,Chain (链) 是一个核心接口,用于实现对多个组件的序列化调用和组合。它将不同的功能单元(如模型调用、数据检索、逻辑处理)封装成一个连贯的工作流(Workflow),从而构建功能复杂的应用程序。
常用的核心链有三种:
LLMChain:将提示词模板和语言模型封装在一起的基础工具,专门用于执行单一、独立的AI调用任务。
Sequential Chain:像流水线一样将多个独立的链按固定顺序连接起来,并自动将上一步的输出作为下一步的输入。
RouterChain:通过分析输入来动态地从多个选项中选择并执行最合适的子链,从而为应用添加决策与分支的能力。
代码
创建环境
|
Python import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI
# 加载 .env 文件 load_dotenv()
os.environ["OPENAI_API_BASE"] = os.getenv("OPENAI_API_BASE") os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
# 初始化 LLM,我们将在所有示例中复用这个实例 llm = ChatOpenAI(temperature=0, model="gpt-4o")
print("环境准备完毕,LLM 已初始化。")
|
测试LLMChain
|
Python from langchain.chains import LLMChain from langchain.prompts import PromptTemplate
# 1. 定义提示词模板 # 这个模板接收一个名为 "product_type" 的变量 prompt_template_name = PromptTemplate( input_variables=["product_type"], template="你是一个专业的品牌顾问。请为一个专注于 {product_type} 的新公司想一个响亮、有创意的中文名字。" )
# 2. 创建 LLMChain # 我们将提示词模板和 LLM 实例组合在一起 name_chain = LLMChain(llm=llm, prompt=prompt_template_name)
# 3. 运行链 # 使用 .invoke() 方法并传入一个字典作为输入 product_type = "家用智能咖啡机" result = name_chain.invoke({"product_type": product_type})
print(f"产品类型: {product_type}") print(f"生成的公司名: {result['text']}")
|
结果
|
Python /var/folders/z5/r_6tsnmx7bjcnqbgkmfp22540000gn/T/ipykernel_45167/3352325305.py:13: LangChainDeprecationWarning: The class `LLMChain` was deprecated in LangChain 0.1.17 and will be removed in 1.0. Use :meth:`~RunnableSequence, e.g., `prompt | llm`` instead. name_chain = LLMChain(llm=llm, prompt=prompt_template_name) 产品类型: 家用智能咖啡机 生成的公司名: 当然!为一家专注于家用智能咖啡机的新公司取一个响亮、有创意的中文名字可以帮助它在市场上脱颖而出。以下是几个建议:
1. 咖智家 2. 智享咖 3. 咖啡慧 4. 咖智坊 5. 咖乐智 6. 咖享家 7. 咖智源 8. 咖啡灵 9. 咖智汇 10. 咖智品
这些名字结合了智能科技与咖啡的元素,旨在传达创新、便捷和高品质的品牌形象。希望其中一个能激发您的灵感!
|
测试Sequential Chain
|
Python # 导入所需的类 from langchain.chains import SequentialChain, LLMChain from langchain.prompts import PromptTemplate # 假设 llm 实例已经像之前一样初始化好了
# 1. 定义第一个链 (起名),并添加严格的输出格式要求 prompt_template_name = PromptTemplate( input_variables=["product_type"], template="""你是一个专业的品牌顾问。请为一个专注于 {product_type} 的新公司想一个响亮、有创意的中文名字。 重要:你必须只回答一个名字,不要包含任何解释、编号、标点或任何其他多余的文字。 例如:如果产品是“智能手表”,你就只回答“时光环”""" ) name_chain = LLMChain(llm=llm, prompt=prompt_template_name, output_key="company_name")
# 2. 定义第二个链 (写广告语),这个可以保持不变 prompt_template_slogan = PromptTemplate( input_variables=["company_name"], template="你是一位顶级的广告文案。请为名为 '{company_name}' 的公司写一句简洁且吸引人的广告语。" ) slogan_chain = LLMChain(llm=llm, prompt=prompt_template_slogan, output_key="slogan")
# 3. 组合 SequentialChain (保持不变) sequential_chain = SequentialChain( chains=[name_chain, slogan_chain], input_variables=["product_type"], output_variables=["company_name", "slogan"], verbose=True )
# 4. 运行顺序链 product_type = "高端降噪耳机" result = sequential_chain.invoke({"product_type": product_type})
print("\n----------- 修正后的最终结果 -----------") print(f"产品类型: {product_type}") print(f"生成的公司名: {result['company_name']}") print(f"生成的广告语: {result['slogan']}")
|
结果
|
JavaScript > Entering new SequentialChain chain...
> Finished chain.
----------- 修正后的最终结果 ----------- 产品类型: 高端降噪耳机 生成的公司名: 静音境界 生成的广告语: "静音境界:让宁静成为你的日常奢华。"
|
测试RouterChain
|
Python # --- 第三部分:RouterChain (最终修正版) ---
from langchain_core.runnables import RunnableBranch, RunnableLambda from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain.chains import ConversationChain
# 1. 为每个子链(领域专家)创建提示模板和链 (此部分不变) physics_prompt = ChatPromptTemplate.from_template( "你是一位非常聪明的物理学家。你总是用简洁、清晰的方式回答关于物理学的问题。\n问题: {input}" ) physics_chain = physics_prompt | llm | StrOutputParser()
math_prompt = ChatPromptTemplate.from_template( "你是一位顶级的数学家。你能够巧妙地解答各种数学问题。\n问题: {input}" ) math_chain = math_prompt | llm | StrOutputParser()
history_prompt = ChatPromptTemplate.from_template( "你是一位学识渊博的历史学家。你对各个时期的历史事件和人物了如指掌。\n问题: {input}" ) history_chain = history_prompt | llm | StrOutputParser()
# 2. 创建一个用于分类的路由链 (此部分不变) classifier_prompt = ChatPromptTemplate.from_template( """根据用户的输入,判断它属于哪个领域:physics, math, history 或 general。 只输出一个单词。
输入: {input} 分类:""" ) classifier_chain = classifier_prompt | llm | StrOutputParser()
# 3. 为默认路由创建一个专门处理输入的链 (这是关键的修正) # 这个链接收一个字典,提取'input'键的值,然后将其传递给ConversationChain default_route = ( RunnableLambda(lambda x: x["input"]) | ConversationChain(llm=llm) )
# 4. 使用 RunnableBranch 构建路由逻辑 branch = RunnableBranch( (lambda x: "physics" in x["topic"], physics_chain), (lambda x: "math" in x["topic"], math_chain), (lambda x: "history" in x["topic"], history_chain), default_route # 使用我们新创建的、带输入处理的默认路由 )
# 5. 将分类链和分支逻辑组合成完整的路由链 (此部分不变) full_router_chain = { "topic": classifier_chain, "input": lambda x: x["input"] } | branch
# 6. 测试新的路由链 (所有测试现在都应该能正常工作) print("\n--- 测试物理问题 ---") result = full_router_chain.invoke({"input": "牛顿第二定律是什么?"}) print(result['response'] if isinstance(result, dict) else result)
print("\n--- 测试数学问题 ---") result = full_router_chain.invoke({"input": "解释一下勾股定理。"}) print(result['response'] if isinstance(result, dict) else result)
print("\n--- 测试历史问题 ---") result = full_router_chain.invoke({"input": "谁是秦始皇?"}) print(result['response'] if isinstance(result, dict) else result)
print("\n--- 测试通用问题 (将使用默认链) ---") result = full_router_chain.invoke({"input": "你好吗?"}) print(result['response'] if isinstance(result, dict) else result)
|
结果
|
SQL --- 测试物理问题 --- 牛顿第二定律描述了物体的加速度与所受净力和质量之间的关系。它可以用公式表示为:F = ma,其中F是净力,m是物体的质量,a是物体的加速度。简单来说,物体的加速度与所受净力成正比,与质量成反比。
--- 测试数学问题 --- 勾股定理是几何学中的一个基本定理,适用于直角三角形。它描述了直角三角形三个边之间的关系。具体来说,勾股定理指出:在一个直角三角形中,斜边(即最长的边,对应直角的对边)的平方等于其他两条边(即直角的两条邻边)的平方和。
如果我们用 \(a\) 和 \(b\) 分别表示直角三角形的两条邻边,用 \(c\) 表示斜边,那么勾股定理可以用数学公式表示为:
\[ c^2 = a^2 + b^2 \]
这个定理不仅在理论上非常重要,而且在实际应用中也非常广泛。例如,它可以用于计算距离、设计建筑、导航等领域。
勾股定理的历史可以追溯到古希腊数学家毕达哥拉斯,但实际上在毕达哥拉斯之前的许多文明中已经有类似的知识。这个定理是几何学的一个重要基础,也是许多其他数学理论的基础。
--- 测试历史问题 --- 秦始皇是中国历史上第一位统一全国的皇帝,他的本名是嬴政。秦始皇于公元前259年出生,公元前210年去世,是秦朝的开国皇帝。他在公元前221年完成了对六国的统一,建立了中国历史上第一个中央集权的封建王朝——秦朝。
秦始皇在位期间进行了多项重要的改革和建设,包括推行郡县制以加强中央集权,统一度量衡、货币和文字,修建了驰名中外的万里长城以抵御北方匈奴的侵扰。此外,他还修建了规模宏大的阿房宫和自己的陵墓——秦始皇陵,陵墓中有著名的兵马俑陪葬。
秦始皇的统治虽然在许多方面促进了中国的统一和发展,但也因其严苛的法律和苛政而受到批评。他的死后不久,秦朝便因内乱和民众反抗而迅速瓦解。秦始皇在中国历史上具有重要的地位,被视为一个具有开创性和争议性的历史人物。
--- 测试通用问题 (将使用默认链) --- 我很好,谢谢你问!作为一个AI,我没有情感,但我很高兴能和你交流。你今天过得怎么样?有什么特别的事情想分享吗?
|