使用 LangChain 和 Pinecone 矢量数据库构建自定义问答应用程序

简介: 本文介绍了如何使用 LangChain、OpenAI 和 PineconeDB 构建自定义聊天机器人,并开发基于任意数据源的问答应用。内容涵盖语义搜索管道构建、数据存储与检索,以及如何在 Streamlit Cloud 上部署应用。适合希望利用大语言模型解决实际问题的开发者和企业。

构建自定义聊天机器人,以使用 LangChain、OpenAI 和 PineconeDB 从任何数据源开发问答应用程序

介绍

大型语言模型的出现是我们这个时代最令人兴奋的技术发展之一。它为人工智能领域开辟了无限可能,为各行业的现实问题提供了解决方案。这些模型最有趣的应用之一是开发来自个人或组织数据源的自定义问答或聊天机器人。然而,由于LLMS接受的是公开可用的一般数据的培训,因此他们的答案可能并不总是具体或对最终用户有用。为了解决这个问题,我们可以使用LangChain等框架来开发自定义聊天机器人,根据我们的数据提供特定的答案。在本文中,我们将学习如何构建自定义问答应用程序并部署在 Streamlit Cloud 上。那么让我们开始吧!

学习目标:

  • 了解为什么自定义问答应用程序比微调语言模型更好
  • 学习使用 OpenAI 和 Pinecone 开发语义搜索管道
  • 开发自定义问答应用程序并将其部署在 Streamlit 云上。

目录:

  • 问答应用概述
  • 什么是 Pinecone 矢量数据库?
  • 使用 OpenAI 和 Pinecone 构建语义搜索管道
  • 带 Streamlit 的自定义问答应用程序
  • 结论
  • 常见问题解答

问答应用概述

问答或“通过数据聊天”是LLMs 和 LangChain 的一个流行用例。LangChain 提供了一系列组件来加载您可以为您的用例找到的任何数据源。它支持大量数据源和转换器转换为一系列字符串以存储在矢量数据库中。一旦数据存储在数据库中,就可以使用称为检索器的组件查询数据库。此外,通过使用LLMS,我们可以像聊天机器人一样获得准确的答案,而无需处理大量文档。

LangChain支持以下数据源。如图所示,它允许超过 120 个集成来连接您可能拥有的每个数据源。

问答应用程序工作流程

我们了解了LangChain支持的数据源,这使我们能够使用LangChain中可用的组件开发问答管道。以下是 LLM 用于文档加载、存储、检索和生成输出的组件。

  • 文档加载器:加载用户文档以进行矢量化和存储
  • 文本分割器:这些是文档转换器,可将文档转换为固定的块长度以有效地存储它们
  • 矢量存储:矢量数据库集成,用于存储输入文本的矢量嵌入
  • 文档检索:根据用户对数据库的查询来检索文本。他们使用相似性搜索技术来检索相同的内容。
  • 模型输出:根据查询的输入提示和检索到的文本生成的用户查询的最终模型输出。

这是问答管道的高级工作流程,可以解决多种类型的现实问题。我没有深入研究每个 LangChain 组件

自定义问答相对于模型微调的优势

  • 针对具体情况的答案
  • 适应新的输入文档
  • 无需对模型进行微调,节省模型训练成本
  • 比一般答案更准确和具体的答案

什么是Pinecone 矢量数据库?

Pinecone

Pinecone 是一种流行的矢量数据库,用于构建 LLM 支持的应用程序。它具有多功能性和可扩展性,适用于高性能人工智能应用。它是一个完全托管的云原生矢量数据库,不会给用户带来任何基础设施麻烦。

LLMS基础应用程序涉及大量非结构化数据,需要复杂的长期记忆才能以最大准确度检索信息。生成式人工智能应用程序依靠向量嵌入的语义搜索来根据用户输入返回合适的上下文。

Pinecone 非常适合此类应用程序,并经过优化以低延迟存储和查询大量向量,以构建用户友好的应用程序。让我们学习如何为我们的问答应用程序设置松果矢量数据库。

# install pinecone-client
 pip install pinecone-client 
# 导入 pinecone 并使用您的 API 密钥和环境名称进行初始化
import pinecone 
pinecone.init(api_key= "YOUR_API_KEY" ,environment= "YOUR_ENVIRONMENT" ) 
# 创建您的第一个索引以开始存储Vectors
 pinecone.create_index( "first_index" ,Dimension= 8 , metric= "cosine" ) 
