LangChain-RAG必備:向量數(shù)據(jù)庫如何CRUD
今天我將帶領(lǐng)大家,以最為基礎(chǔ)的CRUD入手來看看向量數(shù)據(jù)庫應(yīng)該如何使用。考慮到目前市面上的向量數(shù)據(jù)庫眾多,每個數(shù)據(jù)庫的操作方式也無統(tǒng)一標(biāo)準(zhǔn)。「本文將基于LangChain提供的VectorStore類中的統(tǒng)一操作方法,以chroma向量數(shù)據(jù)庫作為示例進(jìn)行演示。」
向量數(shù)據(jù)庫-新增
LangChain的VectorStore類是一個通用的向量數(shù)據(jù)庫的接口,它可以對接不同的底層向量數(shù)據(jù)庫,如chroma、faiss、annoy等,實現(xiàn)統(tǒng)一的操作方法和API。VectorStore類還提供了一些高級的功能,如語義檢索、最大邊際相關(guān)性(MMR)等,可以幫助我們更好地利用向量數(shù)據(jù)庫的能力。
要想向向量數(shù)據(jù)庫中新增數(shù)據(jù),我們首先需要創(chuàng)建一個VectorStore對象,并在創(chuàng)建時配置好embedding function,即用于將原始數(shù)據(jù)轉(zhuǎn)換為向量的函數(shù)。如下所示:
# 通過HuggingFace創(chuàng)建embedding_function
embeddings = HuggingFaceEmbeddings(model_name=model)
# 創(chuàng)建VectorStore的具體實現(xiàn)類Chroma對象,并指定collection_name和持久化目錄
vector = Chroma(collection_name = 'cname', embedding_functinotallow=embeddings,persist_directory='/vs')
創(chuàng)建好VectorStore對象后,我們就可以使用insert方法來向向量數(shù)據(jù)庫中插入數(shù)據(jù)了。insert方法接受一個doc對象作為參數(shù),doc對象可以是一個字符串或一個字典,如果是一個字典,那么必須包含一個名為text的鍵,其值為要插入的文本內(nèi)容,同時,我們還可以在doc對象中添加一些其他的元數(shù)據(jù),用于后續(xù)的查詢或過濾。例如,我們可以向向量數(shù)據(jù)庫中插入以下三個doc對象:
# 先將文本拆分并轉(zhuǎn)化為doc
loader = TextLoader(url,autodetect_encoding = True)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
# 插入向量數(shù)據(jù)庫
vector.add_documents(documents=splits)
add_documents方法會返回一個id列表,這個id是doc的索引,用于唯一標(biāo)識插入的doc對象。我們可以根據(jù)需要記錄這個id,并與原始文件關(guān)聯(lián),一般來說,一個file對應(yīng)多個doc,例如,我們可以將一個長文本拆分為多個段落,然后將每個段落作為一個doc插入到向量數(shù)據(jù)庫中,這樣可以提高檢索的效率和精度。
向量數(shù)據(jù)庫-刪除
要想從向量數(shù)據(jù)庫中刪除數(shù)據(jù),我們可以使用delete方法,delete方法接受一個id或一個id列表作為參數(shù),然后根據(jù)id來刪除對應(yīng)的doc對象。例如,我們可以使用以下代碼來刪除id為1的doc對象:
# 刪除id為1的doc對象
vector.delete('1')
如果我們不知道要刪除的doc對象的id,但是知道它的一些元數(shù)據(jù),我們可以先使用metadata中的字段來查詢到id,然后再使用delete方法來批量刪除。例如,我們可以使用以下代碼來刪除所有category為功能的doc對象:
# 根據(jù)file_id的條件,查詢到所有符合的doc對象的id
reuslt = vector.get(where={"file_id":file_id})
# 使用delete方法,批量刪除這些id對應(yīng)的doc對象
if reuslt['ids'] :
vector.delete(reuslt['ids'])
向量數(shù)據(jù)庫-更新
VectorStore類沒有提供專門的更新方法,因為更新一個doc對象相當(dāng)于先刪除它,然后再插入一個新的doc對象。因此,我們可以使用delete和insert方法來實現(xiàn)文檔的更新。例如,我們可以使用以下代碼來更新id為2的doc對象,將它的source從文檔改為官網(wǎng):
# 刪除id為2的doc對象
vector.delete('2')
# 插入新的doc對象
vector.add_documents(new_doc)
向量數(shù)據(jù)庫-查詢
VectorStore類提供了多種查詢方法,用于根據(jù)不同的需求和場景來檢索向量數(shù)據(jù)庫中的數(shù)據(jù)。查詢方法主要分為兩種類型:similarity和mmr。similarity類型的查詢方法是基于向量之間的相似度來進(jìn)行檢索的,它可以接受一個字符串或一個向量作為查詢,然后返回最相似的doc對象以及相似度。mmr類型的查詢方法是基于最大邊際相關(guān)性(MMR)來進(jìn)行檢索的,它可以接受一個字符串或一個向量作為查詢,然后返回一個多樣化的doc對象列表,這些doc對象既與查詢相關(guān),又盡量不相似。
接下來,我們將介紹以下四個查詢方法:
- similarity_search:這個方法是最基本的相似度查詢方法,它接受一個字符串作為查詢,以及一個可選的top_n參數(shù),用于指定返回的doc對象的數(shù)量,默認(rèn)為4,然后返回最相似的doc對象或它們的id。例如,我們可以使用以下代碼來查詢與“語義檢索”最相似的doc對象:
# 查詢與“語義檢索”最相似的doc對象
docs = vector.similarity_search("語義檢索")
# 打印查詢結(jié)果
for doc in docs:
print(doc)
- similarity_search_with_score:這個方法與similarity_search類似,但是它會同時返回向量之間的距離,距離越小表示越相似。例如,我們可以使用以下代碼來查詢與“語義檢索”最相似的doc對象,并打印它們的分?jǐn)?shù):
# 查詢與“語義檢索”最相似的doc對象,并返回分?jǐn)?shù)
docs_with_score = vector.similarity_search_with_score("語義檢索")
# 打印查詢結(jié)果和分?jǐn)?shù)
for doc_with_score in docs_with_score:
print(doc_with_score[0], doc_with_score[1])
- similarity_search_with_relevance_scores:這個方法與similarity_search_with_score類似,但是它會將分?jǐn)?shù)轉(zhuǎn)換為一個介于0和1之間的相關(guān)度評分,這個評分表示查詢和doc對象之間的語義相關(guān)程度,評分越高越相似。代碼與similarity_search_with_score類似,不再額外示例
- max_marginal_relevance_search:這個方法是基于最大邊際相關(guān)性(MMR)來進(jìn)行查詢的,最大邊際相關(guān)性(MMR)是一種用于檢索或摘要的方法,它既考慮了查詢和文檔之間的相似度,又考慮了文檔之間的多樣性,從而避免返回重復(fù)或冗余的結(jié)果。它接受一個字符串或一個向量作為查詢,以及一個可選的top_n參數(shù),用于指定返回的doc對象的數(shù)量,默認(rèn)為10,然后返回一個多樣化的doc對象列表,這些doc對象既與查詢相關(guān),又盡量不相似。這個方法可以用于生成摘要、提取關(guān)鍵信息、避免重復(fù)內(nèi)容等場景。例如,我們可以使用以下代碼來查詢與“LangChain”相關(guān)的但不相似的doc對象:
# 查詢與“LangChain”相關(guān)的但不相似的doc對象
docs = vector.max_marginal_relevance_search("LangChain")
# 打印查詢結(jié)果
for doc in docs:
print(doc)
結(jié)語
「CRUD只是操作向量數(shù)據(jù)庫的基礎(chǔ)手段,想要用好RAG必須在CRUD的基礎(chǔ)上掌握語義檢索的相關(guān)原理。」比如文檔拆分時需要按語義盡可能的拆分為小的單元,而在召回時,則需要基于召回的單元盡可能的補充完整的窗口上下文,才能在最終使用LLM時得到盡可能好的結(jié)果。
本文轉(zhuǎn)載自 ??AI小智??,作者: AI小智
