LangChain实战课-基础篇:深入 6 大组件 (四) | 豆包MarsCode AI刷题

218 阅读10分钟

课程介绍

  • 启程篇:从 0 到 1
    • 内容:LangChain的安装流程和快速入门操作
    • 实践:构建基于“易速鲜花”本地知识库的智能问答系统
    • 目标:直观感受LangChain的强大功能
  • 基础篇:深入 6 大组件
    • 模型(Models) :各大语言模型的接口、调用细节以及输出解析机制
    • 提示模板(Prompts) :提示工程流线化,进一步激发大语言模型的潜力
    • 数据检索(Indexes) :建立和操作文档,返回相关文档以搭建知识库
    • 记忆(Memory) :通过短时和长时记忆存储和检索对话数据
    • 链(Chains)封装功能的核心机制,灵活完成常见用例
    • 代理(Agents)另一个LangChain中的核心机制,使大模型自主调用工具,形成智能自主Agent
  • 应用篇:积累场景中的智慧
    • 内容:LangChain组件在实际场景中的应用
    • 实践:嵌入式存储、数据库连接、异步通信、智能代理的角色扮演等
    • 目标:通过实际案例展示组件了解如何共同完成复杂任务,提升实战能力
  • 实战篇:动手!
    • 项目:部署鲜花网络电商的人脉工具,开发易速鲜花聊天客服机器人
    • 实践:从模型调用到数据连接,再到记忆的存储与检索,掌握构建智能系统的每个环节
    • 目标:能够独立利用LangChain构建智能问答系统,适用于企业或个人需求

Chain概述

Chain(链)是LangChain里的关键要素,它能把各个组件和功能,像不同模型以及模型与其他组件相互链接起来,其虽构思简单却功能强大,可简化复杂应用程序实现过程并使其模块化,利于调试、维护与改进应用程序;通过预设接口实现具体链功能,像LLMChain能处理用户输入等进行功能封装,而且链之间可组合或与其他组件组合构建更复杂链,它既是内部封装功能、外部可组合串联的基本功能单元,LangChain还提供多种预置链方便完成各类任务

LLMChain:最简单的链

以 LLMChain 为例,看其如何围绕语言模型推理增添功能,整合 PromptTemplate、语言模型及 Output Parser,将 Model I/O 置于一个链中整体操作,对比不使用链时 Model I/O 独立处理的代码示例,展现使用 LLMChain 后代码结构更简洁、能将提示模板构建与模型调用封装在一起的优势特点

#----第一步 创建提示
# 导入LangChain中的提示模板
from langchain import PromptTemplate
# 原始字符串模板
template = "{flower}的花语是?"
# 创建LangChain模板
prompt_temp = PromptTemplate.from_template(template) 
# 根据模板创建提示
prompt = prompt_temp.format(flower='玫瑰')
# 打印提示的内容
print(prompt)

#----第二步 创建并调用模型 
# 导入LangChain中的OpenAI模型接口
from langchain import OpenAI
# 创建模型实例
model = OpenAI(temperature=0)
# 传入提示,调用模型,返回结果
result = model(prompt)
print(result)
# 导入所需的库
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)

链的调用方式

# 设置OpenAI API密钥
import os

# 导入所需库
from langchain import PromptTemplate, LLMChain
from langchain_openai import ChatOpenAI

# 设置提示模板
prompt = PromptTemplate(
    input_variables=["flower", "season"], template="{flower}在{season}的花语是?"
)

# 初始化大模型
llm = ChatOpenAI(model=os.environ.get("LLM_MODELEND"), temperature=0)

# 初始化链
llm_chain = LLMChain(llm=llm, prompt=prompt)

# 调用链
response = llm_chain({"flower": "玫瑰", "season": "夏季"})
print(response)

# run方法
llm_chain.run({"flower": "玫瑰", "season": "夏季"})

# predict方法
result = llm_chain.predict(flower="玫瑰", season="夏季")
print(result)

# apply方法允许您针对输入列表运行链
input_list = [
    {"flower": "玫瑰", "season": "夏季"},
    {"flower": "百合", "season": "春季"},
    {"flower": "郁金香", "season": "秋季"},
]
result = llm_chain.apply(input_list)
print(result)

# generate方法
result = llm_chain.generate(input_list)
print(result)
  • 直接调用:像调用函数一样调用链对象(实际调用其__call__方法),以字典形式传入提示模板变量值获取回复
  • run 方法:等价于直接调用__call__函数,同样传入字典形式的变量值来获取结果
  • predict 方法:和 run 方法类似,但输入键以关键字参数形式传入而非字典形式
  • apply 方法:可针对输入列表运行链,能一次处理多个输入情况,批量获取结果
  • generate 方法:类似于 apply 方法,不过返回的是包含模型相关信息的 LLMResult 对象,而非简单字符串

Sequential Chain:顺序链

下面我们用Sequential Chain 把几个LLMChain串起来,形成一个顺序链

  • 第一步,我们假设大模型是一个植物学家,让他给出某种特定鲜花的知识和介绍
  • 第二步,我们假设大模型是一个鲜花评论者,让他参考上面植物学家的文字输出,对鲜花进行评论
  • 第三步,我们假设大模型是易速鲜花的社交媒体运营经理,让他参考上面植物学家和鲜花评论者的文字输出,来写一篇鲜花运营文案
# 设置OpenAI API密钥
import os

# 导入所需要的库
from langchain.chains import LLMChain, SequentialChain
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

