Microsoft MVP성태의 닷넷 이야기
.NET Framework: 2125. C# - Semantic Kernel의 Semantic Memory 사용 예제 [링크 복사], [링크+제목 복사],
조회: 14852
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

(시리즈 글이 8개 있습니다.)
.NET Framework: 2117. C# - (OpenAI 기반의) Microsoft Semantic Kernel을 이용한 자연어 처리
; https://www.sysnet.pe.kr/2/0/13345

.NET Framework: 2118. C# - Semantic Kernel의 Prompt chaining 예제
; https://www.sysnet.pe.kr/2/0/13347

.NET Framework: 2119. C# - Semantic Kernel의 "Basic Loading of the Kernel" 예제
; https://www.sysnet.pe.kr/2/0/13348

.NET Framework: 2120. C# - Semantic Kernel의 Skill과 Function 사용 예제
; https://www.sysnet.pe.kr/2/0/13349

.NET Framework: 2121. C# - Semantic Kernel의 대화 문맥 유지
; https://www.sysnet.pe.kr/2/0/13352

.NET Framework: 2123. C# - Semantic Kernel의 ChatGPT 대화 구현
; https://www.sysnet.pe.kr/2/0/13355

.NET Framework: 2124. C# - Semantic Kernel의 Planner 사용 예제
; https://www.sysnet.pe.kr/2/0/13357

.NET Framework: 2125. C# - Semantic Kernel의 Semantic Memory 사용 예제
; https://www.sysnet.pe.kr/2/0/13358




C# - Semantic Kernel의 Semantic Memory 사용 예제

ASK, Kernel, Planner, Skill을 지나 이제 Memory 예제까지 왔습니다. ^^

samples/notebooks/dotnet/06-memory-and-embeddings.ipynb
; https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/06-memory-and-embeddings.ipynb

Memory는 간단하게 설명하면 전체적인 문맥을 기억하기 위한 수단입니다. 문맥이라고 하니, 지난 Context 예제가 있었는데요,

C# - Semantic Kernel의 대화 문맥 유지
; https://www.sysnet.pe.kr/2/0/13352

사실 위에서 구현한 ContextVariables는 그다지 특별한 것이 아니고, 지금까지의 대화 내용을 전부 누적시켜 설정하는 것에 지나지 않습니다. 일례로, 이전 예제의 코드를 보면,

var context = new ContextVariables();
var history = "";
context.Set("history", history);

...[생략]...

var bot_answer = await kernel.RunAsync(context, skill["Chat"]);
Console.WriteLine(bot_answer);

history += $"\nHuman: {human_input}\nAssistant: {bot_answer}\n";
context.Update(history);

history 문자열에 대화의 내용을 전부 합쳐 Update 시킨 후 RunAsync에 전달하는 식입니다. 여기서 문제는, 이런 식으로 누적시켜 대화를 이어나가면 결국 Model에서 정한 Token 제약에 금방 걸리고 맙니다.

바로 이런 문제를 해결하기 위해, 단기/장기로 대화 상태를 저장할 수 있는 메모리가 필요한 것입니다. 이 외에도, 메모리를 이용하면 또 다른 활용이 가능합니다. 예를 들어, 사내에서 개발한 제품의 매뉴얼이 있다고 가정해 보겠습니다. 물론, OpenAI가 크롤링한 웹 데이터에 해당 매뉴얼이 있다면 상관없겠지만 그렇지 않을 수도 있습니다. 그런 상황이라면 그 매뉴얼 전체를 Chat 내에서 인식시키려 할 때 또다시 Token 제약에 걸립니다.

이런 문제를 Memory를 이용해 해결할 수 있는데요, 이를 위해서는 2가지 구성요소(Memory Storage와 Embedding backend)를 Kernel에 추가해야 합니다. 방법은 예제 코드에 잘 나옵니다. ^^

우선 Embedding backend는 KernelConfig을 이용해 새롭게 "text-embedding-ada-002" 모델을 추가합니다.

KernelConfig kernelConfig = new KernelConfig();
kernelConfig.AddOpenAITextCompletionService("default", "text-davinci-003", apiKey);
kernelConfig.AddOpenAITextEmbeddingGenerationService("ada", "text-embedding-ada-002", apiKey);

그다음 Memory Storage는, Application이 실행 중일 때만 보관이 되도록 VolatileMemoryStore를 사용합니다.

