Microsoft MVP성태의 닷넷 이야기
.NET Framework: 2125. C# - Semantic Kernel의 Semantic Memory 사용 예제 [링크 복사], [링크+제목 복사],
조회: 12084
글쓴 사람
정성태 (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분
정성태

... 91  92  93  94  95  96  97  98  99  100  101  102  103  104  [105]  ...
NoWriterDateCnt.TitleFile(s)
11299정성태9/9/201719740개발 환경 구성: 330. Hyper-V VM의 Internal Network를 Private 유형으로 만드는 방법
11298정성태9/8/201723102VC++: 119. EnumProcesses / EnumProcessModules API 사용 시 주의점 [1]
11297정성태9/8/201719727디버깅 기술: 96. windbg - 풀 덤프에 포함된 모든 닷넷 모듈을 파일로 저장하는 방법
11296정성태9/8/201722909웹: 36. Edge - "이 웹 사이트는 이전 기술에서 실행되며 Internet Explorer에서만 작동합니다." 끄는 방법
11295정성태9/7/201720345디버깅 기술: 95. Windbg - .foreach 사용법
11294정성태9/4/201720049개발 환경 구성: 329. 마이크로소프트의 CoreCLR 프로파일러 예제 빌드 방법 [1]
11293정성태9/4/201720601개발 환경 구성: 328. Visual Studio(devenv.exe)를 배치 파일(.bat)을 통해 실행하는 방법
11292정성태9/4/201718867오류 유형: 419. Cannot connect to WMI provider - Invalid class [0x80041010]
11291정성태9/3/201720704개발 환경 구성: 327. 아파치 서버 2.4를 위한 mod_aspdotnet 마이그레이션
11290정성태9/3/201723935개발 환경 구성: 326. 아파치 서버에서 ASP.NET을 실행하는 mod_aspdotnet 모듈 [2]
11289정성태9/3/201721597개발 환경 구성: 325. GAC에 어셈블리 등록을 위해 gacutil.exe을 사용하는 경우 주의 사항
11288정성태9/3/201718307개발 환경 구성: 324. 윈도우용 XAMPP의 아파치 서버 구성 방법
11287정성태9/1/201727580.NET Framework: 680. C# - 작업자(Worker) 스레드와 UI 스레드 [11]
11286정성태8/28/201714889기타: 67. App Privacy Policy
11285정성태8/28/201723488.NET Framework: 679. C# - 개인 키 보안의 SFTP를 이용한 파일 업로드파일 다운로드1
11284정성태8/27/201721513.NET Framework: 678. 데스크톱 윈도우 응용 프로그램에서 UWP 라이브러리를 이용한 비디오 장치 열람하는 방법 [1]파일 다운로드1
11283정성태8/27/201717283오류 유형: 418. CSS3117: @font-face failed cross-origin request. Resource access is restricted.
11282정성태8/26/201719725Math: 22. 행렬로 바라보는 피보나치 수열
11281정성태8/26/201721521.NET Framework: 677. Visual Studio 2017 - NuGet 패키지를 직접 참조하는 PackageReference 지원 [2]
11280정성태8/24/201718567디버깅 기술: 94. windbg - 풀 덤프에 포함된 모든 모듈을 파일로 저장하는 방법
11279정성태8/23/201730178.NET Framework: 676. C# Thread가 Running 상태인지 아는 방법
11278정성태8/23/201718320오류 유형: 417. TFS - Warning - Unable to refresh ... because you have a pending edit. [1]
11277정성태8/23/201719568오류 유형: 416. msbuild - error MSB4062: The "TransformXml" task could not be loaded from the assembly
11276정성태8/23/201723911.NET Framework: 675. C# - (파일) 확장자와 연결된 실행 파일 경로 찾기 [2]파일 다운로드1
11275정성태8/23/201732880개발 환경 구성: 323. Visual Studio 설치 없이 빌드 환경 구성 - Visual Studio 2017용 Build Tools [1]
11274정성태8/22/201719480.NET Framework: 674. Thread 타입의 Suspend/Resume/Join 사용 관련 예외 처리
... 91  92  93  94  95  96  97  98  99  100  101  102  103  104  [105]  ...