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

118 阅读8分钟

课程介绍

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

模型概述

模型,位于LangChain框架的最底层,它是基于语言模型构建的应用的核心元素,因为所谓LangChain应用开发,就是以LangChain作为框架,通过API调用大模型来解决具体问题的过程

Model I/O的组成部分

  1. 输入提示(Format)将输入信息格式化为适合模型处理的提示
  • LangChain提供了模板功能,可以根据需要动态生成不同的输入提示,适应特定的任务和应用场景
  1. 调用模型(Predict)通过通用接口调用不同的语言模型
  • 这一机制提高了灵活性和便利性,使得开发者可以无缝替换不同的模型进行测试和应用
  1. 输出解析(Parse)LangChain提供输出解析器,从模型的原始输出中提取所需信息
  • 输出解析帮助将非结构化文本转化为结构化数据,以便程序进行进一步处理,避免冗余和不相关内容的困扰

提示工程

提示工程(Prompt Engineering)是研究如何构建有效提示以获得理想模型输出的领域

鲜花简介提示模板:

  • 使用LangChain创建一个提示模板,自动生成鲜花描述文案
  • 示例代码展示如何定义模板:
from langchain.prompts import PromptTemplate  
template = """您是一位专业的鲜花店文案撰写员。\n对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?"""  
prompt = PromptTemplate.from_template(template)  
print(prompt)  
# 模板包含变量 `{flower_name}` 和 `{price}`,在实际调用时会被具体值替换
  • PromptTemplate对象:提供了输入变量、输出解析器和模板格式等信息,简化了提示生成与模型调用过程

LangChain 提供了多个类和函数,也为各种应用场景设计了很多内置模板,使构建和使用提示变得容易

语言模型

LangChain中支持的模型类型

  1. 大语言模型(LLM) :输入和输出都是文本字符串
  2. 聊天模型(Chat Model) :输入为聊天消息列表,输出也是聊天消息
  3. 文本嵌入模型(Embedding Model) :输入文本,输出为浮点数列表(Embedding)

调用语言模型

# 导入LangChain中的提示模板
import os
from langchain.prompts import PromptTemplate

# 创建原始模板
template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)

# 设置OpenAI API Key
# os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'

# 导入LangChain中的OpenAI模型接口
from langchain_openai import OpenAI, ChatOpenAI

# 创建模型实例
# model = OpenAI(model_name='gpt-3.5-turbo-instruct')
model = ChatOpenAI(model=os.environ.get("LLM_MODELEND"))
# 输入提示
input = prompt.format(flower_name=["玫瑰"], price="50")
# 得到模型的输出
output = model.invoke(input)
# 打印输出内容
print(output)
  1. 模块和模板的初始化:导入所需模块并创建文本模板,设置了生成文案所需的结构
  2. 创建提示模板:通过LangChain的PromptTemplate创建了一个可以进一步格式化的提示
  3. 环境变量设置:为OpenAI API配置环境变量,在实际应用时需要提供有效的API密钥
  4. 模型实例化:使用LangChain的ChatOpenAI类创建模型实例,能够对输入进行响应

复用提示模板

