Pycharm logo

PyCharm

The Python IDE for data science and web development

Data Science How-To's

如何使用 LangChain 构建聊天机器人

Read this post in other languages:

本文是深度学习工程师兼 Python 程序员 Dido Grigorov 撰写的客座文章,他在业界拥有 17 年经验。

聊天机器人的发展已经远远超出单纯问答工具的范畴。 借助大语言模型 (LLM) 的强大功能,它们可以理解对话上下文并生成类似人类的回复,因此对于客户支持应用程序和其他类型的虚拟辅助非常有用。 

LangChain 是一个开源框架,通过为无缝模型集成、上下文管理和提示工程提供工具,简化了构建这些对话式聊天机器人的过程。

在这篇博文中,我们将探讨 LangChain 的运作方式以及聊天机器人与 LLM 的交互方式。 我们还将逐步指导您构建一个上下文感知聊天机器人,这个聊天机器人使用 LangChain 和 GPT-3 提供准确、相关的回答。

什么是 LLM 领域中的聊天机器人?

LLM 领域中的聊天机器人是通过文本或语音接口模拟与用户进行类似人类对话的尖端软件。 这些聊天机器人利用了 LLM 的高级功能,LLM 是使用大量文本数据训练的神经网络,可对各种输入提示做出类似人类的回答。

基于 LLM 的聊天机器人在生成回答时可以考虑对话的上下文。 这意味着它们可以在多段对话中保持一致,并且可以处理复杂的查询以生成符合用户意图的输出。 此外,这些聊天机器人还能评估用户输入的情感基调,并根据用户的情绪调整回答。

聊天机器人具有很强的适应能力和很高的个性化程度。 它们从用户交互中学习,根据用户个人喜好和需求调整和改进回答。 

什么是 LangChain?

LangChain 是一个开源框架,用于创建使用大语言模型 (LLM) 的应用。 它附带工具和抽象,以更好地个性化这些模型生成的信息,同时保持准确性和相关性。 

阅读 LLM 相关文章时,您经常会看到“提示链”这个术语。 提示链是指在人工智能和机器学习中使用的一系列提示或指令,目的是引导 AI 模型通过多步骤流程生成更准确、更详细或更精细的输出。 这种方法可用于各种任务,例如写作、问题解决或代码生成。 

开发者可以使用 LangChain 创建新的提示链,这是该框架最强大的功能之一。 他们甚至可以修改现有提示模板,无需在使用新数据集时再次训练模型。

LangChain 如何运作?

LangChain 框架旨在简化利用语言模型的应用程序的开发。 它提供了一套工具,帮助开发者有效构建和管理涉及自然语言处理 (NLP) 和大语言模型的应用程序。 通过定义实现预期结果(可以是聊天机器人、任务自动化、虚拟助手、客户支持等)所需的步骤,开发者可以使用 LangChain 灵活调整语言模型,适应具体业务环境。 

以下是 LangChain 运作方式的总体概览。

模型集成

LangChain 支持多种语言模型,包括 OpenAI、Hugging Face、Cohere、Anyscale、Azure Models、Databricks、Ollama、Llama、GPT4All、Spacy、Pinecone、AWS Bedrock、MistralAI 等。 开发者可以在不同模型之间轻松切换,也可以在一个应用程序中使用多个模型。 他们可以构建定制开发的模型集成解决方案,利用针对其具体应用程序定制的特定功能。

LangChain 的核心概念是,它将不同的 AI 组件整合在一起,实现上下文感知回答。 链代表用户提示和最终模型输出之间的一组自动化操作。 LangChain 提供了两种类型的链:

  • 序列链:这些链使一个模型或函数的输出可以用作另一个模型或函数的输入。 这对于制作相互依赖的多步骤流程特别有用。
  • 并行链:它支持同时运行多个任务,并在最后合并输出。 非常适合执行可以分为完全独立的子任务的任务。

内存

LangChain 能够促进各种交互中信息的存储和检索。 在需要持久保存上下文时,例如在聊天机器人或交互式代理中,这一点至关重要。 另外还提供两种类型的记忆:

  • 短期记忆 – 有助于跟踪最近的会话。
  • 长期记忆 – 允许保留先前会话的信息,增强系统对过去聊天和用户偏好的回忆能力。

工具和实用程序

LangChain 提供了很多工具,但最常用的是 Prompt Engineering、Data Loaders 和 Evaluators。  在 Prompt Engineering 方面,LangChain 包含用于开发良好提示的实用程序,这对于从语言模型中获得最佳回答非常重要。

