前言

LangChain给自身的定位是:用于开发由大语言模型支持的应用程序的框架。它的做法是:通过提供标准化且丰富的模块抽象,构建大语言模型的输入输出规范,利用其核心概念chains,灵活地连接整个应用开发流程。 这里是LangChain系列的第七篇,通过实战项目:客服机器人来熟悉整个流程。

一、LangChain

1-1、介绍

LangChain是一个框架,用于开发由大型语言模型(LLM)驱动的应用程序。

LangChain 简化了 LLM 应用程序生命周期的每个阶段:

  • 开发:使用LangChain的开源构建块和组件构建应用程序。使用第三方集成和模板开始运行。
  • 生产化:使用 LangSmith 检查、监控和评估您的链条,以便您可以自信地持续优化和部署。
  • 部署:使用 LangServe 将任何链转换为 API。

总结: LangChain是一个用于开发由LLM支持的应用程序的框架,通过提供标准化且丰富的模块抽象,构建LLM的输入输出规范,主要是利用其核心概念chains,可以灵活地链接整个应用开发流程。(即,其中的每个模块抽象,都是源于对大模型的深入理解和实践经验,由许多开发者提供出来的标准化流程和解决方案的抽象,再通过灵活的模块化组合,才得到了langchain)

【LangChain系列7】【LangChain实战—客服机器人项目】-LMLPHP

1-2、LangChain抽象出来的核心模块

想象一下,如果要组织一个AI应用,开发者一般需要?

  • 提示词模板的构建,不仅仅只包含用户输入!
  • 模型调用与返回,参数设置,返回内容的格式化输出。
  • 知识库查询,这里会包含文档加载,切割,以及转化为词嵌入(Embedding)向量。
  • 其他第三方工具调用,一般包含天气查询、Google搜索、一些自定义的接口能力调用。
  • 记忆获取,每一个对话都有上下文,在开启对话之前总得获取到之前的上下文吧?

LangChain通过模块化的方式去高级抽象LLM在不同场景下的能力,其中LangChain抽象出的最重要的核心模块如下:

  • Model I/O :标准化各个大模型的输入和输出,包含输入模版,模型本身和格式化输出;
  • Retrieval :检索外部数据,然后在执行生成步骤时将其传递到 LLM,包括文档加载、切割、Embedding等;
  • Chains :链条,LangChain框架中最重要的模块,链接多个模块协同构建应用,是实际运作很多功能的高级抽象;
  • Memory : 记忆模块,以各种方式构建历史信息,维护有关实体及其关系的信息;
  • Agents : 目前最热门的Agents开发实践,未来能够真正实现通用人工智能的落地方案;
  • Callbacks :回调系统,允许连接到 LLM 应用程序的各个阶段。用于日志记录、监控、流传输和其他任务;

1-3、特点

LangChain的特点如下:

  • 大语言模型(llm): LangChain为自然语言处理提供了不同类型的模型,这些模型可用于处理非结构化文本数据,并且可以基于用户的查询检索信息

  • PromptTemplates: 这个特征使开发人员能够使用多个组件为他们的模型构造输入提示。在查询时,开发人员可以使用PromptTemplates为用户查询构造提示模板,之后模板会传递到大模型进行进一步的处理。

  • :在LangChain中,链是一系列模型,它们被连接在一起以完成一个特定的目标。聊天机器人应用程序的链实例可能涉及使用LLM来理解用户输入,使用内存组件来存储过去的交互,以及使用决策组件来创建相关响应。

  • agent: LangChain中的agent与用户输入进行交互,并使用不同的模型进行处理。Agent决定采取何种行动以及以何种顺序来执行行动。例如,CSV Agent可用于从CSV文件加载数据并执行查询,而Pandas Agent可用于从Pandas数据帧加载数据并处理用户查询。可以将代理链接在一起以构建更复杂的应用程序。

【LangChain系列7】【LangChain实战—客服机器人项目】-LMLPHP

1-4、langchain解决的一些行业痛点

在使用大模型的过程中,一些行业痛点:

  • 大模型的使用规范以及基于大模型的开发范式不尽相同,当使用一个新模型时,我们往往需要学习新的模型规范。
  • 大模型知识更新的滞后性
  • 大模型的外部API调用能力
  • 大模型输出的不稳定问题,如何稳定输出?
  • 大模型与私有化数据的连接方式?

1-5、安装

pip install langchain

二、基于LangChain的客服机器人实战

2-1、依赖安装

faiss: 向量搜索工具,如果有GPU的话,可以安装GPU版本,这里使用的是CPU版本。

pip install pandas
pip install openpyxl
pip install langchain
pip install -U langchain-community
pip install sentence-transformers
pip install faiss-cpu
pip install pyjwt

2-2、数据加载

数据加载: 这里使用的是财经类数据

import pandas as pd

file_path = 'SmoothNLP专栏资讯数据集样本10k.xlsx'
# 使用pandas读取xlsx文件
data = pd.read_excel(file_path)[:50]
data

输出:
【LangChain系列7】【LangChain实战—客服机器人项目】-LMLPHP

2-3、使用langchain对文档进行分割

文档分割: 这里使用的是较为简单的文档分割方法,即一行内容当作一块检索内容。

from langchain.schema import Document

