🔗 LangChain for LLM Application Development - DeepLearning.AI
Embedding : https://huggingface.co/BAAI/bge-large-en-v1.5/tree/main
学习目标
1、Embedding and Vector Store
2、RetrievalQA
引包、加载环境变量
python
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
from langchain.indexes import VectorstoreIndexCreator
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
from langchain.document_loaders import CSVLoader
from langchain.vectorstores import DocArrayInMemorySearch
from langchain_huggingface import HuggingFaceEmbeddings
from IPython.display import display, Markdown
加载一下我们的文件
python
file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file, encoding='utf-8')
docs = loader.load()
Embedding and vector Store
大语言模型一次只能处理几千个单词,如果我们有一个非常大的文档的话,大语言模型不能一次全部处理,怎么办?
这时候就需要用到embeding和 vector store,先来看看embeding
embeding将一段文本转化成数字,用一组数字来表示这段文本。这组数字捕捉了这段文本表示的内容,内容相似的文本,将会有相似的向量值。我们可以在向量空间中比较文本片段来查看他们之间的相似性。
我们使用智源实验室推出的BGE Embedding模型;
python
model_name = "bge-large-en-v1.5"
embeddings = HuggingFaceEmbeddings(model_name=model_name)
有了embedding模型后,我们还需要一个向量数据库, 创建向量数据库,首先需要将文档进行切片分割操作,把文档切分成一个个块(chunks),然后对每个块做embedding,最后再把由embedding生成的所有向量存储在向量数据库中;
我们使用DocArrayInMemorySearch作为向量数据库,DocArrayInMemorySearch是由Docarray提供的文档索引,它将会整个文档以向量的形式存储在内存中;
python
db = DocArrayInMemorySearch.from_documents(docs, embeddings)
当我们完成了向量数据库构建后,在用户提问时,用户的问题通过Embedding操作生成一组向量,接下来将该向量与向量数据库中的所有向量进行比较,找出前n个最相似的向量并将其转换成对应的文本信息。我们有这样一个问题,现在我们通过向量数据库来查找和该问题相似度最高的内容;
python
query = "Please suggest a shirt with sunblocking"
docs = db.similarity_search(query)
我们这里查看一下检索到的第一条数据 ,确实是跟防嗮有关的;
最后,我们将这些与用户问题最相似的文本信息输入到LLM,并由LLM生成最终的回复;
python
# 创建一个检索器
retriever = db.as_retriever()
# 初始化LLM
llm = ChatOpenAI(api_key=os.environ.get('ZHIPUAI_API_KEY'),
base_url=os.environ.get('ZHIPUAI_API_URL'),
model="glm-4",
temperature=0.98)
刚刚我们输入了一个问题并在向量数据库中检索到了一些相关信息,接下来我们将这些信息和问题一起输入到大语言模型中,使用markdown的格式展示一下效果;
python
docs_str = "".join([docs[i].page_content for i in range(len(docs))])
response = llm.invoke(f"{docs_str} Question: Please list all your shirts with sun protection in a table in markdown and summarize each one.")
display(Markdown(response.content))
这是智谱GLM4帮我们整理之后的答案,并且帮我们整理好了;
RetrievalQA
当然,如果你觉得这很麻烦,我们可以创建一个RetrievalQA链,这样调用也是可以的;
python
qa_stuff = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
verbose=True
)
query = "Please list all your shirts with sun protection in a table in markdown and summarize each one."
response = qa_stuff.invoke(query)
该chain包含三个主要的参数,其中llm参数是我们的智谱GLM4, retriever参数设置设置为前面我们由DocArrayInMemorySearch创建的retriever,最后一个重要的参数为chain_type,该参数包含了四个可选值:stuff,map_reduce,refine,map_rerank,接下来我们简单了解一下这些选择的区别;
这种最简单粗暴,会把所有的 document 一次全部传给 llm 模型进行总结。如果document很多话,可能会报超出最大 token 限制的错。
这个方式会先将每个 document 通过llm 进行总结,最后将所有 document 总结出的结果再进行一次总结。
这种方式会先总结第一个 document,然后在将第一个 document 总结出的内容和第二个document 一起发给 llm 模型再进行总结,以此类推。这种方式的好处就是在总结后一个 document 的时候,会带着前一个的 document 进行总结,给需要总结的 document 添加了上下文,增加了总结内容的连贯性。
这种方式会通过llm对每个文档进行一次总结,然后得到一个分数,最后选择一个分数最高的总结作为最终回复。