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

... 151  152  153  154  155  156  [157]  158  159  160  161  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1124정성태9/17/201126409.NET Framework: 240. System.Collections.ArrayList가 .NET 4.5에서 지원이 안된다??? [2]
1123정성태9/17/201165219Windows: 53. 2가지 모드의 Internet Explorer 10과 ActiveX [6]
1122정성태9/16/201132916Windows: 52. 새롭게 지원되는 WinRT 응용 프로그램 [7]
1121정성태9/12/201127665Java: 5. WTP 내에서 서블릿을 실행하는 환경
1120정성태9/11/201127593.NET Framework: 239. IHttpHandler.IsReusable 속성 이야기파일 다운로드1
1119정성태9/11/201126688Java: 4. 이클립스에 WTP SDK가 설치되지 않는다면? [2]
1118정성태9/11/201138331Java: 3. 이클립스에서 서블릿 디버깅하는 방법 [4]
1117정성태9/9/201125618제니퍼 .NET: 17. 제니퍼 닷넷 적용 사례 (2) - 웹 애플리케이션 hang의 원인을 알려주다.
1116정성태9/8/201156673Java: 2. 자바에서 "Microsoft SQL Server JDBC Driver" 사용하는 방법
1115정성태9/4/201130195Java: 1. 닷넷 개발자가 처음 실습해 본 서블릿
1114정성태9/4/201134724Math: 2. "Zhang Suen 알고리즘(세선화, Thinning/Skeletonization)"의 C# 버전 [4]파일 다운로드1
1113정성태9/2/201134283개발 환경 구성: 129. Hyper-V에 CentOS 설치하기
1112정성태9/2/201151050Linux: 1. 리눅스 <-> 윈도우 원격 접속 프로그램 사용 [3]
1111정성태8/29/201125438제니퍼 .NET: 16. 적용 사례 (1) - DB Connection Pooling을 사용하지 않았을 때의 성능 저하를 알려주다. [1]
1110정성태8/26/201126788오류 유형: 136. RDP 접속이 불연속적으로 끊기는 문제
1109정성태8/26/201129685오류 유형: 135. 어느 순간 Active Directory 접속이 안되는 문제
1108정성태8/22/201131173오류 유형: 134. OLE/COM Object Viewer - DllRegisterServer in IVIEWERS.DLL failed. [1]
1107정성태8/21/201128987디버깅 기술: 43. Windows Form의 Load 이벤트에서 발생하는 예외가 Visual Studio에서 잡히지 않는 문제
1106정성태8/20/201127279웹: 26. FailedRequestTracing 설정으로 인한 iisexpress.exe 비정상 종료 문제
1105정성태8/19/201127206.NET Framework: 238. Web Site Model 프로젝트에서 Trace.WriteLine 출력이 dbgview.exe에서 확인이 안 되는 문제파일 다운로드1
1104정성태8/19/201127410웹: 25. WebDev보다 IIS Express가 더 나은 점 - 다중 가상 디렉터리 매핑 [1]
1103정성태8/19/201133311오류 유형: 133. WCF 포트 바인딩 실패 오류 - TCP error(10013) [1]
1102정성태8/19/201131031Math: 1. 방탈출3 - Room 10의 '중복가능한 조합' 문제를 위한 C# 프로그래밍 [2]파일 다운로드1
1101정성태8/19/201129686.NET Framework: 237. WCF AJAX 서비스와 JavaScript 간의 DateTime 연동 [1]파일 다운로드1
1100정성태8/17/201128793.NET Framework: 236. SqlDbType - DateTime, DateTime2, DateTimeOffset의 차이점파일 다운로드1
1099정성태8/15/201128236오류 유형: 132. 어느 순간 갑자기 접속이 안 되는 TFS 서버
... 151  152  153  154  155  156  [157]  158  159  160  161  162  163  164  165  ...