上一篇實作了如何使用 Embedding Model,然後將轉換成 Embeddings 的句子做相似度的比對,透過這樣的方式找到我們要的結果。
Retriever (檢索) 簡單來說就是我們輸入查詢,然後會去檢索我們所指定的資料,可能是 Python 中的變數名字、可能是存在 Memory、可能是存在資料庫,檢索完之後會找到相似度與輸入查詢最相近的結果回傳。像是昨天實作過的相似度比對,不管是 Cosine Similarity Search 或是 MMR,透過比對我們取得比對後的結果,這個動作就叫做 Retriever (檢索)。那 Retriever 的種類也有很多種,除了最簡單的 一個輸入查詢檢索一個句子或文件
,也有 多個輸入查詢
或者 上下文壓縮
,可以參考 LangChain Retriver。
因為還沒有碰到向量資料庫,所以今天先實戰將一些些內容存在記憶體,會使用到最被廣泛使用的 Cosine Similarity 之外,還有 FAISS Search 的部分。這兩個技術都沒用到資料庫,都是先將資料暫存在記憶體中~
import pprint
from langchain_ffm import FFMEmbedding
from langchain_core.vectorstores import InMemoryVectorStore
embeddings = FFMEmbedding()
# 範例資料
documents = [
"Python 是一種高階編程語言,近年來被拿來做許多機器學習和深度學習的開發與模型訓練。",
"Java 是一種面向對象的編程語言,廣泛應用於企業級應用和 Android 開發。",
"JavaScript 是網頁開發的核心語言,允許動態操作 DOM 以實現交互效果。",
"Go 是由 Google 開發的開源編程語言,因其高併發性能在雲端運算中大放異彩。",
"C# 是由微軟開發的語言,主要用於 Windows 應用開發及遊戲開發,特別是在 Unity 引擎中。",
"PHP 是一種伺服器端腳本語言,廣泛應用於網頁開發,尤其是動態內容生成。",
]
# 將內容透過轉為向量存進記憶體
vectorstore = InMemoryVectorStore.from_texts(
documents,
embedding=embeddings,
)
# k=3 代表回傳相似度最接近的三筆結果
retriever = vectorstore.as_retriever(search_kwargs={'k': 3})
# 輸入內容
retrieved_documents = retriever.invoke("我想成為前端工程師!")
# 查看比對結果
pprint.pprint(retrieved_documents)
程式碼結果探討 🧐:
from_texts
,那如果是 Documents 就要使用 from_documents
。as_retiever
,最後可以傳入的變數除了指定 top_k 取多少之外,還有可以設定 score_threshold
這個就是可以篩選相似度高於多少才納入檢索結果。還有一個是設定要使用 Cosine Similarity 還是 MMR,Cosine Similarity 是預設。將檢索的方式改成使用 MMR
# search_type設定為MMR,在kwargs中設定lambda_unit
retriever = vectorstore.as_retriever(search_type='mmr', search_kwargs={'k': 3, 'lambda_unit':0.25})
程式碼結果探討 🧐:
search_type
為 MMR,再根據自身要求微調 lambda_unit
即可。先簡單介紹一下 FAISS,他的全名是 Facebook AI Similarity Search
。那麼 FAISS 進行相似度比對的時候,不同於大多數是使用 Cosine Similarity,而是使用名為 歐幾里德距離 (L2)
的公式,一樣是算出向量間的距離找最近,但計算方式不盡相同。
import pprint
from langchain_community.vectorstores import FAISS
from langchain_ffm import FFMEmbedding
from langchain_core.documents import Document
embeddings = FFMEmbedding()
# 範例資料
documents = [
Document(page_content="Python 是一種高階編程語言,近年來被拿來做許多機器學習和深度學習的開發與模型訓練。"),
Document(page_content="Java 是一種面向對象的編程語言,廣泛應用於企業級應用和 Android 開發。"),
Document(page_content="JavaScript 是網頁開發的核心語言,允許動態操作 DOM 以實現交互效果。"),
Document(page_content="Go 是由 Google 開發的開源編程語言,因其高併發性能在雲端運算中大放異彩。"),
Document(page_content="C# 是由微軟開發的語言,主要用於 Windows 應用開發及遊戲開發,特別是在 Unity 引擎中。"),
Document(page_content="PHP 是一種伺服器端腳本語言,廣泛應用於網頁開發,尤其是動態內容生成。"),
]
# 將內容透過轉為向量存進記憶體
vectorstore = FAISS.from_documents(documents, embeddings)
# k=3 代表回傳相似度最接近的三筆結果
faiss_retriever = vectorstore.as_retriever(search_kwargs={'k': 3})
# 輸入內容
retriever = faiss_retriever.invoke("我想成為前端工程師!")
# 查看比對結果
pprint.pprint(retriever)
程式碼結果探討 🧐:
# search_type設定為MMR,在kwargs中設定lambda_unit
retriever = vectorstore.as_retriever(search_type='mmr', search_kwargs={'k': 3, 'lambda_unit':0.25})
程式碼結果探討 🧐:
歐幾里德距離
沒辦法取代 Similarity 的部分,這是我的猜測啦,因為找不到太多相關資料可以參考。今天用最簡單的方式了解 Retriever 在做什麼,他的類型有很多種,之後會有一天會來實作這個各種 Retriever 的部分。知道 Retriever 怎麼用之後,今天的實作都是存在記憶體,資料一多對電腦的 Loading 會很大,所以我們下一篇文章要來看看轉成向量的資料如何存進向量資料庫。
今天去雲林崙背當志工,開車來回就 6 個多小時了,超暴斃超累。