참고
이 튜토리얼에서는 시맨틱 커널 C# 라이브러리를 사용합니다. Python 라이브러리를 사용하는 튜토리얼은 시맨틱 커널 Python 통합 시작하기를 참조하세요.
MongoDB Vector Search를 Microsoft 시맨틱 커널과 통합하여 AI 애플리케이션을 빌드 하고 RAG(검색 강화 생성)를 구현 수 있습니다. 이 튜토리얼에서는 시맨틱 커널과 함께 MongoDB 벡터 검색을 사용하여 데이터에 시맨틱 검색 수행하고 RAG 구현 빌드 방법을 보여 줍니다. 구체적으로 다음 조치를 수행합니다.
환경을 설정합니다.
사용자 지정 데이터를 MongoDB 에 저장합니다.
데이터에 MongoDB Vector Search 인덱스 생성합니다.
데이터에 대해 시맨틱 검색 쿼리를 실행합니다.
MongoDB Vector Search를 사용하여 데이터에 대한 질문에 답변 RAG를 구현합니다.
배경
시맨틱 커널은 다양한 AI 서비스 및 플러그인을 애플리케이션과 결합할 수 있는 오픈 소스 SDK입니다. 시맨틱 커널은 RAG 를 포함한 다양한 AI 사용 사례에 사용할 수 있습니다.
MongoDB Vector Search를 시맨틱 커널과 통합하면 MongoDB 벡터 데이터베이스로 사용하고 MongoDB Vector Search를 사용하여 데이터에서 의미적으로 유사한 문서를 검색하여 RAG 를 구현. RAG에 대해 자세히 학습 MongoDB 사용한 검색-증강 생성(RAG)을 참조하세요.
전제 조건
이 튜토리얼을 완료하려면 다음 조건을 충족해야 합니다.
다음 MongoDB cluster 유형 중 하나입니다.
MongoDB 버전 6.0.11을 실행하는 Atlas 클러스터 7.0.2 또는 그 이상. IP 주소가 Atlas 프로젝트의 액세스 목록에 포함되어 있는지 확인하세요.
Atlas CLI 사용하여 생성된 로컬 Atlas 배포서버 입니다. 자세히 학습 로컬 Atlas 배포 만들기를 참조하세요.
검색 및 벡터 검색이 설치된 MongoDB Community 또는 Enterprise 클러스터.
OpenAI API 키입니다. API 요청에 사용할 수 있는 크레딧이 있는 OpenAI 계정이 있어야 합니다. OpenAI 계정 등록에 대해 자세히 학습하려면 OpenAI API 웹사이트를 참조하세요.
.NET 애플리케이션을 실행하기 위한 터미널 및 코드 편집기입니다.
C#/ .NET 설치되었습니다.
환경 설정
먼저 이 튜토리얼을 진행하려면 환경을 설정해야 합니다. 환경을 설정하려면 다음 단계를 완료하세요.
종속 요소를 설치합니다.
터미널에서 다음 명령을 실행하여 이 튜토리얼의 패키지를 설치합니다.
dotnet add package Microsoft.SemanticKernel dotnet add package Microsoft.SemanticKernel.Connectors.MongoDB --prerelease dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI dotnet add package Microsoft.Extensions.AI dotnet add package Microsoft.Extensions.AI.OpenAI dotnet add package Microsoft.Extensions.AI.Abstractions dotnet add package Microsoft.Extensions.VectorData.Abstractions dotnet add package SemanticKernelPooling.Connectors.OpenAI
환경 변수를 정의합니다.
터미널에서 다음 명령을 실행하여 MongoDB cluster의 SRV 연결 문자열 과 OpenAI API 키를 환경에 추가합니다.
export OPENAI_API_KEY="<Your OpenAI API Key>" export MONGODB_URI="<Your MongoDB Atlas SRV Connection String>"
참고
<connection-string>을 Atlas 클러스터 또는 로컬 Atlas 배포서버의 연결 문자열로 교체합니다.
연결 문자열은 다음 형식을 사용해야 합니다.
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
자세한 학습은 드라이버를 통해 클러스터에 연결을 참조하세요.
연결 문자열은 다음 형식을 사용해야 합니다.
mongodb://localhost:<port-number>/?directConnection=true
학습 내용은 연결 문자열을 참조하세요.
MongoDB 에 사용자 지정 데이터 저장
이 섹션에서는 애플리케이션의 서비스 및 플러그인을 관리 데 사용되는 기본 인터페이스인 커널을 초기화합니다. 커널을 통해 AI 서비스를 구성하고, MongoDB 벡터 데이터베이스 (메모리 저장 라고도 함)로 인스턴스화하고, 사용자 지정 데이터를 MongoDB cluster 에 로드합니다.
다음 코드를 복사하여 애플리케이션의 Program.cs 파일에 붙여넣습니다.
이 코드는 다음 작업을 수행합니다.
Semantic Kernel 및 필요한 모든 패키지를 가져옵니다.
환경에서 SRV 연결 문자열을 검색하여 Atlas 클러스터에 연결합니다.
환경에서 OpenAI API 키를 조회하고 OpenAI
text-embedding-ada-002임베딩 모델의 인스턴스를 생성합니다.Atlas를 메모리 저장소로 인스턴스화하고 다음 매개변수를 지정합니다.
semantic_kernel_db.records를 사용해 문서를 저장하는 컬렉션입니다.vector_index메모리 저장소를 쿼리하는 데 사용할 인덱스입니다.
CreateCollectionFromListAsync메서드를 호출하여semantic_kernel_db.records컬렉션을 샘플 문서로 채웁니다.semantic_kernel_db.records컬렉션 포함하는 변수recordCollection를 정의합니다.메모리에 텍스트를 저장 하고 조회 도움이 되는 두 가지 헬퍼 메서드를 만듭니다.
CreateRecord: 새DataModel객체 생성하는 팩토리입니다.CreateCollectionFromListAsync: 문자열 항목을 가져와서 문자열에 대한 임베딩을 생성하고, 해당 레코드를 만든 다음 해당 레코드를 Atlas cluster 의 컬렉션 에 업서트 메서드입니다.
MongoDB 컬렉션 에 저장된 문서의 구조를 정의하는
DataModel클래스를 만듭니다.
using Microsoft.Extensions.AI; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.MongoDB; using Microsoft.SemanticKernel.Data; using MongoDB.Bson; using MongoDB.Driver; using OpenAI; static class Program { static async Task Main(string[] args) { // Get connection string and OpenAI API Key var connectionString = Environment.GetEnvironmentVariable("MONGODB_URI"); if (connectionString == null) { Console.WriteLine("You must set your 'MONGODB_URI' environment variable."); Environment.Exit(0); } var openAIKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY"); if (openAIKey == null) { Console.WriteLine("You must set your 'OPENAPI_KEY' environment variable."); Environment.Exit(0); } // Create new OpenAI API Embedding Model var embeddingGenerator = new OpenAIClient(openAIKey) .GetEmbeddingClient("text-embedding-ada-002") .AsIEmbeddingGenerator(); // Instantiate MongoDB as a vector store var mongoClient = new MongoClient(connectionString); var options = new MongoVectorStoreOptions { EmbeddingGenerator = embeddingGenerator }; var vectorStore = new MongoVectorStore(mongoClient.GetDatabase("semantic_kernel_db"), options); // Sample data string[] lines = [ "I am a developer", "I started using MongoDB two years ago", "I'm using MongoDB Vector Search with Semantic Kernel to implement RAG", "I like coffee" ]; // Populate database with sample data await CreateCollectionFromListAsync<string, DataModel>(vectorStore, "records", lines, embeddingGenerator, CreateRecord); // Get the specific collection from the vector store var recordCollection = vectorStore.GetCollection<string, DataModel>("records"); } static DataModel CreateRecord(string text, ReadOnlyMemory<float> embedding) => new() { Key = ObjectId.GenerateNewId().ToString(), Text = text, Embedding = embedding }; static async Task CreateCollectionFromListAsync<TKey, TRecord>( this VectorStore vectorStore, string collectionName, string[] entries, IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator, Func<string, ReadOnlyMemory<float>, TRecord> createRecord) where TKey : notnull where TRecord : class { // Get and create collection if it doesn't exist var collection = vectorStore.GetCollection<TKey, TRecord>(collectionName); await collection.EnsureCollectionExistsAsync().ConfigureAwait(false); // Create records and generate embeddings for them var embeddings = await embeddingGenerator.GenerateAsync(entries); var records = entries.Zip(embeddings, (entry, embedding) => createRecord(entry, embedding.Vector)); // Add them to the database await collection.UpsertAsync(records).ConfigureAwait(false); } internal sealed class DataModel { [] [] public required String Key { get; init; } [] [] public required string Text { get; init; } [] public ReadOnlyMemory<float> Embedding { get; init; } } }
파일 저장한 후 다음 명령을 실행 데이터를 MongoDB 에 로드합니다.
dotnet run
팁
샘플 코드를 실행 후 Atlas 사용하는 경우 semantic_kernel_db.test Atlas UI 의 네임스페이스 로이동하여 벡터 임베딩을 확인할 수 있습니다.
Vector Search 쿼리 실행
벡터 임베딩을 만든 후에는 데이터에 대해 벡터 검색 쿼리를 실행 수 있습니다.
Program.cs 파일 의 Program 클래스 끝에 다음 코드를 추가하여 문자열 What is my job title?에 대한 기본 시맨틱 검색 수행합니다. 가장 관련성이 높은 문서 를 인쇄합니다.
1 // Create a text search instance using the InMemory vector store. 2 var textSearch = new VectorStoreTextSearch<DataModel>(recordCollection, embeddingGenerator); 3 4 // Search and return results as TextSearchResult items 5 var query = "What is my job title?"; 6 KernelSearchResults<TextSearchResult> textResults = await textSearch.GetTextSearchResultsAsync(query, new() { Top = 2, Skip = 0 }); 7 await foreach (TextSearchResult result in textResults.Results) 8 { 9 Console.WriteLine($"Answer: {result.Value}"); 10 } 11 Console.WriteLine("Search completed.");
파일을 저장한 후 다음 명령을 실행하여 시맨틱 검색 결과를 확인합니다.
dotnet run
Answer: I am a developer Search completed.
데이터에 대한 질문에 답변
이 섹션에서는 MongoDB 벡터 검색 및 시맨틱 커널을 사용한 RAG 구현 예시 보여줍니다. 이제 MongoDB Vector Search를 사용하여 의미적으로 유사한 문서를 조회 했으므로, Program.cs 의 Program 클래스 끝에 다음 코드 예시 붙여넣어 LLM 이 해당 문서를 기반으로 질문에 답변 합니다.
이 코드는 다음 작업을 수행합니다.
OpenAI의
gpt-4o를 채팅 모델로 사용하여 새 커널을 생성하여 응답을 생성합니다.벡터 저장 사용하여 새 텍스트 검색 인스턴스 만듭니다.
채팅 모델에 질문할 질문을 정의하고 벡터 저장 의 컨텍스트를 보유하기 위해 변수
retrievedContext를 초기화합니다.질문
When did I start using MongoDB?에 대해recordCollection에서 시맨틱 검색 수행하고 가장 관련성이 높은 검색 결과를 반환합니다.검색된 컨텍스트를 기반으로만 질문에 답변 하도록 AI 모델에 지시하는 프롬프트 템플릿을 빌드합니다.
커널의
CreateFunctionFromPrompt함수를 사용하여 채팅 프롬프트에서ragFunction라는 함수를 생성합니다.질문과 컨텍스트를 저장할 새 객체 생성하여 RAG 프롬프트에 대한 인수를 준비합니다.
커널의
InvokeAsync함수를 호출하여 다음 파라미터를 사용하여 채팅 모델에서 응답을 생성합니다.프롬프트 템플릿을 구성하는
ragFunction입니다.질문과 컨텍스트가 포함된
ragArguments입니다.
질문과 생성된 답변을 출력합니다.
// Create a kernel with OpenAI chat completion IKernelBuilder kernelBuilder = Kernel.CreateBuilder(); kernelBuilder.AddOpenAIChatCompletion( modelId: "gpt-4o", apiKey: openAIKey); Kernel kernel = kernelBuilder.Build(); // Create a text search instance using the vector store collection. var textSearch = new VectorStoreTextSearch<DataModel>(recordCollection, embeddingGenerator); // --- Modified RAG Section --- var userQuestion = "When did I start using MongoDB?"; string retrievedContext = "No relevant context found."; // Default // 1. Perform search to get context var searchResults = await textSearch.GetTextSearchResultsAsync(userQuestion, new() { Top = 1 }); // Get most relevant result await foreach (var result in searchResults.Results) { if (result.Value != null) { retrievedContext = result.Value; // Use the text from the search result as context break; // Take the most relevant result } } // 2. Define a prompt template that uses the retrieved context const string ragPromptTemplate = @" Context: {{$context}} Question: {{$question}} Based *only* on the context provided, answer the question. Answer: "; // 3. Create a function from the RAG prompt template var ragFunction = kernel.CreateFunctionFromPrompt(ragPromptTemplate); // 4. Prepare arguments for the RAG prompt var ragArguments = new KernelArguments { ["question"] = userQuestion, ["context"] = retrievedContext }; // 5. Invoke the RAG prompt var ragResult = await kernel.InvokeAsync(ragFunction, ragArguments); Console.WriteLine($"Question: {userQuestion}"); Console.WriteLine($"Retrieved Context: {retrievedContext}"); Console.WriteLine($"Answer: {ragResult.GetValue<string>()}"); // --- End of Modified RAG Section ---
파일을 저장한 후 다음 명령을 실행하여 응답을 생성합니다.
dotnet run
Question: When did I start using MongoDB? Retrieved Context: I started using MongoDB two years ago Answer: Two years ago.
팁
자체 데이터를 추가하고 코드의 다음 부분을 대체하여 다른 질문에 대한 응답을 생성할 수 있습니다.
var userQuestion = "When did I start using MongoDB?"
다음 단계
MongoDB는 다음과 같은 개발자 리소스도 제공합니다.