var kernel = Kernel.Builder
    .WithConfiguration(kernelConfig)
    .WithMemoryStorage(new VolatileMemoryStore())
    .Build();

이 외에도, Azure Cosmos DB, PostgreSQL, SQLite 등으로 유지할 수 있다고 합니다. nuget을 찾아보면 관련 타입들이 아마도 다음의 패키지들에 포함된 것 같습니다.

Microsoft.SemanticKernel.Connectors.Memory.Sqlite
; https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.Memory.Sqlite

Microsoft.SemanticKernel.Connectors.Memory.Qdrant 
; https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.Memory.Qdrant

Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch
; https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch

Microsoft.SemanticKernel.Connectors.Memory.Postgres
; https://github.com/microsoft/semantic-kernel/tree/main/dotnet/src/Connectors/Connectors.Memory.Postgres

당연히 모두 현재(2023-05-17)는 Preview 버전이고 PostgreSQL의 경우에는 찾을 수 없었습니다.

자, 그럼 이제 남은 것은 Memory Store에 문맥 정보를 추가하는 일이 남았는데요, 이를 위해 SaveInformationAsync 메서드를 사용할 수 있습니다.

const string MemoryCollectionName = "aboutMe";

await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea");
await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I currently work as a tourist operator");
await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I currently live in Seattle and have been living there since 2005");
await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015");
await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info5", text: "My family is from New York");

여기서 문맥 정보에 대한 식별자를 줬기 때문에 관련 문맥을 사용할 때도 동일한 식별자를 줘야 합니다. 아래는 위와 같은 문맥이 있는 상태에서 질문하는 코드를 보여줍니다.

var questions = new[]
{
    "what is my name?",
    "where do I live?",
    "where is my family from?",
    "where have I travelled?",
    "what do I do for work?",
};

foreach (var q in questions)
{
    var response = await kernel.Memory.SearchAsync(MemoryCollectionName, q).FirstOrDefaultAsync();
    Console.WriteLine(q + " " + response?.Metadata.Text);
}

/* 출력 결과
what is my name? My name is Andrea
where do I live? I currently live in Seattle and have been living there since 2005
where is my family from? My family is from New York
where have I travelled? I visited France and Italy five times since 2015
what do I do for work? I currently work as a tourist operator
*/

오호~~~ 점점 더 예제가 재미있어지는군요. ^^

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




참고로, 이때 문맥으로 저장하는 텍스트는 단순히 문자열로 저장되는 것이 아니고, 우리가 지정한 Embedding backend, 즉 위의 예제에서는 "text-embedding-ada-002" 모델로 벡터값으로 인코딩된 유형으로 저장됩니다. 관련해서는 아래의 문서를 참조하라고 하는군요. ^^

What are Embeddings?
; https://learn.microsoft.com/en-us/semantic-kernel/concepts-ai/embeddings

그러고 보면, 지난 예제에서 "text-embedding-ada-002" 모델을 사용해 "안녕하세요, 책 좀 추천해 주세요." 문자열을 전송했더니 다음과 같은 결과가 나왔는데요,