# 更新插入样本数据(5个8维向量)
 index.upsert([ 
    ( "A" , [ 0.1 , 0.1 , 0.1 , 0.1 , 0.1 ) , 0.1 , 0.1 , 0.1 ]), 
    ( "B" , [ 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 ]), 
    ( "C" , [ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ]), 
    ( "D" , [ 0.4 , 0.4 , 0.4 , 0.4 , 0.4 , 0.4 , 0.4 , 0.4 ]), 
    ( "E" , [ 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 ]) 
]) 
# 使用 list_indexes() 方法调用 db 中可用的多个索引
pinecone.list_indexes() 
[Output]>>> [ 'first_index' ]

在上面的演示中,我们安装了一个pinecone客户端来初始化我们项目环境中的矢量数据库。初始化向量数据库后,我们可以创建具有所需维度和度量的索引,以将向量嵌入插入到向量数据库中。在下一节中,我们将使用 Pinecone 和 LangChain 为我们的应用程序开发语义搜索管道。

使用 OpenAI 和 Pinecone 构建语义搜索管道

我们了解到问答应用程序工作流程有 5 个步骤。在本节中,我们将执行前 4 个步骤,即文档加载器、文本拆分器、向量存储和文档检索。

要在本地环境或云基础笔记本环境(例如 Google Colab)中执行这些步骤,您需要安装一些库并在 OpenAI 和 Pinecone 上创建一个帐户以分别获取它们的 API 密钥。让我们从环境设置开始:

安装所需的库

# install langchain and openai with other dependencies
!pip install --upgrade langchain openai -q
!pip install pillow==6.2.2
!pip install unstructured -q
!pip install unstructured[local-inference] -q
!pip install detectron2@git+https://github.com/facebookresearch/detectron2.git@v0.6#egg=detectron2 -q
!apt-get install poppler-utils
!pip install pinecone-client -q
!pip install tiktoken -q
# setup openai environment
import os
os.environ["OPENAI_API_KEY"] = "YOUR-API-KEY"
# importing libraries
import os
import openai
import pinecone
from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Pinecone
from langchain.llms import OpenAI
from langchain.chains.question_answering import load_qa_chain

安装设置完成后,导入上述代码片段中提到的所有库。然后,按照以下步骤操作:

加载文档

在此步骤中,我们将从目录加载文档作为 AI 项目管道的起点。我们的目录中有 2 个文档,我们将把它们加载到项目环境中。

#load the documents from content/data dir
directory = '/content/data'
# load_docs functions to load documents using langchain function
def load_docs(directory):
  loader = DirectoryLoader(directory)
  documents = loader.load()
  return documents
documents = load_docs(directory)
len(documents)
[Output]>>> 5

分割文本数据

如果每个文档的长度固定,文本嵌入和LLMS的性能会更好。因此,对于任何LLMS用例来说,将文本分割成相等长度的块是必要的。我们将使用“RecursiveCharacterTextSplitter”将文档转换为与文本文档相同的大小。

# split the docs using recursive text splitter
def split_docs(documents, chunk_size=200, chunk_overlap=20):
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
  docs = text_splitter.split_documents(documents)
  return docs
# split the docs
docs = split_docs(documents)
print(len(docs))
[Output]>>>12

将数据存储在向量存储中

一旦文档被分割,我们将使用 OpenAI 嵌入将它们的嵌入存储在向量数据库中。

# embedding example on random word
embeddings = OpenAIEmbeddings()
# initiate pinecondb
pinecone.init(
    api_key="YOUR-API-KEY",
    environment="YOUR-ENV"
)
# define index name
index_name = "langchain-project"
# store the data and embeddings into pinecone index
index = Pinecone.from_documents(docs, embeddings, index_name=index_name)

从向量数据库中检索数据

在此阶段,我们将使用语义搜索从矢量数据库中检索文档。我们将向量存储在名为“langchain-project”的索引中,一旦我们查询到与下面相同的内容,我们就会从数据库中获得最相似的文档。

# An example query to our database
query = "What are the different types of pet animals are there?"
# do a similarity search and store the documents in result variable 
result = index.similarity_search(
    query,  # our search query
    k=3  # return 3 most relevant docs
)
-
--------------------------------[Output]--------------------------------------
result
[Document(page_content='Small mammals like hamsters, guinea pigs, 
and rabbits are often chosen for their
low maintenance needs. Birds offer beauty and song,
and reptiles like turtles and lizards can make intriguing pets.', 
metadata={'source': '/content/data/Different Types of Pet Animals.txt'}),
 Document(page_content='Pet animals come in all shapes and sizes, each suited 
to different lifestyles and home environments. Dogs and cats are the most 
common, known for their companionship and unique personalities. Small', 
metadata={'source': '/content/data/Different Types of Pet Animals.txt'}),
 Document(page_content='intriguing pets. Even fish, with their calming presence
, can be wonderful pets.', 
metadata={'source': '/content/data/Different Types of Pet Animals.txt'})]

