使用Longchain打造个人专属知识库

什么是Longchain?

LangChain 是一个开源框架,让软件开发人员能够使用人工智能 (AI) 及其机器学习子集,将大型语言模型与其他外部组件结合起来,开发由 LLM 驱动的应用程序。LangChain的目标是将强大的LLM(例如OpenAI的GPT-3.5和GPT-4)链接到一系列外部数据源,以创建并获得自然语言处理(NLP)应用程序的优势。

具有Python、JavaScript或TypeScript编程语言经验的开发人员、软件工程师和数据科学家可以使用LangChain以这些语言提供的软件包。LangChain 由联合创始人 Harrison Chase 和 Ankush Gola 于 2022 年作为开源项目推出,同年发布了最初的版本。

什么是RAG?

大模型(LLM)支持的最强大的应用程序之一是复杂的问答 (Q&A) 聊天机器人。这些应用程序可以回答有关特定源信息的问题。这些应用程序使用一种称为检索增强生成(Retrieval Augmented Generation:RAG)的技术。

RAG 是一种利用额外数据增强 LLM 知识的技术。大模型可以推理广泛的主题,但他们的知识仅限于他们接受培训的特定时间点的公共数据。 如果您想要构建能够推理私有数据或模型截止日期之后引入的数据的 AI 应用程序,您需要使用模型所需的特定信息来增强模型的知识。 引入适当的信息并将其插入模型提示的过程称为检索增强生成 (RAG)。LangChain 有许多组件旨在帮助构建问答应用程序,以及更广泛的 RAG 应用程序

RAG架构

典型的 RAG 应用程序有两个主要组件:

索引(Index):用于从源获取数据并为其建立索引的管道。这通常发生在离线状态。

检索和生成(Retrieval and generation):实际的 RAG 链,它在运行时接受用户查询并从索引中检索相关数据,然后将其传递给模型。

从原始数据到答案的最常见的完整序列如下所示:

索引

  1. 加载(Load):首先我们需要加载数据。这是通过 DocumentLoaders 完成的。
  2. 分割(Split):文本分割器将大文档分成更小的块。这对于索引数据和将其传递到模型都很有用,因为大块更难搜索并且不适合模型的有限上下文窗口。
  3. 嵌入(Embedding):嵌入是机器学习模型和算法可以轻松使用的一种特殊的数据表示格式。嵌入是一段文本语义的信息密集表示。每个嵌入都是一个浮点数向量,使得向量空间中两个嵌入之间的距离与原始格式中两个输入之间的语义相似性相关。例如,如果两个文本相似,那么它们的向量表示也应该相似。
  4. 存储(Store):我们需要某个地方来存储和索引我们的分割,以便以后可以搜索它们。这通常是使用 VectorStore 模型来完成的。
图片

检索和生成

检索:给定用户输入,使用检索器从存储中检索相关分割。

生成:ChatModel / LLM 使用包含问题和检索到的数据的提示生成答案

图片

在VS code中新建一个python文件,安装相关的依赖包后,导入以下模块:

from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import CharacterTextSplitter
import os
import pinecone 
from langchain.vectorstores import Pinecone
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
import streamlit as st

其中DirectoryLoader用来导入知识库文件,CharacteTextSplitter用来分割文本,pinecone是矢量数据库,用来储存嵌入(Embedding)后的文本,这里的嵌入模型采用OpenAIEmbeddings。RetrievalQA用来回答用户的提问,ChatOpenAI是回答的机器人模型。

文件处理函数:

def doc_preprocessing():
    loader = DirectoryLoader(
        'data/',
        glob='**/*.pdf',     # only the PDFs
        show_progress=True
    )
    docs = loader.load()
    text_splitter = CharacterTextSplitter(
        chunk_size=1000, 
        chunk_overlap=0
    )
    docs_split = text_splitter.split_documents(docs)
    return docs_split

上面的代码检索目录下的pdf文件,然后将文本按照1000个字的大小进行分割,因为嵌入模型的文本处理能力有限,一次性不能处理太多的文字。

处理文本嵌入,然后将处理后的文本储存在Pinecone的数据库:

def embedding_db():
    # we use the openAI embedding model
    embeddings = OpenAIEmbeddings()
    pinecone.init(
        api_key=PINECONE_API_KEY,
        environment=PINECONE_ENV
    )
    docs_split = doc_preprocessing()
    doc_db = Pinecone.from_documents(
        docs_split, 
        embeddings, 
        index_name='chatpdf-demo-index'
    )
    return doc_db

获取问题的答案:

llm = ChatOpenAI()
doc_db = embedding_db()

def retrieval_answer(query):
    qa = RetrievalQA.from_chain_type(
    llm=llm, 
    chain_type='stuff',
    retriever=doc_db.as_retriever(),
    )
    query = query
    result = qa.run(query)
    return result

以上代码中,我们指定了大模型llm为ChatOpenAI(),简化了直接调用openai的过程,然后构造了一个提问-回答链(QA chain), 采用RetrievalQA函数,类型为“填充”(stuff),填充文档链是最直接的文档链。 它需要一个文档列表,将它们全部插入到提示中,并将该提示传递给法学硕士。该链非常适合文档较小且大多数调用只传递少量文档的应用程序。同时构造了一个检索器(Retriver),使用as_retriever()从数据库检索答案。

最后是main()函数定义了一个简单的streamlit应用的界面:

def main():
    st.title("Question and Answering App powered by LLM and Pinecone")

    text_input = st.text_input("Ask your query...") 
    if st.button("Ask Query"):
        if len(text_input)>0:
            st.info("Your Query: " + text_input)
            answer = retrieval_answer(text_input)
            st.success(answer)

运行程序界面如下:

图片

在这个例子里我用了几篇关于苹果公司和加沙战争的新闻稿,当然可以将这些文件替换为其它的专业文件来打造属于你自己的专有知识库!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注