本文將介紹如何在Semantic Kernel中使用Qdrant向量資料庫,並演示如何在Semantic Kernel中進行向量更新和查詢操作。
1. 背景
在前一篇文章 中,我們介紹了如何使用 Docker 部署 Qdrant 向量資料庫,以及其相關的安全配置,並演示了如何使用 .NET 透過 TLS 安全存取 Qdrant 向量資料庫。現在,我們將在 Semantic Kernel [1] 中使用Qdrant向量資料庫,並演示如何進行向量更新和查詢操作。
Semantic Kernel是一個開源的語意內核 SDK,它提供了一種高效的方式讓使用者可以在自己的應用程式中整合大語言模型 (LLM) 的強大功能。Semantic Kernel提供了多種向量資料庫的連結器,可以與各種向量資料庫整合,從而提供高效的向量查詢和更新功能。
2. 在Semantic Kernel中使用Qdrant
在我們的大語言模型 (LLM) 應用程式中,我們通常會需要構建短期和長期記憶的方式,以賦予更智慧的應用程式更大的能力。這個時候,我們就需要使用向量資料庫來儲存和查詢向量數據。Qdrant 是一個高效能的向量資料庫,它提供了高效的向量查詢和更新功能,可以滿足我們的需求。
2.1 安裝Semantic Kernel SDK
在Semantic Kernel中使用Qdrant向量資料庫,我們首先需要安裝Semantic Kernel SDK,以及 Semantic Kernel 的 Memory 外掛程式和 Qdrant 連結器:
dotnet add packageMicrosoft.SemanticKernel --version 1.6.3
dotnet add packageMicrosoft.SemanticKernel.Plugins.Memory --version 1.6.3-alpha
dotnet add packageMicrosoft.SemanticKernel.Connectors.Qdrant --version 1.6.3-alpha
透過上面的 alpha 標識,我們可以看到 Semantic Kernel 的 Memory 外掛程式和 Qdrant 連結器還處於預覽階段,後續相關方法可能會有所變化,我們需要註意這一點。
在安裝好 Semantic Kernel SDK 和相關外掛程式後,我們就可以在我們的應用程式中使用 Qdrant 向量資料庫了。接下來我會進行一個一個簡單的程式碼範例,修改自 Github 的 notebook
【Building Semantic Memory with Embeddings】
[2]
,這裏我們更改了儲存方式,將
VolatileMemoryStore
改為使用 Qdrant 向量資料庫的方式。
2.2 引入 Embedding 服務
完成了基礎的類別庫安裝,我們就可以引入相關的名稱空間了:
usingMicrosoft.SemanticKernel.Connectors.OpenAI;
usingMicrosoft.SemanticKernel.Connectors.Qdrant;
usingMicrosoft.SemanticKernel.Memory;
接下來,我們需要建立一個 MemoryBuilder 物件,這裏需要註意的是,因為功能是實驗性的,所以我們需要禁用一些警告:
#pragma warning disable SKEXP0001, SKEXP0010, SKEXP0050
var memoryBuilder = newMemoryBuilder();
非常重要的是,這裏我們需要選擇一個 Embedding 服務,用來將文本轉換為向量。這裏我們使用的是 Azure AI 的
text-embedding-ada-002
服務,需要在 Azure OpenAI Studio 中完成該模型的部署:
memoryBuilder.WithAzureOpenAITextEmbeddingGeneration("text-embedding-ada-002", "AZURE_ENDPOINT ", "AZURE_OPENAI_KEY");
2.3 連線 Qdrant 向量資料庫
接下來我們使用 Semantic Kernel 提供的連結器,將
MemoryBuilder
與 Qdrant 向量資料庫連線起來,這裏使用的通訊方式不是我們上一篇文章中官方客戶端使用的 GRPC,而是使用的 HTTP:
HttpClient httpClient = newHttpClient(newCustomQdrantHandler("<certificate thumbprint>", "client.pfx", "password"));
#pragma warning disable SKEXP0020
memoryBuilder.WithQdrantMemoryStore(httpClient, 1536 , "https://localhost:6333");
var memory = memoryBuilder.Build();
這裏需要註意的是,因為我們從官方樣例的
VolatileMemoryStore
改為了 Qdrant 向量資料庫,所以這裏我們需要使用
WithQdrantMemoryStore
方法,這個方法需要提供所使用的 Embedding 的維度。
另外,因為我們使用的是自簽名證書,所以我們需要對 HttpClient 進行一些配置,這裏我們使用了一個自訂的
CustomQdrantHandler
類,用來處理證書的驗證,並提供客戶端證書進行雙向認證。
internal classCustomQdrantHandler : HttpClientHandler{
privatestring _knownHash;
private X509Certificate2 _clientCertificate;
publicCustomQdrantHandler(string knownHash, string certPath, string certPassword) : base()
{
_knownHash = knownHash;
_clientCertificate = new X509Certificate2(certPath, certPassword);
this.ClientCertificates.Add(_clientCertificate);
this.ServerCertificateCustomValidationCallback = CheckServerCertificate;
}
privateboolCheckServerCertificate(HttpRequestMessage httpRequestMessage, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors errors)
{
usingvar sha256 = SHA256.Create();
var hashBytes = sha256.ComputeHash(certificate.GetPublicKey());
var hashString = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
return hashString == _knownHash;
}
}
2.4 向量更新和查詢
在完成了 MemoryBuilder 的構建後,我們就可以使用 Memory 物件進行向量的更新和查詢操作了。這裏我們使用一個關於「我」的簡單介紹的例子,將一些文本轉換為向量,並儲存到 Qdrant 向量資料庫中:
stringMemoryCollectionName = "aboutMe";
await memory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea");
await memory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I currently work as a tourist operator");
await memory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I currently live in Seattle and have been living there since 2005");
await memory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015");
await memory.SaveInformationAsync(MemoryCollectionName, id: "info5", text: "My family is from New York");
透過上面的程式碼,我們將這些文本資訊儲存到 Qdrant 向量資料庫中,
SaveInformationAsync
指定了集合名稱、文本 ID 和文本內容。
接下來,我們可以定義下面一些問題,然後使用 Memory 物件進行查詢操作:
var questions = new[]
{
"what is my name?",
"where do I live?",
"where is my family from?",
"where have I travelled?",
"what do I do for work?",
};
foreach (var q in questions)
{
var response = await memory.SearchAsync(MemoryCollectionName, q).FirstOrDefaultAsync();
Console.WriteLine("Q: " + q);
Console.WriteLine("A: " + response?.Relevance.ToString() + "\t" + response?.Metadata.Text);
}
透過上面的程式碼,我們搜尋並打印了一些問題的答案,這裏我們使用的是
SearchAsync
方法,指定了集合名稱和問題文本。該方法對問題進行了一些篩選,預設只返回最相關的一個答案,並且要求相關性至少為 0.7。
在執行後,我們即可在 Qdrant 的 Web 界面上看到相關的向量數據:
3. 總結
在Semantic Kernel中使用Kernel Memory服務和Qdrant向量資料庫可以極大地提高數據的儲存和檢索效率。透過靈活的數據處理流程和強大的查詢功能,可以輕松地在大量的數據中找到最相關的資訊。這對於構建高效的AI系統來說,是非常重要的。
References
[1]
Semantic Kernel:
https://github.com/microsoft/semantic-kernel?wt.mc_id=DT-MVP-5005195
[2]
【Building Semantic Memory with Embeddings】:
https://github.com/microsoft/semantic-kernel/blob/main/dotnet/notebooks/06-memory-and-embeddings.ipynb?wt.mc_id=DT-MVP-5005195