# 逐行处理数据并创建Document对象
documents = []
for index, row in data.iterrows():
    title = row['title']
    content = row['content']
    combined_text = f"{title}\n{content}"
    
    # 创建Document对象
    document = Document(page_content=combined_text)
    
    # 将Document对象添加到列表中
    documents.append(document)

# 现在,documents列表包含了所有的Document对象,可以用于后续的处理
documents[1]

输出:
【LangChain系列7】【LangChain实战—客服机器人项目】-LMLPHP
更加通用的一种写法: 这里主要是没有写死列名,而是通过column_names 来更加灵活的获取列名。

column_names = data.columns.tolist()
documents = []
for index, row in data.iterrows():
    combined_text = ""
    # 遍历每一列,将列名和对应的值拼接成字符串
    for column in column_names:
        value = row[column]
        # 将列名和值拼接,可以用换行符或其他分隔符分隔
        combined_text += f"{column}: {value}\n"
    # 创建Document对象
    document = Document(page_content=combined_text)
    # 将Document对象添加到列表中
    documents.append(document)
documents[1]

2-4、使用Faiss进行向量搜索

2-4-1、使用相似性搜索similarity_search

向量搜索: 这里使用HuggingFaceEmbeddings来进行文档的编码,使用Faiss来进行向量的检索,也可以尝试换其他常用的工具。

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS

embeddings = HuggingFaceEmbeddings()
db = FAISS.from_documents(documents, embeddings)
query = "双11广告我应该怎么打?"
docs = db.similarity_search(query)
docs

输出:
【LangChain系列7】【LangChain实战—客服机器人项目】-LMLPHP

2-4-2、使用相似性分数(similarity_score_threshold)进行检索

# 实例化一个 similarity_score_threshold Retriever
retriever = db.as_retriever(
    search_type="similarity_score_threshold",
    search_kwargs={"score_threshold": 0.8}
)
docs = retriever.get_relevant_documents("苏宁618")
for doc in docs:
    print(doc.page_content + "\n")

2-4-3、FAISS向量数据库结果的存储以及加载

# 存储
db.save_local("real_estates_sale")

# 加载
db = FAISS.load_local("real_estates_sale", embeddings)

2-4-4、数据库检索&LLM(借用大模型的能力)

数据库检索&LLM: LLM参考检索的内容来对用户的提问做出回答。
create_stuff_documents_chain: create_stuff_documents_chain 是 LangChain 提供的一个函数,它用于创建一个链,这个链可以将一系列文档(Documents)格式化为一个提示(prompt),并将这个提示传递给一个语言模型(LLM)。这个函数非常适合于需要将多个文档内容作为上下文传递给模型的场景,例如问答系统和文本摘要等任务。

以下是 create_stuff_documents_chain 的一些关键参数和它们的用途:

  • llm:这是你要使用的运行时语言模型,可以是任何实现了 Runnable 接口的模型。
  • prompt:这是一个 BasePromptTemplate 对象,它定义了如何格式化传递给模型的输入。这个模板中必须包含一个名为 - context 的变量(或者你可以设置 document_variable_name 来指定一个不同的变量名),用于传递格式化后的文档内容。
  • output_parser:这是一个可选参数,用于解析模型的输出。如果不设置,将使用默认的 StrOutputParser。
  • document_prompt:这是一个可选的 BasePromptTemplate 对象,用于格式化每个单独的文档为字符串。这个模板可以访问文档的 page_content 或任何在所有文档中都存在的元数据键。
  • document_separator:这是一个字符串,用于在格式化后的文档字符串之间添加分隔符。默认为 \n\n。
  • document_variable_name:这是用于在提示中引用格式化后的文档内容的变量名。默认为 context。

用chain的概念来介绍: 用户输入内容后,先进行向量检索,得到相应的上下文context,之后上下文嵌入到提示词模板 ChatPromptTemplate()中去,得到一个完整的提示,这里我们使用的大模型为质谱AI,GLM4,完整提示进入大模型,得到响应,最后通过输出规范,StrOutputParser()。

context | ChatPromptTemplate() | ChatZhipuAI | StrOutputParser()

Demo如下所示:

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.chat_models import ChatZhipuAI
import os

os.environ["ZHIPUAI_API_KEY"] = ""
llm = ChatZhipuAI(
    model="glm-4",
    temperature=0.5,
)

system_prompt = (
    "Use the given context to answer the question. "
    "If you don't know the answer, say you don't know. "
    "Use three sentence maximum and keep the answer concise. "
    "Context: {context}"
)
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        ("human", "{input}"),
    ]
)
question_answer_chain = create_stuff_documents_chain(llm, prompt)
chain = create_retrieval_chain(db.as_retriever(search_type="similarity_score_threshold",
                                                         search_kwargs={"score_threshold": 0.2}), 
                               question_answer_chain)
chain.invoke({"input": query})

输出: 输出的主要成分为Input、检索到的上下文内容、以及LLM参考上下文回复用户的answer。
【LangChain系列7】【LangChain实战—客服机器人项目】-LMLPHP

参考文章:

langchain_community.utilities.sql_database.SQLDatabase
LangChain 🦜️🔗 中文网,跟着LangChain一起学LLM/GPT开发
LangChain官网
Rebuff: 防止提示词注入检测器

未完成:
Build a Question/Answering system over SQL data
langchain101 AI应用开发指南
Langchain官方文档tavily_search搜索工具

总结

🪽茶之初,香浓如墨;久而淡,清雅若兰。

11-16 00:15