"""
# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate

# 创建原始模板
template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)

# 设置OpenAI API Key
import os
# os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'

# 导入LangChain中的OpenAI模型接口
from langchain_openai import OpenAI, ChatOpenAI

# 创建模型实例
# model = OpenAI(model_name='gpt-3.5-turbo-instruct')
model = ChatOpenAI(model=os.environ.get("LLM_MODELEND"))

# 多种花的列表
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]

# 生成多种花的文案
for flower, price in zip(flowers, prices):
    # 使用提示模板生成输入
    input_prompt = prompt.format(flower_name=flower, price=price)

    # 得到模型的输出
    output = model.invoke(input_prompt)

    # 打印输出内容
    print(output)
  1. 模块和模板来源:引入PromptTemplate模块,并创建一个用于生成文案的模板
  2. 循环处理:利用zip()函数遍历花卉和价格的组合,为每种花生成符合要求的文案
  3. 格式化输入并调用模型:通过prompt.format()生成模型输入,并使用模型实例生成文案

LangChain和提示模板的优点

  1. 代码可读性:模板使得提示文本清晰易懂,增强代码意图的表达
  2. 可复用性:一次定义,多处重用,减少代码重复,提高简洁性
  3. 易于维护:修改模板时自动更新所有引用,提升维护效率
  4. 简化变量处理:自动处理变量插入,减少拼接错误
  5. 参数化生成:根据不同输入生成个性化提示,灵活应对需求
  6. 模型切换灵活性:轻松切换模型而不需修改提示代码
  7. 一致的调用方式:提供统一接口调用不同模型,简化开发流程

输出解析

在开发具体应用的过程中,我们不仅仅需要文字,我们需要的是程序能够直接处理的、结构化的数据

通过LangChain的输出解析器来重构程序

# 导入OpenAI Key
import os

# os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'

# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate

# 创建提示模板
prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
{format_instructions}"""

# 通过LangChain调用模型
from langchain_openai import OpenAI, ChatOpenAI

# 创建模型实例
# model = OpenAI(model_name='gpt-3.5-turbo-instruct')
model = ChatOpenAI(model=os.environ.get("LLM_MODELEND"))

# 导入结构化输出解析器和ResponseSchema
from langchain.output_parsers import StructuredOutputParser, ResponseSchema

# 定义我们想要接收的响应模式
response_schemas = [
    ResponseSchema(name="description", description="鲜花的描述文案"),
    ResponseSchema(name="reason", description="问什么要这样写这个文案"),
]
# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)

# 获取格式指示
format_instructions = output_parser.get_format_instructions()
# 根据模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(
    prompt_template, partial_variables={"format_instructions": format_instructions}
)

# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]

# 创建一个空的DataFrame用于存储结果
import pandas as pd

df = pd.DataFrame(columns=["flower", "price", "description", "reason"])  # 先声明列名

for flower, price in zip(flowers, prices):
    # 根据提示准备模型的输入
    input = prompt.format(flower_name=flower, price=price)

    # 获取模型的输出
    output = model.invoke(input)
    # 解析模型的输出(这是一个字典结构)
    parsed_output = output_parser.parse(output.content)

    # 在解析后的输出中添加“flower”和“price”
    parsed_output["flower"] = flower
    parsed_output["price"] = price

    # 将解析后的输出添加到DataFrame中
    df.loc[len(df)] = parsed_output

# 打印字典
print(df.to_dict(orient="records"))

# 保存DataFrame到CSV文件
df.to_csv("flowers_with_descriptions.csv", index=False)
  1. 提示模板:使用PromptTemplate类创建用于生成鲜花描述的提示模板,包含花名和价格占位符
  2. 模型实例:通过ChatOpenAI创建OpenAI模型实例,模型名称从环境变量中获取
  3. 输出解析:定义响应模式(描述和原因),并创建结构化输出解析器,方便解析模型的输出
  4. 结果存储:使用pandas创建一个DataFrame以存储生成的描述、原因为每种鲜花及其价格

写在最后

通过使用大模型和LangChain框架,我们成功开发了一个自动生成鲜花文案的应用程序。这种方法与传统基于SQL和数据库的应用开发截然不同,因为每次运行的结果都具有随机性和创造性,展现出模型的创新潜力

LangChain的主要优势包括:

  1. 模板管理:高效管理多个提示模板,使代码更加清晰整洁
  2. 变量提取与检查:自动提取模板中的变量并进行验证,避免遗漏
  3. 模型切换:轻松尝试不同模型,只需更改模型名称,无需修改代码
  4. 输出解析:可以嵌入输出格式定义,简化后续处理

这些特性简化了开发流程,提高了代码的可维护性……无论如何,有一点毋庸置疑。我们正站在一个崭新的历史节点上。