使用KernelMemory、Ollama實作落地Language Model與Vector DB的RAG應用

Ian Chen
playtech
Published in
8 min readMay 13, 2024

--

上一篇說到有讀者來信問 Semantic Kernel 是否能連接其它模型,甚至是落地的模型,因此我快速使用 Ollama實現本地模型部署,再以 Semantic Kernel 示範如何與本地模型連接。

那既然都可以串接落地模型,那能不能再進一步串起落地的向量資料庫實現RAG應用呢?答案是肯定的,本篇就延續上一篇再串接個向量資料庫快速示範一下。

(工商服務 )

如果你不知道什麼是RAG、向量資料庫,那麼我與二位朋友合著的ChatGPT開發書籍,有專章細部講解什麼RAG以及向量資料庫。書本銷售 :極速 ChatGPT 開發者兵器指南:跨界整合 Prompt Flow、LangChain 與 Semantic Kernel 框架

首先這個範例會用到 2 個模型,分別是處理文字轉向量的模型 (embedding models) 以及回覆應答用的模型,再來會有一個向量資料庫,本例選擇使用 Qdrant 向量資料庫,同樣使用容器方式掛載它。

  1. 文字轉向量的模型,選擇使用AOAI上所部署的 text-embedding-3-large 模型,它是目前OpenAI最新釋出功能最強大的 embedding models。當然如果你想用本地模型也行,例如 Ollama 上有的mxbai-embed-large 模型。

2. 使用docker掛載 Qdrant 向量資料庫,Qdrant 會在本機監聽 Port 6333,開啟瀏覽器查看 localhost:6333,如果有顯示 Qdrant Version資訊,就代表 Qdrant 已經成功安裝並啟動。另外Qdrant 向量資料庫也提供WebUI介面,localhost:6333/dashboard,可以方便進行管理。(本例未配置Qdrant DB 的密碼)

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

3. 與上一篇的範例一樣這次回覆應答用的模型選用 Meta 的 llama3:8b 模型,也是採用Docker 容器運行Ollama達到本地部署,相關操作可以參考上一篇文章。

4. 前置作業完備後,接著就換 KernelMemory上場,為求簡化本次同樣使用 Console 應用(使用.net 8 .0)做為示範,並安裝Microsoft.KernelMemory.Core 套件 0.50.240504.7 版本。

KernelMemory 是由 Semantic Kernel 獨立分拆出來,降低耦合性,專門針對 LLM Memory 方面的應用,提供更大的彈性(更詳細的說明,請參考我們最新推出的著作 )。

<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.50.240504.7" />

5. 配置連接 Ollama Model 與 AOAI Embedding Model 的參數,Ollama相容 OpenAI 的API,因此直接使用 OpenAIConfig 物件進行配置,其中 API Key 的部份是必填但用不到,因此隨意給個值即可。

//Chat Model Config
var ollamaConfig = new OpenAIConfig
{
Endpoint = "http://localhost:11434/v1",
TextModel = "llama3:8b",
APIKey = "0"
};

//Embedding Model Config
var aoaiEmbeddingConfig = new AzureOpenAIConfig
{
APIKey = api_Key,
Deployment = deploy_embedding_Name,
Endpoint = aoai_Endpoint,
APIType = AzureOpenAIConfig.APITypes.ChatCompletion,
Auth = AzureOpenAIConfig.AuthTypes.APIKey
};

6. 建立 KernelMemoryBuilder,並給與Ollama Model 與 AOAI Embedding Model的參數,以及Qdrant 向量資料庫的連接端點。

var kernelMemory = new KernelMemoryBuilder()
.WithOpenAITextGeneration(ollamaConfig)
.WithAzureOpenAITextEmbeddingGeneration(aoaiEmbeddingConfig)
.WithQdrantMemoryDb("http://localhost:6333")
.Build<MemoryServerless>();

7. 知識文字轉向量進資料庫,通常這個部份會是獨立的一個應用進行維謢,而不會直接掛在 LLM 應用內,但這裡我們簡化一下,直接在 LLM 應用內做轉入的動作。(用道路交通管理處罰條例 PDF格式做示範)

await ImportKm(kernelMemory);

async Task ImportKm(MemoryServerless memory)
{
await memory.ImportDocumentAsync(Path.Combine(Directory.GetCurrentDirectory(), "道路交通管理處罰條例.pdf"), documentId: "taiwan_traffic_law");
}

8. 向量資料庫完成後,便可以進行提問測試。KernelMemory提供二個方法,分別是AskAsync、SearchAsync,其中AskAsync是經過參考向量檢索資料後,再做文本生成的結果,簡單來說就是答案,而SearchAsync是指經過向量檢索後的結果,尚未經過文本生成,也就是說這個結果是向量檢索的結果,簡單來說就是參考資料。

如果在應用上有需要其它進一步的處理,那麼 SearchAsync 方法會是比較合適的。若要直接生成回應回答使用者,那麼直接使用AskAsync方法。

//AskAsync是經過參考向量檢索資料後,再做文本生成的結果,簡單來說就是答案
var ans = await kernelMemory.AskAsync("闖紅燈罰多少錢,請以中文回答", minRelevance: 0.6f);
Console.WriteLine(ans.Result);
foreach (var source in ans.RelevantSources)
{
Console.WriteLine($"source:{source.DocumentId}");
}

Console.WriteLine("\n============== SearchAsync ================\n");

//SearchAsync是指經過向量檢索後的結果,尚未經過文本生成,也就是說這個結果是向量檢索的結果,簡單來說就是參考資料
var search_ref = await kernelMemory.SearchAsync("闖紅燈罰多少錢,請以中文回答", limit: 2, minRelevance: 0.6f);
foreach (var item in search_ref.Results)
{
Console.WriteLine(item.Partitions.First().Text);
Console.WriteLine(item.Partitions.First().Relevance);
Console.WriteLine();
}

透過以上的步驟便可以打造一個降低資料資安疑慮,具備落地模型部署+落地向量資料庫的應用,這個範例程式碼同樣的發佈在我的 Github 上,有需要的朋友們可以自行參考。

歡迎斗內一下我們的新書,給還願意出版繁體中文技術書籍的作者們一點動力 :)

--

--

Ian Chen
playtech

Microsoft MVP / Microsoft Certified Trainer(MCT)