如果要加载 csv、pdf 或其他格式的文件,Data Loaders 可以帮助您加载和预处理不同类型的数据,使其可用于模型交互。

在使用机器学习模型和大语言模型时,评估是至关重要的一环。 为此,LangChain 提供了 Evaluators – 这个工具用于测试语言模型和链,使生成的结果满足所需标准,其中可能包括:

数据集标准:

  • 手动精选样本:从高质量、多样化的输入开始。
  • 历史日志:使用真实的用户数据和反馈。
  • 合成数据:根据初始数据生成样本。

评估类型:

  • 人工:手动评分和反馈。
  • 启发式:基于规则的函数,包括无引用的函数和基于引用的函数。
  • LLM 评判:LLM 根据编码标准对输出进行评分。
  • 成对:比较两个输出,选择更好的一个。

应用程序评估:

  • 单元测试:快速、基于启发式的检查。
  • 回归测试:衡量性能在一段时间内的变化。
  • 回溯测试:在新版本上重新运行生产数据。
  • 在线评估:实时评估,通常用于防护机制和分类。

代理
LangChain 代理本质上是自主实体,利用 LLM 与用户交互、执行任务并根据自然语言输入做出决策。

以操作为基础的代理使用语言模型来决定预定义任务的最佳操作。 另一方面,交互式代理或聊天机器人等交互式应用程序利用这些代理,在响应查询时也会考虑用户输入和存储的记忆。

聊天机器人如何与 LLM 配合运作?

聊天机器人所依赖的 LLM 使用自然语言理解 (NLU) 和自然语言生成 (NLG),NLU 和 NLG 则基于使用大量文本数据的预训练。

自然语言理解 (NLU)

  • 上下文感知:LLM 可以理解对话中的细微差别和暗示,并且可以跟踪对话的进展。 这使聊天机器人能够为客户生成合乎逻辑且符合上下文的回答。
  • 意图识别:这些模型应该能够从查询中理解用户的意图,无论语言是非常具体还是相当笼统。 它们可以辨别用户想要实现的目标,并确定帮助用户实现目标的最佳方式。
  • 情绪分析:聊天机器人可以通过所用语言的语气判断用户的情感,并适应用户的情感状态,从而增加用户参与度。

自然语言生成 (NLG)

  • 回答生成:被问到问题时,LLM 能够提供在语法和上下文方面都正确的回答。 这是因为这些模型生成的回答模仿了人类的交流,基于模型在大量自然语言文本数据上进行的训练。
  • 创意和灵活性:除了简单的回答之外,基于 LLM 的聊天机器人还可以讲故事、创作诗歌或提供特定技术问题的详细描述,因此在提供的材料方面可以被认为非常灵活。

个性化和适应性

  • 从交互中学习:聊天机器人使交互个性化,因为它们能够从用户的行为以及选择中学习。 可以说它是在不停地学习,因此使聊天机器人能够更有效、更准确地回答问题。
  • 适应不同领域:LLM 可以针对特定领域或专业进行调整,这使聊天机器人能够成为客户关系、技术支持或医疗领域的主题专家。

LLM 能够理解和生成多种语言的文本,使其适合在不同语言上下文中应用。

通过五个步骤使用 LangChain 构建您自己的聊天机器人

这个项目旨在构建一个利用 GPT-3 在文档中搜索答案的聊天机器人。 首先,我们从在线文章中抓取内容,将其分成小块,计算它们的嵌入向量,然后将其存储在 Deep Lake 中。 接下来,我们使用用户查询从 Deep Lake 中检索最相关的块,这些块被合并到提示中,用于通过 LLM 生成最终答案。

注意,使用 LLM 可能会产生幻觉或虚假信息。 虽然这在许多客户支持场景中可能无法接受,但聊天机器人仍然可以协助操作员起草答案,在发送给用户之前由操作员验证。

接下来,我们将探讨如何管理与 GPT-3 的对话,并提供示例证明此工作流的有效性。

第 1 步:项目创建、先决条件和必需库安装

首先,为聊天机器人创建 PyCharm 项目。 打开 PyCharm,点击 New project(新建项目)。 然后,给您的项目命名。

创建 PyCharm 项目

设置项目,然后登录(或在 OpenAI 网站上注册),在 OpenAI API 平台网站上生成您的 ‘OPENAI_API_KEY‘。 为此,转到左侧导航菜单上的 API Keys(API 密钥)部分,点击按钮 +Create new secret key(+创建新密钥)。 别忘了复制密钥。

