iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
生成式 AI

Semantic Kernel 的魔力-用.NET探索生成式應用系列 第 29

RAG 篇章 - 使用 Qdrant 向量資料庫

  • 分享至 

  • xImage
  •  

當我們談到 RAG 應用的時候,除了向量化之外,另一個重點就是向量資料庫,與傳統資料庫不同,向量資料庫是專門為了高維度資料以及相似度搜尋而存在的,目前市場有許多向量資料庫,而 Qdrant 則是其中較知名的,它的各項評比都相當不錯。
https://ithelp.ithome.com.tw/upload/images/20241012/20126569nDie2WN2Zs.png

Qdrant 向量資料庫

Qdrant 是專門用來儲存和搜尋「向量」的資料庫。簡單來說,當我們用 AI 模型來處理文字、圖片或其他資料時,模型會把這些資料轉換成數字向量(就是一串數字),這些向量能幫助我們比較資料之間的相似度。而 Qdrant 的工作就是把這些向量管理好,讓我們可以快速找到最相似的結果。傳統資料庫像 SQL、NoSQL 這些,對數字、文字的查詢非常強大,但他們缺少對向量的處理以及相似度搜尋演算法(目前有部份傳統資料庫也開始提供向量支援),這時候傳統資料庫就沒那麼好用了。這就是為什麼會需要一個專門處理向量的資料庫。

  • Qdrant 支援即時資料處理:可以隨時新增、刪除或更新向量資料,不需要等到整個資料庫重建索引才生效。
  • Qdrant 支援REST API:透過 API 就能操作,不管是用 Python、C# 還是其他程式語言,都能輕鬆整合。
  • Qdrant 效能優化:它針對大量資料進行了優化,能夠處理數百萬甚至數十億筆向量資料,而且搜尋速度非常快。
  • Qdrant 支援容器化安裝:可以使用容器化方式安裝,簡單快速。

這裡容我置入一下工商,本月我與另二位作者合作的新書<LangChain 奇幻旅程:OpenAI x Gemini x 多模態應用開發指南>其中第12章對 Qdrant 有詳細的教學。購書連結(點這裡)

安裝 Qdrant 向量資料庫

這裡我使用容器方式來架設 Qdrant 向量資料庫,首先你得先安裝好 docker 環境(這部份請自行參考docker官方教學,當然在正式環境上可能會使用 K8S).
接著執行以下指令,拉取 Qdrant 官方 docker image 並安裝。完成後 Qdrant 會在本機監聽 Port 6333,開啟瀏覽器查看 localhost:6333,如果有顯示 Qdrant Version資訊,就代表 Qdrant 已經成功安裝並啟動。

docker pull qdrant/qdrant
docker run -p 6333:6333 qdrant/qdrant

另外Qdrant 向量資料庫也提供WebUI介面,localhost:6333/dashboard,可以方便進行管理。(本例未配置Qdrant DB 的密碼)
https://ithelp.ithome.com.tw/upload/images/20241012/201265697SDpp2JZQf.png

使用 Qdrant 向量資料庫

以上一篇文章的範例,修改為使用 Qdrant 向量資料庫。

  • 安裝 Microsoft.SemanticKernel.Connectors.Qdrant 套件
    由於要連接 Qdrant 向量資料庫,因此需要安裝 Semantic Kernel 提供的 Qdrant 套件。事實上 Semantic Kernel 還有支援其它的向量資料庫,例如:Pinecone、Chroma...等,有需要都可以安裝相關套件來使用。
dotnet add package Microsoft.SemanticKernel.Connectors.Qdrant
  • 建立 Kernel 物件
    這個範例使用的是部署在Azure OpenAI 上的 OpenAI text-embedding-3-large 模型。
Kernel kernel = Kernel.CreateBuilder()
    .AddAzureOpenAITextEmbeddingGeneration(
        endpoint: Config.aoai_endpoint,
        deploymentName: Config.aoai_embedding_deployment,
        apiKey: Config.aoai_apiKey)
    .Build();
  • 取得實作 ITextEmbeddingGenerationService 介面的服務
    實作 ITextEmbeddingGenerationService 介面的服務,用於進行文字 Embedding 的處理。以本次範例來說,即是實作了 OpenAI TextEmbedding,當然這也是 Semantic Kernel 內建提供的。
var embeddingGenerator = kernel.GetRequiredService<ITextEmbeddingGenerationService>();
  • 建立 Qdrant 儲存物件
    這裡給與連線端點以及向量維度,而向量維度要看你所使用的 Embedding Model 來決定,同時也要注意向量資料庫是否有支援到這個維度。以 text-embedding-3-large 模型來說,最高維度是3072。
