在上次的文章中,我們已經詳細介紹了GraphRag的基本功能和使用方式。如果你還不熟悉,建議先閱讀前面的文章
透過前兩篇文章,相信你已經瞭解到GraphRag.Net目前只支援OpenAI規範的介面,但許多小夥伴在社群中提議,希望能增加對本地模型(例如:ollama等)的支援。所以這次,我們將探討如何在GraphRag.Net中使用自定義模型和本地模型。
為什麼選擇GraphRag.Net?
GraphRag.Net採用了Semantic Kernel作為基礎,讓我們能夠非常簡潔地抽象出會話與向量介面。因此,使用者可以非常方便地實現自己定製的解決方案。接下來,我們會透過一個具體的例子,展示如何將本地模型和國產模型整合到GraphRag.Net中。
預設配置方法
首先,我們來看看如何進行預設配置:
// OpenAI配置 builder.Configuration.GetSection("OpenAI").Get<OpenAIOption>(); // 文件切片配置 builder.Configuration.GetSection("TextChunker").Get<TextChunkerOption>(); // 配置資料庫連線 builder.Configuration.GetSection("GraphDBConnection").Get<GraphDBConnectionOption>(); // 注意,需要先注入配置檔案,然後再注入GraphRag.Net builder.Services.AddGraphRagNet();
這裡,我們將在預設配置中注入OpenAI的配置、文字切片的配置和資料庫連線的配置。然後,依次注入這些配置檔案和GraphRag.Net的服務。
自定義配置方法
如果需要自定義模型或本地模型,可能需要實現一些額外的服務介面,下面是自定義配置的示例:
var kernelBuild = Kernel.CreateBuilder(); kernelBuild.Services.AddKeyedSingleton<ITextGenerationService>("mock-text", new MockTextCompletion()); kernelBuild.Services.AddKeyedSingleton<IChatCompletionService>("mock-chat", new MockChatCompletion()); kernelBuild.Services.AddSingleton<ITextEmbeddingGenerationService>(new MockTextEmbeddingGeneratorService()); kernelBuild.Services.AddKeyedSingleton("mock-embedding", new MockTextEmbeddingGeneratorService()); builder.Services.AddGraphRagNet(kernelBuild.Build());
在這個自定義配置示例中,我們引入了三個自定義服務介面:ITextGenerationService
、IChatCompletionService
和ITextEmbeddingGenerationService
。
實現自定義服務介面
接下來,我們需要為每個服務介面提供具體的實現。以下是三個介面的具體實現:
實現IChatCompletionService
public class MockChatCompletion : IChatCompletionService { private readonly Dictionary<string, object?> _attributes = new(); private string _chatId; private static readonly JsonSerializerOptions _jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString, Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) }; public IReadOnlyDictionary<string, object?> Attributes => _attributes; public MockChatCompletion() { } public async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { StringBuilder sb = new(); string result = $"這是一條Mock資料,便於聊天測試,你的訊息是:{chatHistory.LastOrDefault().ToString()}"; return [new(AuthorRole.Assistant, result.ToString())]; } public async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { StringBuilder sb = new(); string result = $"這是一條Mock資料,便於聊天測試,你的訊息是:{chatHistory.LastOrDefault().ToString()}"; foreach (var c in result) { yield return new StreamingChatMessageContent(AuthorRole.Assistant, c.ToString()); } } }
實現ITextGenerationService
public class MockTextCompletion : ITextGenerationService, IAIService { private readonly Dictionary<string, object?> _attributes = new(); private string _chatId; private static readonly JsonSerializerOptions _jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString, Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) }; public IReadOnlyDictionary<string, object?> Attributes => _attributes; public MockTextCompletion() { } public async Task<IReadOnlyList<TextContent>> GetTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) { StringBuilder sb = new(); string result = $"這是一條Mock資料,便於聊天測試,你的訊息是:{prompt}"; return [new(result.ToString())]; } public async IAsyncEnumerable<StreamingTextContent> GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) { StringBuilder sb = new(); string result = $"這是一條Mock資料,便於聊天測試,你的訊息是:{prompt}"; foreach (var c in result) { var streamingTextContent = new StreamingTextContent(c.ToString(), modelId: "mock"); yield return streamingTextContent; } } }
實現ITextEmbeddingGenerationService
public sealed class MockTextEmbeddingGeneratorService : ITextEmbeddingGenerationService { private Dictionary<string, object?> AttributesInternal { get; } = []; public IReadOnlyDictionary<string, object?> Attributes => this.AttributesInternal; public MockTextEmbeddingGeneratorService() { } public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync( IList<string> data, Kernel? kernel = null, CancellationToken cancellationToken = default) { IList<ReadOnlyMemory<float>> results = new List<ReadOnlyMemory<float>>(); float[] array1 = { 1.0f, 2.0f, 3.0f }; float[] array2 = { 4.0f, 5.0f, 6.0f }; float[] array3 = { 7.0f, 8.0f, 9.0f }; // 將陣列包裝為ReadOnlyMemory<float>並新增到列表中 results.Add(new ReadOnlyMemory<float>(array1)); results.Add(new ReadOnlyMemory<float>(array2)); results.Add(new ReadOnlyMemory<float>(array3)); return results; } public void Dispose() { } }
看到這裡,你可能已經發現,整合自定義模型和本地模型非常簡單。只需按照上述步驟,實現相應的介面並注入配置,你就可以在GraphRag.Net中使用這些自定義的功能。
結語
透過本文的介紹,我們瞭解瞭如何在GraphRag.Net中整合國產模型和本地模型。希望大家能夠根據這些示例,開發出更多適合自己需求的功能。更多精彩內容,歡迎關注我的公眾號,併傳送進群加入我們的GraphRag.Net交流群,與社群小夥伴們一起交流學習!
感謝閱讀,我們下期再見!