接下来,在 Activeloop 网站上注册,获取 ‘ACTIVELOOP_TOKEN‘。 登录后,点击 Create API Token(创建 API 令牌)按钮,导航到令牌创建页面。 也复制这个令牌。

获得令牌和密钥后,在 PyCharm 中打开配置设置,点击运行和调试按钮旁边的 3 点按钮,然后选择 Edit(编辑)。 您应该看到以下窗口:

PyCharm 中的运行/调试配置

现在,前往 Environment variables(环境变量)字段并找到字段右侧的图标。 然后点击,您将看到以下窗口:

PyCharm 中的环境变量

现在,点击 + 按钮,开始添加环境变量,并注意它们的名称。 它们应该与上文相同:’OPENAI_API_KEY‘ 和 ‘ACTIVELOOP_TOKEN‘。 准备就绪后,在第一个窗口中点击 OK(确定),然后在第二个窗口中点击 Apply(应用)和 OK(确定)。

这是 PyCharm 的一个巨大优势,我非常喜欢,因为它可以自动为我们处理环境变量,不需要额外调用,让我们可以更多地考虑代码的创意部分。

Activeloop 是一家专注于开发机器学习和人工智能数据基础架构与工具的科技公司。 这家公司的目标是简化管理、存储和处理大规模数据集的流程,特别是在深度学习和其他 AI 应用中。

Deep Lake 是 Activeloop 的旗舰产品。 它提供高效的数据存储、管理和访问功能,针对 AI 中经常使用的大规模数据集进行了优化。

安装必需

我们将使用 LangChain 中的 ‘SeleniumURLLoader‘ 类,它依赖于 ‘unstructured‘ 和 ‘selenium‘ Python 库。 使用 pip 进行安装。  建议安装最新版本,虽然代码已经在 0.7.7 版本上进行过专门测试。 

为此,在 PyCharm 终端中使用以下命令:

pip install unstructured selenium

现在,我们需要安装 langchaindeeplakeopenai。 为此,只需在终端(与用于 Selenium 的窗口相同)中使用此命令,然后等待一段时间,直到安装完全成功:

pip install langchain==0.0.208 deeplake openai==0.27.8 psutil tiktoken

为了确保所有库都正确安装,添加我们的聊天机器人应用需要的以下行,然后点击 Run(运行)按钮:

from langchain.embeddings.openai import OpenAIEmbeddings

from langchain.vectorstores import DeepLake

from langchain.text_splitter import CharacterTextSplitter

from langchain import OpenAI

from langchain.document_loaders import SeleniumURLLoader

from langchain import PromptTemplate

安装库的另一种方式是通过 PyCharm 的设置。 打开设置,转到 Project -> Python Interpreter(项目 -> Python 解释器)部分。 然后,找到 + 按钮,搜索您的软件包,点击 Install Package(安装软件包)按钮。 准备好后,将其关闭,在下一个窗口中点击 Apply(应用),然后点击 OK(确定)。

PyCharm 中的 Python 解释器

第 2 步:将内容分块并计算其嵌入向量

如前所述,我们的聊天机器人将与来自在线文章的内容“交流”,因此,我将 Digitaltrends.com 用作数据来源并选择了 8 篇文章。 文章全部组织成一个 Python 列表,并被指定给名为“articles”的变量。

articles = ['https://www.digitaltrends.com/computing/claude-sonnet-vs-gpt-4o-comparison/',
           'https://www.digitaltrends.com/computing/apple-intelligence-proves-that-macbooks-need-something-more/',
           'https://www.digitaltrends.com/computing/how-to-use-openai-chatgpt-text-generation-chatbot/',
           'https://www.digitaltrends.com/computing/character-ai-how-to-use/',
           'https://www.digitaltrends.com/computing/how-to-upload-pdf-to-chatgpt/']

我们从提供的 URL 加载文档,并使用 ‘CharacterTextSplitter‘ 将其分块,块大小为 1000 且没有重叠:

# Use the selenium to load the documents
loader = SeleniumURLLoader(urls=articles)
docs_not_splitted = loader.load()

# Split the documents into smaller chunks
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(docs_not_splitted)

如果一切顺利,到现在为止运行代码应该会收到以下输出:

[Document(page_content="techcrunchnntechcrunchnnWe, TechCrunch, are part of the Yahoo family of brandsThe sites and apps that we own and operate, including Yahoo and AOL, and our digital advertising service, Yahoo Advertising.Yahoo family of brands.nn    When you use our sites and apps, we use nnCookiesCookies (including similar technologies such as web storage) allow the operators of websites and apps to store and read information from your device. Learn more in our cookie policy.cookies to:nnprovide our sites and apps to younnauthenticate users, apply security measures, and prevent spam and abuse, andnnmeasure your use of our sites and appsnn    If you click '", metadata={'source': ……………]

接下来,我们使用 OpenAIEmbeddings 生成嵌入向量并将其保存在托管在云端的 Deep Lake 向量存储中。 理想情况下,在生产环境中,我们可以将整个网站或课程上传到 Deep Lake 数据集,从而实现对数千甚至数百万个文档的搜索。 

利用云端的无服务器 Deep Lake 数据集,来自不同位置的应用程序可以无缝访问集中数据集,而无需在专用机器上设置向量存储。

为什么需要块中的嵌入向量和文档?

使用 LangChain 构建聊天机器人时,嵌入向量和分块文档至关重要,其中的原因与聊天机器人的效率、准确性和性能有关。

嵌入向量是捕捉语义的文本(单词、句子、段落或文档)的向量表示。 它们以数字形式封装单词的上下文和含义。 通过捕捉细微差别、同义词和单词之间的关系,这使聊天机器人能够理解并生成适合上下文的回答。

得益于嵌入向量,聊天机器人还可以快速识别和检索知识库中最相关的回答或信息,因为它们允许将用户查询与语义上最相关的信息块进行匹配,即使措辞不同。

分块则涉及将大文档分成更小、易于管理的块。 与大型、单一文档相比,更小的块可以更快地处理和分析。 这使聊天机器人的回答时间更短。

文档分块也有助于提高输出的相关性,因为当用户提出问题时,它通常只出现在文档的特定部分中。 分块可以让系统精确定位并检索相关部分,使聊天机器人提供更精确、更准确的答案。

现在,我们回到我们的应用程序,添加 Activeloop 组织 ID 来更新以下代码。 注意,默认情况下,您的组织 ID 和您的用户名相同。

# TODO: use your organization id here. (by default, org id is your username)
my_activeloop_org_id = "didogrigorov"
my_activeloop_dataset_name = "jetbrains_article_dataset"
dataset_path = f"hub://{my_activeloop_org_id}/{my_activeloop_dataset_name}"
db = DeepLake(dataset_path=dataset_path, embedding_function=embeddings)


# add documents to our Deep Lake dataset
db.add_documents(docs)

PyCharm 另一个很棒的功能是可以直接在 Python 注释中添加 TODO 备注的选项。 使用大写字母输入 TODO 时,所有注释都会进入 PyCharm 的一个部分:

# TODO: use your organization id here. (by default, org id is your username)

点击后,PyCharm 会直接显示它们在代码中的位置。 我发现这对开发者来说非常方便,并且一直在使用:

PyCharm 中 Python 注释中的 TODO 备注

如果一切正常,到现在为止运行代码应该会收到以下输出:

PyCharm 中的聊天机器人代码执行

为了找到与给定查询最相似的块,我们可以利用 Deep Lake 向量存储提供的 similarity_search 方法:

# Check the top relevant documents to a specific query
query = "how to check disk usage in linux?"
docs = db.similarity_search(query)
print(docs[0].page_content)

第 3 步:构建 GPT-3 的提示

我们将设计一个集成角色提示、相关知识库数据和用户查询的提示模板。 此模板将聊天机器人的形象确立为出色的客户支持代理。 它接受两个输入变量:chunks_formatted(包含文章的预格式化摘录)和 query(代表客户的问题)。 目标是仅根据给定块产生精确的回答,避免任何虚假或不正确的信息。

第 4 步:构建聊天机器人功能

为了生成回答,我们首先检索与用户查询最相似的前 k 个(例如前 3 个)块。 然后这些块被格式化为提示,并发送到温度设置为 0 的 GPT-3 模型。

# user question
query = "How to check disk usage in linux?"

# retrieve relevant chunks
docs = db.similarity_search(query)
retrieved_chunks = [doc.page_content for doc in docs]

# format the prompt
chunks_formatted = "nn".join(retrieved_chunks)
prompt_formatted = prompt.format(chunks_formatted=chunks_formatted, query=query)

# generate answer
llm = OpenAI(model="gpt-3.5-turbo-instruct", temperature=0)
answer = llm(prompt_formatted)
print(answer)

如果一切正常,您的输出应该是:

To upload a PDF to ChatGPT, first log into the website and click the paperclip icon next to the text input field. Then, select the PDF from your local hard drive, Google Drive, or Microsoft OneDrive. Once attached, type your query or question into the prompt field and click the upload button. Give the system time to analyze the PDF and provide you with a response.

第 5 步:建立对话历史

# Create conversational memory
memory = ConversationBufferMemory(memory_key="chat_history", input_key="input")

# Define a prompt template that includes memory
template = """You are an exceptional customer support chatbot that gently answers questions.

{chat_history}

You know the following context information.

{chunks_formatted}

Answer the following question from a customer. Use only information from the previous context information. Do not invent stuff.

Question: {input}

Answer:"""

prompt = PromptTemplate(
    input_variables=["chat_history", "chunks_formatted", "input"],
    template=template,
)

# Initialize the OpenAI model
llm = OpenAI(openai_api_key="YOUR API KEY", model="gpt-3.5-turbo-instruct", temperature=0)

# Create the LLMChain with memory
chain = LLMChain(
    llm=llm,
    prompt=prompt,
    memory=memory
)

# User query
query = "What was the 5th point about on the question how to remove spotify account?"

# Retrieve relevant chunks
docs = db.similarity_search(query)
retrieved_chunks = [doc.page_content for doc in docs]

# Format the chunks for the prompt
chunks_formatted = "nn".join(retrieved_chunks)

# Prepare the input for the chain
input_data = {
    "input": query,
    "chunks_formatted": chunks_formatted,
    "chat_history": memory.buffer
}

# Simulate a conversation
response = chain.predict(**input_data)

print(response)

我们用更具对话性的方式讲解代码。

首先,使用 ‘ConversationBufferMemory‘ 设置对话记忆。 这使聊天机器人能够记住当前聊天历史,使用 ‘input_key=”input”‘ 管理传入用户输入。

接下来,我们设计一个提示模板。 这个模板就像是聊天机器人的脚本,包括聊天历史部分、我们收集的信息块以及当前用户问题(输入)。 这种结构可以帮助聊天机器人准确了解上下文以及需要回答什么问题。

然后,我们继续初始化语言模型链或 ‘LLMChain‘。 这就像组装组件一样:选择提示模板、语言模型和先前设置的记忆,把它们组合成一个工作流。

需要处理用户查询时,我们准备输入。 这涉及创建包含用户问题 (‘input‘) 和相关信息块 (‘chunks_formatted‘) 的字典。 这种设置可以确保聊天机器人掌握它需要的所有详细信息,做出有意义的回答。

最后,我们生成一个回答。 调用 ‘chain.predict‘ 方法,传入我们准备好的输入数据。 该方法通过我们构建的工作流处理此输入,输出聊天机器人的回答,然后我们将其显示出来。

由此,我们的聊天机器人能够保持顺畅、有意义的对话,记住过去的互动并根据上下文提供相关答案。

PyCharm 中另一个我最喜欢的技巧是将光标放在方法上,按 CTRL 键并点击,这对我创建这个功能帮助很大。

将光标放在方法上

结论

GPT-3 擅长创建能够根据提示中提供的上下文信息回答特定问题的对话式聊天机器人。 不过,确保模型仅基于这种上下文生成答案可能具有挑战性,因为它往往会产生幻觉(即生成新的、可能错误的信息)。 此类虚假信息的影响因用例而异。

总之,我们按照提供的代码和策略,使用 LangChain 开发了一个上下文感知问答系统。 流程包括将文档分块、计算嵌入向量、实现检索器以查找相似的块、为 GPT-3 构建提示,以及使用 GPT-3 模型进行文本生成。 这种方式展现了利用 GPT-3 创建强大且上下文准确的聊天机器人的潜力,同时也强调了警惕生成虚假信息风险的重要性。

作者简介

Dido Grigorov

Dido Grigorov

Dido 是一位经验丰富的深度学习工程师和 Python 程序员,在该领域拥有 17 年经验。 他目前正在著名的斯坦福大学攻读高级学位,并参加了一项由吴恩达、Christopher Manning、李飞飞和 Chelsea Finn 等知名专家领导的尖端 AI 项目。从这个项目中,Dido 获得了宝贵的见解和指导。

Dido 对工作和实验的投入展现了他对人工智能的热情。 多年来,他在设计、实现和优化机器学习模型方面积累了深厚的专业知识。 他精通 Python,能够解决复杂问题并为多种领域的创新 AI 解决方案做出贡献。

image description

Discover more