最近有看到能够利用LangChain+OpenAI的API来完成一个问答体系,上一篇文章:ChatGLM 集成进LangChain东西。既然能够将ChatGLM 集成进LangChain,是不是我们能够在彻底不运用OpenAI的情况下来是完成一个私有化的本地知识库问答体系的建立呢?本文将介绍一种可行的计划。

步骤

ChatGLM集成进LangChain东西

能够参考笔者的上一篇文章:ChatGLM 集成进LangChain东西

生成Embedding

本文运用一篇公开的新闻数据(腾讯2022年第四季度营收1449.5亿元 调整后净利润297.1亿元)来做测验。

切分文本

参照Text Splitters文档,能够挑选对应的文本切分器,假如是通用文本的话,主张挑选RecursiveCharacterTextSplitter,代码如下:

from langchain.document_loaders import UnstructuredFileLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 导入文本
loader = UnstructuredFileLoader("./data/news_test.txt")
# 将文本转成 Document 目标
data = loader.load()
print(f'documents:{len(data)}')
# 初始化加载器
text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)
# 切割加载的 document
split_docs = text_splitter.split_documents(data)
print("split_docs size:",len(split_docs))

打印成果如下:

documents:1
split_docs size: 31
  • chunk_size:每一个分片的最大大小
  • chunk_overlap:相邻的块之间的最大堆叠。有一些堆叠能够很好地坚持块之间的一些连续性(类似于一个滑动窗口)。

生成embedding

目前有两种方法能够生成Embedding数据

  1. 直接运用OpenAIEmbeddings来生成Embedding数据
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain import VectorDBQA
from langchain.document_loaders import UnstructuredMarkdownLoader
from langchain.embeddings.openai import OpenAIEmbeddings
import IPython
import os
from dotenv import load_dotenv
load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["OPENAI_API_BASE"] = os.getenv("OPENAI_API_BASE")
embeddings = OpenAIEmbeddings( )
  1. 运用HuggingFaceEmbeddings来生成Embedding数据
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
import IPython
import sentence_transformers
embedding_model_dict = {
    "ernie-tiny": "nghuyong/ernie-3.0-nano-zh",
    "ernie-base": "nghuyong/ernie-3.0-base-zh",
    "text2vec": "GanymedeNil/text2vec-large-chinese",
    "text2vec2":"uer/sbert-base-chinese-nli",
    "text2vec3":"shibing624/text2vec-base-chinese",
}
EMBEDDING_MODEL = "text2vec3"
# 初始化 hugginFace 的 embeddings 目标
embeddings = HuggingFaceEmbeddings(model_name=embedding_model_dict[EMBEDDING_MODEL], )
embeddings.client = sentence_transformers.SentenceTransformer(
        embeddings.model_name, device='mps')

两种方法的差别:

  • OpenAIEmbeddings:
    • 运用简略,并且作用比较好;
    • 会耗费openai的token,特别是大段文本时,耗费的token还不少,假如知识库是比较固定的,能够考虑将每次生成的embedding做耐久化,这样就不需求再调用openai了,能够大大节约token的耗费;
    • 或许会有数据走漏的风险,假如是一些高度私密的数据,不主张直接调用。
  • HuggingFaceEmbeddings:
    • 能够在HuggingFace上面挑选各种sentence-similarity模型来进行试验,数据都是在本机上进行核算
    • 需求必定的硬件支撑,最好是有GPU支撑,否则生成数据或许会非常慢
    • 生成的向量作用或许不是很好,并且HuggingFace上的中文向量模型不是许多。

保存Embedding数据

有多种向量数据库挑选,这儿挑选比较简略的Chroma,由于比较轻量,直接装置库就可运用。

from langchain.vectorstores import Chroma
# 初始化加载器
db = Chroma.from_documents(split_docs, embeddings,persist_directory="./chroma/openai/news_test")
# 耐久化
db.persist()

耐久化后,能够直接挑选从耐久化文件中加载,不需求再从头就可运用了,运用方法如下:

db = Chroma(persist_directory="./chroma/news_test", embedding_function=embeddings)

当然也可运用FAISS,运用方法也类似,

  • 耐久化
from langchain.vectorstores import FAISS
db = FAISS.from_documents(split_docs, embeddings)
db.save_local("./faiss/news_test")
  • 加载已耐久化向量
db = FAISS.load_local("./faiss/news_test",embeddings=embeddings)

试验作用

  • 假如只想运用embedding来核算语句的类似度,能够直接类似下面这样运用:
# 初始化 prompt 目标
question = "2022年腾讯营收多少"
similarDocs = db.similarity_search(question, include_metadata=True,k=4)
[print(x) for x in similarDocs]

最多回来匹配的前4条类似度最高的语句

  • 假如想接入ChatGLM来帮助做总结和汇总的话,能够如下运用:
from langchain.chains import RetrievalQA
import IPython
retriever = db.as_retriever()
qa = RetrievalQA.from_chain_type(llm=ChatGLM(temperature=0.1), chain_type="stuff", retriever=retriever)
# 进行问答
query = "2022年腾讯营收多少"
print(qa.run(query))

LangChain + ChatGLM 实现本地知识库问答

  • ChatGLM根据ChatGLM 集成进LangChain东西文章中的封装

最终作用或许并不是很好,这或许跟文本切分、embedding生成都有关系,需求再不断调理,但是整体思路和计划是可行的。

总结

本文运用LangChain+ChatGLM来完成一个简略的根据本地知识库的问答体系,能够在彻底不运用openai提供的api来完成本地知识库问答体系的建立,假如有需求做本地私有化知识库问答体系的,能够参考此计划。

参考

imClumsyPanda/langchain-ChatGLM

运用langchain合作chatglm建立本地的知识库,但是langchain和chatglm是布置在一起的,耦合性比较高

ChatGLM 集成进LangChain东西