# 第一个LLMChain:生成鲜花的介绍
llm = ChatOpenAI(
    temperature=0.7,
    model=os.environ.get("LLM_MODELEND"),
)
template = """
你是一个植物学家。给定花的名称和类型,你需要为这种花写一个200字左右的介绍。
花名: {name}
颜色: {color}
植物学家: 这是关于上述花的介绍:"""
prompt_template = PromptTemplate(input_variables=["name", "color"], template=template)
introduction_chain = LLMChain(
    llm=llm, prompt=prompt_template, output_key="introduction"
)

# 第二个LLMChain:根据鲜花的介绍写出鲜花的评论
template = """
你是一位鲜花评论家。给定一种花的介绍,你需要为这种花写一篇200字左右的评论。
鲜花介绍:
{introduction}
花评人对上述花的评论:"""
prompt_template = PromptTemplate(input_variables=["introduction"], template=template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review")

# 第三个LLMChain:根据鲜花的介绍和评论写出一篇自媒体的文案
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)
  • 第一个链:初始化 ChatOpenAI 模型,设置相关参数。创建提示模板,按花名和颜色生成花的介绍内容,构建 introduction_chain 用于输出对应鲜花介绍,指定输出键
  • 第二个链:定义新提示模板,基于鲜花介绍写评论,以此构建 review_chain 输出鲜花评论,设输出键
  • 第三个链:再定义提示模板,结合鲜花介绍与评论写自媒体文案,构建 social_post_chain 输出文案,设输出键
  • 用 SequentialChain 将前面三个链按顺序组合,设置输入变量为花名和颜色,输出变量对应各链的输出内容,开启详细输出模式

Router Chain:路由链

RouterChain(路由链)可动态选择给定输入对应的下一个链,能依据预设规则或分析输入内容来智能判断,使处理流程更灵活高效,适配不同情况的处理路径,满足多样化任务需求,在复杂业务与多链路框架中有重要作用

import warnings
import os # 添加

warnings.filterwarnings("ignore")

# 设置OpenAI API密钥

# 构建两个场景的模板
flower_care_template = """
你是一个经验丰富的园丁,擅长解答关于养花育花的问题。
下面是需要你来回答的问题:
{input}
"""

flower_deco_template = """
你是一位网红插花大师,擅长解答关于鲜花装饰的问题。
下面是需要你来回答的问题:
{input}
"""

# 构建提示信息
prompt_infos = [
    {
        "key": "flower_care",
        "description": "适合回答关于鲜花护理的问题",
        "template": flower_care_template,
    },
    {
        "key": "flower_decoration",
        "description": "适合回答关于鲜花装饰的问题",
        "template": flower_deco_template,
    },
]

# 初始化语言模型
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model=os.environ.get("LLM_MODELEND"),
)

# 构建目标链
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

# 构建路由链
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)

# 构建默认链
from langchain.chains import ConversationChain

default_chain = ConversationChain(llm=llm, output_key="text", verbose=True)

# 构建多提示链
from langchain.chains.router import MultiPromptChain

chain = MultiPromptChain(
    router_chain=router_chain,
    destination_chains=chain_map,
    default_chain=default_chain,
    verbose=True,
)

# 测试1
print(chain.run("如何为玫瑰浇水?"))
# 测试2
print(chain.run("如何为婚礼场地装饰花朵?"))
# 测试3
print(chain.run("如何区分阿豆和罗豆?"))
  1. 构建提示模板:创建两个不同场景下的文本模板,分别是 flower_care_template(针对养花育花问题,以园丁角度)和 flower_deco_template(针对鲜花装饰问题,以网红插花大师角度),用于后续生成不同用途的提示信息
  2. 构建提示信息列表:将上述两个模板相关信息整理成 prompt_infos 列表,每个元素包含 key(用于标识不同场景链)、description(对应场景描述)以及 template(具体模板内容),明确不同提示的用途及对应模板情况
  3. 初始化语言模型:从 langchain_openai 库中导入 ChatOpenAI 并初始化语言模型 llm,模型名称尝试从环境变量 LLM_MODELEND 中获取(可能存在变量名准确性问题),用于后续链构建中的语言处理环节
  4. 构建目标链:从相关库导入必要的类,通过循环 prompt_infos 列表,针对每个提示信息创建对应的 PromptTemplate,再用其和已初始化的 llm 构建 LLMChain,将这些链存储在 chain_map 字典中,以 key 作为字典的键,方便后续按场景调用不同的链
  5. 构建路由链:从相应路由相关库中导入类,先是基于 prompt_infos 整理出 destinations 信息,然后结合特定模板格式生成 router_template,并创建对应的 PromptTemplate 即 router_prompt,最后利用语言模型 llm 和 router_prompt 构建出 LLMRouterChain(路由链),且设置为详细输出模式,用于根据输入动态选择后续链
  6. 构建默认链:从 langchain.chains 库导入 ConversationChain 并构建 default_chain,用于在路由链无法匹配合适场景时作为默认的处理链,同样设置为详细输出模式
  7. 构建多提示链:从 langchain.chains.router 库导入相关类构建 MultiPromptChain,整合了前面构建的 router_chain(路由链)、destination_chains(目标链集合)以及 default_chain(默认链),使其可以根据输入决定使用目标链或默认链来处理,并开启详细输出模式

写在最后

LangChain 提供了实用的 “链” 来连接多个组件,链代表着组件的调用顺序,且可包含其他链。我们能用多种方法调用链,并按需选择不同类型的链。这些链帮助我们按不同需求灵活构建和处理语言相关任务,让整个开发流程更有条理、更具针对性……无论如何,有一点毋庸置疑。我们正站在一个崭新的历史节点上。