前言
上一篇文章介紹了使用SemanticKernel/C#的RAG簡易實踐,在上篇文章中我使用的是相容OpenAI格式的線上API,但實際上會有很多本地離線的場景。今天跟大家介紹一下在SemanticKernel/C#中如何使用Ollama中的對話模型與嵌入模型用於本地離線場景。
開始實踐
本文使用的對話模型是gemma2:2b,嵌入模型是all-minilm:latest,可以先在Ollama中下載好。
2024年2月8號,Ollama中的相容了OpenAI Chat Completions API,具體見https://ollama.com/blog/openai-compatibility。
因此在SemanticKernel/C#中使用Ollama中的對話模型就比較簡單了。
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(modelId: "gemma2:2b", apiKey: null, endpoint: new Uri("http://localhost:11434")).Build();
這樣構建kernel即可。
簡單嘗試一下效果:
public async Task<string> Praise()
{
var skPrompt = """
你是一個夸人的專家,回覆一句話夸人。
你的回覆應該是一句話,不要太長,也不要太短。
""";
var result = await _kernel.InvokePromptAsync(skPrompt);
var str = result.ToString();
return str;
}
就這樣設定就成功在SemanticKernel中使用Ollama的對話模型了。
現在來看看嵌入模型,由於Ollama並沒有相容OpenAI的格式,所以直接用是不行的。
Ollama的格式是這樣的:
OpenAI的請求格式是這樣的:
curl https://api.openai.com/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"input": "Your text string goes here",
"model": "text-embedding-3-small"
}'
OpenAI的返回格式是這樣的:
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [
-0.006929283495992422,
-0.005336422007530928,
... (omitted for spacing)
-4.547132266452536e-05,
-0.024047505110502243
],
}
],
"model": "text-embedding-3-small",
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
}
因此透過請求轉發的方式是不行的。
之前也有人在ollama的issue提了這個問題:
似乎也有準備實現嵌入介面的相容:
目前試了一下還沒有相容。
在SemanticKernel中需要自己實現一些介面來使用Ollama的嵌入模型,但是經過搜尋,我發現已經有大佬做了這個事,github地址:https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel。
使用方法見:https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel/tree/main/dotnet/Codeblaze.SemanticKernel.Connectors.Ollama
大佬實現了ChatCompletion、EmbeddingGeneration與TextGenerationService,如果你只使用到EmbeddingGeneration可以看大佬的程式碼,在專案裡自己新增一些類,來減少專案中的包。
這裡為了方便,直接安裝大佬的包:
構建ISemanticTextMemory:
public async Task<ISemanticTextMemory> GetTextMemory3()
{
var builder = new MemoryBuilder();
var embeddingEndpoint = "http://localhost:11434";
var cancellationTokenSource = new System.Threading.CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
builder.WithHttpClient(new HttpClient());
builder.WithOllamaTextEmbeddingGeneration("all-minilm:latest", embeddingEndpoint);
IMemoryStore memoryStore = await SqliteMemoryStore.ConnectAsync("memstore.db");
builder.WithMemoryStore(memoryStore);
var textMemory = builder.Build();
return textMemory;
}
現在開始試試效果,基於昨天的分享做改進,今天上傳一個txt文件。
一個私有文件如下所示,隱私資訊已替換:
各位同學:
你好,為了幫助大家平安、順利地度過美好的大學時光,學校專門引進“網際網路+”高校安全教育服務平臺,可透過手機端隨時隨地學習安全知識的網路微課程。大學生活多姿多彩,牢固掌握安全知識,全面提升安全技能和素質。請同學們務必在規定的學習時間完成該課程的學習與考試。
請按如下方式自主完成學習和考試:
1、手機端學習平臺入口:請關注微信公眾號“XX大學”或掃描下方二維碼,進入後點選公眾號選單欄【學術導航】→【XX微課】,輸入賬號(學號)、密碼(學號),點【登入】後即可繫結資訊,進入學習平臺。
2、網頁端學習平臺入口:開啟瀏覽器,登入www.xxx.cn,成功進入平臺後,即可進行安全知識的學習。
3、平臺開放時間:2024年4月1日—2024年4月30日,必須完成所有的課程學習後才能進行考試,試題共計50道,滿分為100分,80分合格,有3次考試機會,最終成績取最優分值。
4、答疑qq群號:123123123。
學習平臺登入流程
1. 手機端學習平臺入口:
請掃描下方二維碼,關注微信公眾號“XX大學”;
公眾號選單欄【學術導航】→【XX微課】,選擇學校名稱,輸入賬號(學號)、密碼(學號),點【登入】後即可繫結資訊,進入學習平臺;
遇到問題請點【線上課服】或【常見問題】,進行諮詢(諮詢時間:週一至週日8:30-17:00)。
2. 網頁端學習平臺入口:
開啟瀏覽器,登入www.xxx.cn,成功進入平臺後,即可進行安全知識的學習。
3. 安全微課學習、考試
1) 微課學習
點選首頁【學習任務中】的【2024年春季安全教育】,進入課程學習;
展開微課列表,點選微課便可開始學習;
大部分微課是點選繼續學習,個別微課是向上或向左滑動學習;
微課學習完成後會有“恭喜,您已完成本微課的學習”的提示,需點選【確定】,再點選【返回課程列表】,方可記錄微課完成狀態;
2) 結課考試
完成該專案的所有微課學習後,點選【考試安排】→【參加考試】即可參加結課考試。
上傳文件:
切割為三段:
存入資料:
回一個問題,比如“答疑qq群號是多少?”:
雖然耗時有點久,大概幾十秒,但是回答對了:
再嘗試回答一個問題:
回答效果不是很好,而且由於配置不行,本地跑也很慢,如果有條件可以換一個模型,如果沒有條件並且不是一定要離線執行的話,可以接一個免費的api,在結合本地的嵌入模型。
換成線上api的Qwen/Qwen2-7B-Instruct,效果還不錯:
總結
本次實踐的主要收穫是如何在SemanticKernel中使用Ollama中的對話模型與嵌入模型用於本地離線場景。在實踐RAG的過程中,發現影響效果的最主要在兩個地方。
第一個地方是切片大小的確定:
var lines = TextChunker.SplitPlainTextLines(input, 20);
var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 100);
第二個地方是要獲取幾條相關資料與相關度的設定:
var memoryResults = textMemory.SearchAsync(index, input, limit: 3, minRelevanceScore: 0.3);
相關度太高一條資料也找不到,太低又容易找到不相關的資料,需要透過實踐,調整成一個能滿足需求的設定。
參考
1、https://medium.com/@johnkane24/local-memory-c-semantic-kernel-ollama-and-sqlite-to-manage-chat-memories-locally-9b779fc56432
2、https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel