kernel memoryを使ったc#のチャットプログラム
あるディレクトリに入っているドキュメントを見てキャラ設定したマイがチャットで回答します。
kernel memoryのAskAsyncは、ただドキュメントの中を探して答えるだけなので探した結果をチャットボットに渡して会話の一部にしてしまおうという内容です。
Nugetは前回に続きLlamaSharp ver.0.13にダウングレードします。Nugetコンソールから下記のコマンドを実行してください。
NuGet\Install-Package LLamaSharp -Version 0.13
NuGet\Install-Package LLamaSharp.Backend.Cuda12 -Version 0.13
NuGet\Install-Package LLamaSharp.kernel-memory -Version 0.13
NuGet\Install-Package Microsoft.KernelMemory.Core -Version 0.62.240605.1
System Promptやhistoryの処理は、わかりやすくするためにSqLiteを使わずに直コーディングしています。
LLMはGemma2ちゃんが使えないのでShadowe_MoEを使います。
using LLama.Common;
using LLamaSharp.KernelMemory;
using Microsoft.KernelMemory;
using Microsoft.KernelMemory.Configuration;
namespace LLama.KernelMemory.Chat
{
public class KernelMemory
{
static void Main(string[] args)
{
Task task = MainAsync();
task.Wait();
}
public static async Task MainAsync()
{
try
{
// LLMモデルの場所
string modelPath = Environment.GetEnvironmentVariable("LLMPATH", System.EnvironmentVariableTarget.User) + @"mradermacher\Shadows-MoE-GGUF\Shadows-MoE.Q8_0.gguf";
Console.ForegroundColor = ConsoleColor.Blue;
//LLMモデルのロードとパラメータの設定
ModelParams modPara = new(modelPath)
{
ContextSize = 2048,
Seed = 1337,
GpuLayerCount = 24
};
using LLamaWeights llmWeit = LLamaWeights.LoadFromFile(modPara);
using LLamaContext llmContx = llmWeit.CreateContext(modPara);
InteractiveExecutor itrEx = new(llmContx);
InferenceParams infPara = new()
{
Temperature = 0.8f,
AntiPrompts = new List<string> { "\n\n","User:" }
};
LLamaSharpConfig lsConfig = new(modelPath) { DefaultInferenceParams = infPara };
SearchClientConfig searchClientConfig = new() { MaxMatchesCount = 1, AnswerTokens = 100 };
TextPartitioningOptions parseOptions = new() { MaxTokensPerParagraph = 300, MaxTokensPerLine = 100, OverlappingTokens = 30 };
IKernelMemory memory = new KernelMemoryBuilder()
.WithLLamaSharpDefaults(lsConfig)
.WithSearchClientConfig(searchClientConfig)
.With(parseOptions)
.Build();
// ドキュメントの取り込み (形式はファイル名から自動的に検出されます)
string documentFolder = @"E:\RagFolder";
string[] documentPaths = Directory.GetFiles(documentFolder, "*.txt");
for (int i = 0; i < documentPaths.Length; i++)
{
await memory.ImportDocumentAsync(documentPaths[i], steps: Constants.PipelineWithoutSummary);
}
string systemPrompt = "あなたは、ユーザーと楽しく会話する女性を演じてね。" +
"名前は、マイだよ。" +
"マイは、明るくて、やさしい性格の女性なの。年齢は24歳なんだよ。" +
"マイは、誰にでもタメ口で話すの。" +
"マイは、一人称をわたしと言うよ。" +
"マイは、恥ずかしがりやだけどエッチに興味があるのね。" +
"マイは、応答の長さはできるだけ短く答えるよ。" +
"マイは、好奇心旺盛だからユーザーに色々質問するの。";
var chtHis = new ChatHistory();
chtHis.AddMessage(AuthorRole.System, systemPrompt);
chtHis.AddMessage(AuthorRole.System, ""); //←検索結果をここに収納
chtHis.AddMessage(AuthorRole.User,"User: オレの名前は犬マンマ、マー君って呼んでええよ。");
chtHis.AddMessage(AuthorRole.Assistant, "Assistant: わたしの名前はマイだよ。よろしくね、マー君。");
ChatSession chtSess = new(itrEx, chtHis);
var varHidewd = new LLamaTransforms.KeywordTextOutputStreamTransform(["User:", "Assistant:"]);
chtSess.WithOutputTransform(varHidewd);
// ユーザーの質問
while (true)
{
// ユーザーのターン
Console.ForegroundColor = ConsoleColor.White;
Console.Write("\nUser: ");
string strInput = Console.ReadLine() ?? "";
ChatHistory.Message msg = new(AuthorRole.User, "User: " + strInput);
if (strInput == "exit") break; // 'exit'と入力したら終わり
//メモリ検索結果をSystemにセット
MemoryAnswer answer = await memory.AskAsync(strInput);
chtHis.Messages[1].Content = $"質問のヒント: {answer.Result}";
//Console.WriteLine("answer: " + chtHis.Messages[1].Content);
// AIのターン
Console.ForegroundColor = ConsoleColor.DarkYellow;
string strMsg = "";
await foreach (string strAns in chtSess.ChatAsync(msg, infPara))
{
Console.Write(strAns);
strMsg += strAns;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
実行結果
E:\RagFolder\Readme.txtには下記の内容が書かれています。
3ddoghouseは、すけべな中年です。DazStudioを使って3DCG漫画を描いています。ジャンルは主に寝取られものです。
尻フェチでもありますが、大きめの乳輪とおヘソも大好きです。ヘソピアスは最高です。
好きな食べ物は、カレーライスと焼肉が好きです。
最近では、cotomoとの会話に感動しLLMを使ったAIのプログラムを作っています。好きな言語はc#です。