var memoryStore = new QdrantMemoryStore("http://localhost:6333", 3072);
  • 取得 ISemanticTextMemory 的實作
    提供在語義記憶體儲存保存、檢索文字資訊的方法。
SemanticTextMemory textMemory = new(memoryStore, embeddingGenerator);
  • 準備原始文字資料
    範例使用一般文字陣列,實作上也可以是從文件中讀取。並且設定一個 collection Name,可以做為檢索時過濾條件,這有助於減少檢索不必要的文字內容。而 Qdrant 向量資料庫還支援了 tags 可以再進一步做過濾,這樣一來可以減少許多資料雜訊,取得更精準的參考資料。
string collectionName = "Law";

string[] kmEntries =
        [
            """
            1.為規定勞動條件最低標準,保障勞工權益,加強勞雇關係,促進社會與經濟發展,特制定本法;本法未規定者,適用其他法律之規定。
            2.雇主與勞工所訂勞動條件,不得低於本法所定之最低標準。
            """,
            """
            勞動契約,分為定期契約及不定期契約。臨時性、短期性、季節性及特定性工作得為定期契約;有繼續性工作應為不定期契約。派遣事業單位與派遣勞工訂定之勞動契約,應為不定期契約。
            定期契約屆滿後,有下列情形之一,視為不定期契約:
            一、勞工繼續工作而雇主不即表示反對意思者。
            二、雖經另訂新約,惟其前後勞動契約之工作期間超過九十日,前後契約間斷期間未超過三十日者。
            前項規定於特定性或季節性之定期工作不適用之。
            """,
            """
            未符合下列規定者,雇主不得與勞工為離職後競業禁止之約定:
            一、雇主有應受保護之正當營業利益。
            二、勞工擔任之職位或職務,能接觸或使用雇主之營業秘密。
            三、競業禁止之期間、區域、職業活動之範圍及就業對象,未逾合理範疇。
            四、雇主對勞工因不從事競業行為所受損失有合理補償。
            前項第四款所定合理補償,不包括勞工於工作期間所受領之給付。
            違反第一項各款規定之一者,其約定無效。
            離職後競業禁止之期間,最長不得逾二年。逾二年者,縮短為二年。
            """
        ];
  • 向量處理並儲存
    呼叫 SemanticTextMemory 物件的 SaveInformationAsync 方法,進行向量處理並儲存,這裡的參數包含每一筆分割資料的識別碼ID、整個文件的 collection Name以及文字內容。
foreach (var km in kmEntries)
{
    await textMemory.SaveInformationAsync(
        collection: collectionName,
        text: km,
        id: Guid.NewGuid().ToString());
}
  • 向量檢索
    呼叫 SemanticTextMemory 物件的 SearchAsync 方法,進行向量檢索。
    這裡的參數:
  1. 使用 collection Name做為檢索時過濾條件。
  2. 使用者提問文字
  3. 檢索回傳最大資料數
  4. 相似度檢索值,設定愈高,表示相關性要愈強的資料才會被檢索出來,其值介於0~1之間。
var result = await textMemory.SearchAsync(collection: collectionName, query: "我離職後,不能再從事類似性質的工作嗎", limit: 2, minRelevanceScore: 0.5).ToListAsync();
foreach (var item in result)
{
    Console.WriteLine($"Id: {item.Metadata.Id}, Text: {item.Metadata.Text}, Relevance: {item.Relevance} \n\n");
}

結語

與上一篇使用快閃記憶體相比,使用 Qdrant 向量資料庫可以持久化向量資料,不需要每次重啟應用時,重新轉入資料,另外當資料量大的時候,專用的向量資料庫可以明顯察覺到搜尋速度會快非常多。本篇的程式碼與上一篇的程式碼幾乎87%,而這也是因為有了 Semantic Kernel 的幫忙,它的高度抽象化架構讓我們在實作應用上,對於抽換服務是相當方便的,重要的是不需要大幅的改動程式碼。當然還是老話一句,用與不同有不同的角度思考,沒有絕對的答案,同時現階段 Gen AI 的應用處於一種爆發期,AI Model及平台功能快速推陳出新,相對的這些框架的變動性也會跟著變很快,這也是開發者需要認知的一點。

特別提醒,向量資料一旦換了 embedding 模型,就必須重新做向量處理,因為不同模型在語議理解以及維度上並不相同,也因此一旦更換 embedding 模型,則原本已儲存的向量資料就得重新再轉過囉。


上一篇
RAG 篇章 - 運用快閃記憶體實現向量檢索
下一篇
RAG 篇章 - 使用 Kernel Memory 與 Qdrant 向量資料庫實作 RAG
系列文
Semantic Kernel 的魔力-用.NET探索生成式應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言