( 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0, 0 0 0 0 0 1 0 0, 0 0 0, 0 0 0, 0 0, 0 0, 0 0 0, 0 0 0 0,0 0 0, 0 0 0,0,0 0 0 0, 0 0 0 0, 0 0 0,0,0 0, 0,0,0,,0,0,0,0 1 0, 0,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,0,0, 0,0,0, 0,0,0,0,0,, 0,0,0, 0,0,0,0,0,,0,0,0,0, 1 0,0,0,0,0,0,0,0, 0,0,0,0, 0,0,0, 0,0,0, 0 1 0,0,0,0,0,,, 0,0,0,0, 0,0,0, 0,0, 0,0,0, 0,0, 0,0, 0,0, 0,0,0, 0,0, 0,0,1, 0,0, 0,0, 0,0,0,0, 0,0,0, 0,0, 1,0,0, 0,0, 0,0,0, 0,0,1,0,0,0,0,1, 0,0,0, 0,0,0,1,1,0, 0,0,0,0, 1,0,0,1,1,0, 1,0,0,0,0,0, 1,0,0,0,0,1,0,1,1, 1,0,0,0,1,1, 1,0,1,1,0, 0,0,0,0,0, 0,0, 1, 0,0,1,0,1,1,1, 0,0,0,1,0,1,1, 0,0,0,0, 0,0, 1,0,1,0, 1,1,1,0, 0,0,0, 1,0,0,0,1,1, 1,0,1,1,1, 0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1, 1,0,0,0,0, 1,0,1,1,1,1, 0,0,0,0, 1,1,0,1,0,1,1, 1,0,0,0, 0,0,0,1,,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

아마도 저것이 "vectors or arrays of numbers that represent the meaning and the context of tokens processed by the model."인 듯합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/8/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2023-06-01 08시59분
정성태

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
14000정성태8/18/2025253오류 유형: 979. ERROR: failed to solve: failed to read dockerfile: open Dockerfile: no such file or directory
13999정성태8/15/2025780닷넷: 2355. C# 14 - (8) null 조건부 연산자 개선 - 대입문에도 사용 가능파일 다운로드1
13998정성태8/14/2025822닷넷: 2354. C# 14 - (7) 확장 메서드에 정적 메서드와 속성 지원을 위한 전용 구문 추가파일 다운로드1
13997정성태8/14/2025989Linux: 120. docker 컨테이너로 매핑된 볼륨에 컨테이너 측의 사용자 ID를 유지하면서 복사하는 방법
13996정성태8/13/2025581오류 유형: 978. Unable to find the requested .Net Framework Data Provider.
13995정성태8/13/2025630개발 환경 구성: 754. Visual C++ - 리눅스 빌드를 위한 Ubuntu 18 docker 컨테이너 설정
13994정성태8/12/2025643오류 유형: 977. SQL Server - User, group, or role '...' already exists in the current database. (Microsoft SQL Server, Error: 15023)
13993정성태8/11/2025976오류 유형: 976. Microsoft.ML.OnnxRuntimeGenAI 패키지 사용 시 "cublasLt64_12.dll" which is missing. (Error 126: "The specified module could not be found.") 오류
13992정성태8/11/20251160닷넷: 2353. C# - Foundry Local을 이용한 gpt-oss-20b 모델 사용파일 다운로드1
13991정성태8/9/20251082오류 유형: 975. winget - Foundry Local 패키지 업데이트가 안 되는 문제
13990정성태8/8/2025831Windows: 283. Time zone 설정이 없는 Windows Server 2025
13989정성태8/8/20251221닷넷: 2352. C# - Windows S-mode 환경인지 체크하는 방법파일 다운로드1
13988정성태8/8/20251365오류 유형: 974. 비주얼 스튜디오 업데이트 시 잠김 파일 경고 - Visual Studio Standard Collector Service 150 (VSStandardCollectorService150)
13987정성태8/7/20251030닷넷: 2351. C# 14 - (6) event와 생성자에도 partial 메서드 적용파일 다운로드1
13986정성태8/6/20251115닷넷: 2350. C# 14 - (5) 람다 매개 변수에 접근자가 있는 경우에도 타입 생략 가능파일 다운로드1
13985정성태8/6/20251471오류 유형: 973. "wsl --install" 명령어 수행 시 "The server name or address could not be resolved"
13984정성태8/6/20251245Windows: 282. 윈도우 운영체제에 추가된 ssh 서버(Win32-OpenSSH)
13983정성태8/4/20251332오류 유형: 972. Microsoft.Data.SqlClient 6.1.0 버전부터 .NET 8 이상만 지원
13982정성태8/2/20251752개발 환경 구성: 753. CentOS 7 컨테이너 내에서 openssh 서버 호스팅
13981정성태8/1/20251405오류 유형: 971. CentOS 7에서 yum 사용 시 "Could not resolve host: mirrorlist.centos.org; Unknown error"
13980정성태7/31/20251581Linux: 119. eBPF - BPF_PROG_TYPE_CGROUP_SOCK 유형에서 정상 동작하지 않는 BPF_CORE_READ (2)
13979정성태7/30/20251879Linux: 118. eBPF - BPF_PROG_TYPE_CGROUP_SOCK 유형에서 정상 동작하지 않는 BPF_CORE_READ
13978정성태7/29/20251705오류 유형: 970. 파일 복사 시 "Data error (cyclic redundancy check). (0x80070017)" 에러
13977정성태7/28/20252020닷넷: 2349. C# 14 - (4) 문자열 리터럴을 utf-8 인코딩으로 저장파일 다운로드1
13976정성태7/25/20251867닷넷: 2348. C# - 카카오 카나나 모델 + Microsoft.ML.OnnxRuntimeGenAI 예제파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...