我们可以根据相似性搜索从向量存储中检索文档

带 Streamlit 的自定义问答应用程序

在问答应用程序的最后阶段,我们将集成工作流程的每个组件来构建自定义问答应用程序,该应用程序允许用户输入各种数据源(例如基于网络的文章、PDF、CSV 等)与其聊天。从而使他们在日常活动中富有成效。我们需要创建一个 GitHub 存储库并将以下文件添加到其中。

GitHub 仓库结构

需要添加的项目文件:

  • main.py — 包含流式前端代码的 python 文件
  • qanda.py — 提示设计和模型输出函数,返回用户查询的答案
  • utils.py — 加载和分割输入文档的实用函数
  • vector_search.py — 文本嵌入和向量存储函数
  • requirements.txt - 在 Streamlit 公共云中运行应用程序的项目依赖项

我们在此项目演示中支持两种类型的数据源:

  • 基于 Web URL 的文本数据
  • 在线 PDF 文件

这两种类型包含广泛的文本数据,并且在许多用例中最常见。您可以查看下面的main.py python 代码来了解应用程序的用户界面。

# import necessary libraries
import streamlit as st
import openai
import qanda
from vector_search import *
from utils import *
from io  import StringIO
# take openai api key in
api_key = st.sidebar.text_input("Enter your OpenAI API key:", type='password')
# open ai key
openai.api_key = str(api_key)
# header of the app
_ , col2,_ = st.columns([1,7,1])
with col2:
    col2 = st.header("Simplchat: Chat with your data")
    url = False
    query = False
    pdf = False
    data = False
    # select option based on user need
    options = st.selectbox("Select the type of data source",
                            options=['Web URL','PDF','Existing data source'])
    #ask a query based on options of data sources
    if options == 'Web URL':
        url = st.text_input("Enter the URL of the data source")
        query = st.text_input("Enter your query")
        button = st.button("Submit")
    elif options == 'PDF':
        pdf = st.text_input("Enter your PDF link here") 
        query = st.text_input("Enter your query")
        button = st.button("Submit")
    elif options == 'Existing data source':
        data= True
        query = st.text_input("Enter your query")
        button = st.button("Submit") 
# write code to get the output based on given query and data sources   
if button and url:
    with st.spinner("Updating the database..."):
        corpusData = scrape_text(url)
        encodeaddData(corpusData,url=url,pdf=False)
        st.success("Database Updated")
    with st.spinner("Finding an answer..."):
        title, res = find_k_best_match(query,2)
        context = "\n\n".join(res)
        st.expander("Context").write(context)
        prompt = qanda.prompt(context,query)
        answer = qanda.get_answer(prompt)
        st.success("Answer: "+ answer)
# write a code to get output on given query and data sources
if button and pdf:
    with st.spinner("Updating the database..."):
        corpusData = pdf_text(pdf=pdf)
        encodeaddData(corpusData,pdf=pdf,url=False)
        st.success("Database Updated")
    with st.spinner("Finding an answer..."):
        title, res = find_k_best_match(query,2)
        context = "\n\n".join(res)
        st.expander("Context").write(context)
        prompt = qanda.prompt(context,query)
        answer = qanda.get_answer(prompt)
        st.success("Answer: "+ answer)
        
if button and data:
    with st.spinner("Finding an answer..."):
        title, res = find_k_best_match(query,2)
        context = "\n\n".join(res)
        st.expander("Context").write(context)
        prompt = qanda.prompt(context,query)
        answer = qanda.get_answer(prompt)
        st.success("Answer: "+ answer)
        
        
# delete the vectors from the database
st.expander("Delete the indexes from the database")
button1 = st.button("Delete the current vectors")
if button1 == True:
    index.delete(deleteAll='true')

在streamlit云上部署问答应用程序

应用程序用户界面

Streamlit 提供社区云来免费托管应用程序。此外,streamlit 由于其自动化 CI/CD 管道功能而易于使用。

结论

总之,我们探索了使用 LangChain 和 Pinecone 矢量数据库构建自定义问答应用程序的令人兴奋的可能性。本博客向我们介绍了基本概念,从问答应用程序的概述开始,到了解 Pinecone 矢量数据库的功能。通过将 OpenAI 语义搜索管道的强大功能与 Pinecone 高效的索引和检索系统相结合,我们充分利用了利用 Streamlit 创建强大且准确的问答解决方案的潜力。

