Langchain의 임베딩 기능을 닷넷에서는 Semantic Kernel로 구현할 수 있습니다.

인터넷 상에서 검색된 정보를 기반으로 답하는 일반적인 ChatGPT 기능을 넘어서서, 특정한 맥락을 학습시키고, 맥락을 기반으로 정확한 답을 할 수 있는 커스터마이징 챗봇을 만들 수 있는 방법으로 Langchain이 많이 거론됩니다. 여기에 대응되는 닷넷 버전의 구현체는 Microsoft의 Semantic Kernel이 있습니다.

2개의 좋아요

다음은 코드 예시와 실행 예시입니다.

// Text Completion Model: text-davinci-003
// Text Embeding Model: text-embedding-ada-002

var openAiEndpoint = "...";
var openAiApiKey = "...";

var store = await SqliteMemoryStore.ConnectAsync(
	Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "semantic.db"));

var kernel = new KernelBuilder()
	.Configure(c => {
		c.AddAzureTextCompletionService("TextCompletion", openAiEndpoint, openAiApiKey);
		c.AddAzureTextEmbeddingGenerationService("TextEmbedding", openAiEndpoint, openAiApiKey);
	})
	.WithMemoryStorage(store)
	.Build();

async Task IndexContents(IKernel kernel, string collection)
{
	await kernel.Memory.SaveInformationAsync(collection, id: "info1", text: "My name is Andrea");
	await kernel.Memory.SaveInformationAsync(collection, id: "info2", text: "I currently work as a tourist operator");
	await kernel.Memory.SaveInformationAsync(collection, id: "info3", text: "I also currently work as a bus driver");
	await kernel.Memory.SaveInformationAsync(collection, id: "info4", text: "I sometimes work as a teacher");
}

ISKFunction PrepareSkillFunction(IKernel kernel)
{
	var promptTemplate = @"Use the following pieces of context to answer the question at the end. If you don't know the answer, don't try to make up an answer and answer with '모르겠어요.'. Answer in the langauge that used for the question.

{{$context}}

Question: {{$INPUT}}
Answer: 
";

	var config = new PromptTemplateConfig()
	{
		Schema = 1,
		Description = "Given a context answer a question",
		Type = "completion",
		Completion = new PromptTemplateConfig.CompletionConfig {
			MaxTokens = 2000,
			Temperature = 0d,
			TopP = 1d,
			PresencePenalty = 0d,
			FrequencyPenalty = 0d,
		},
	};
	
	return kernel.CreateSemanticFunction(
		promptTemplate, config, functionName: "answer", skillName: "qa");
}

async Task<string> Answer(IKernel kernel, string collection, string question)
{
	var results = await kernel.Memory.SearchAsync(collection, question).ToListAsync();
	var variables = new ContextVariables(question)
	{
		["context"] = results.Any()
			? string.Join("\n", results.Select(r => r.Metadata.Text))
			: "No context found for this question."
	};

	var function = kernel.Skills.GetFunction("qa", "answer");
	var result = await kernel.RunAsync(variables, function);
	return result.Result;
}

PrepareSkillFunction(kernel);
const string MemoryCollectionName = "aboutMe";
await IndexContents(kernel, MemoryCollectionName);

var questions = new[]
{
	"나의 이름이 뭔지 맞춰봐.",
	"나는 어디서 살고 있을까?",
	"what do I do for work?",
	"오늘 날씨 어때?",
};

foreach (var q in questions)
{
	var response = await Answer(kernel, MemoryCollectionName, q);
	Console.WriteLine(q + "\n" + response + "\n");
}

실행 예시

image

4개의 좋아요

그리고 메모리 스토리지로 SQLite를 지정해서 인덱싱을 수행해보니 그림과 같이 데이터가 저장됩니다. 이 데이터를 바탕으로 OpenAI와 커뮤니케이션하면서 커스터마이징된 학습 결과를 토대로 OpenAI가 답을 하도록 만들 수 있습니다.

4개의 좋아요