常见问题解答

Q1:什么是Pinecone和LangChain ?

答:Pinecone 是一个可扩展的长期记忆向量数据库,用于存储 LLM 支持的应用程序的文本嵌入,而 LangChain 是一个允许开发人员构建 LLM 支持的应用程序的框架

Q2:NLP问答有什么应用?

答:问答应用程序用于客户支持聊天机器人、学术研究、电子学习等。

Q3:为什么要使用LangChain ?

答:与LLMS合作可能会很复杂。LangChain允许开发人员使用各种组件以对开发人员最友好的方式集成这些LLM,从而更快地交付产品。

Q4:构建问答应用程序的步骤是什么?

A:构建问答应用的步骤如下:文档加载、文本分割、向量存储、检索、模型输出。

Q5:LangChain 工具有哪些?

答:LangChain 有以下工具:文档加载器、文档转换器、向量存储、链、内存和代理。

相关文章
|
4天前
|
人工智能 缓存 监控
使用LangChain4j构建Java AI智能体:让大模型学会使用工具
AI智能体是大模型技术的重要演进方向,它使模型能够主动使用工具、与环境交互,以完成复杂任务。本文详细介绍如何在Java应用中,借助LangChain4j框架构建一个具备工具使用能力的AI智能体。我们将创建一个能够进行数学计算和实时信息查询的智能体,涵盖工具定义、智能体组装、记忆管理以及Spring Boot集成等关键步骤,并展示如何通过简单的对话界面与智能体交互。
87 1
|
7天前
|
人工智能 Java API
构建基于Java的AI智能体:使用LangChain4j与Spring AI实现RAG应用
当大模型需要处理私有、实时的数据时,检索增强生成(RAG)技术成为了核心解决方案。本文深入探讨如何在Java生态中构建具备RAG能力的AI智能体。我们将介绍新兴的Spring AI项目与成熟的LangChain4j框架,详细演示如何从零开始构建一个能够查询私有知识库的智能问答系统。内容涵盖文档加载与分块、向量数据库集成、语义检索以及与大模型的最终合成,并提供完整的代码实现,为Java开发者开启构建复杂AI智能体的大门。
239 1
|
28天前
|
安全 关系型数据库 数据管理
阿里云数据库:构建高性能与安全的数据管理系统
阿里云数据库提供RDS、PolarDB、Tair等核心产品,具备高可用、弹性扩展、安全合规及智能运维等技术优势,广泛应用于电商、游戏、金融等行业,助力企业高效管理数据,提升业务连续性与竞争力。
|
16天前
|
SQL 弹性计算 关系型数据库
如何用读写分离构建高效稳定的数据库架构?
在少写多读业务场景中,主实例读请求压力大,影响性能。通过创建只读实例并使用数据库代理实现读写分离,可有效降低主实例负载,提升系统性能与可用性。本文详解配置步骤,助你构建高效稳定的数据库架构。
|
1月前
|
安全 关系型数据库 MySQL
MySQL安全最佳实践:保护你的数据库
本文深入探讨了MySQL数据库的安全防护体系,涵盖认证安全、访问控制、网络安全、数据加密、审计监控、备份恢复、操作系统安全、应急响应等多个方面。通过具体配置示例,为企业提供了一套全面的安全实践方案,帮助强化数据库安全,防止数据泄露和未授权访问,保障企业数据资产安全。
|
16天前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
54 3
|
22天前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
2月前
|
存储 运维 关系型数据库
从MySQL到云数据库,数据库迁移真的有必要吗?
本文探讨了企业在业务增长背景下,是否应从 MySQL 迁移至云数据库的决策问题。分析了 MySQL 的优势与瓶颈,对比了云数据库在存储计算分离、自动化运维、多负载支持等方面的优势,并提出判断迁移必要性的五个关键问题及实施路径,帮助企业理性决策并落地迁移方案。
|
9天前
|
关系型数据库 MySQL 分布式数据库
阿里云PolarDB云原生数据库收费价格:MySQL和PostgreSQL详细介绍
阿里云PolarDB兼容MySQL、PostgreSQL及Oracle语法,支持集中式与分布式架构。标准版2核4G年费1116元起,企业版最高性能达4核16G,支持HTAP与多级高可用,广泛应用于金融、政务、互联网等领域,TCO成本降低50%。
|
10天前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。