注意
本教程使用语义内核 C# 库 。有关使用 Python 库的教程,请参阅 Semantic Kernel Python 集成入门。
您可以将 MongoDB Vector Search 与 Microsoft 语义内核 集成,以构建 AI 应用程序并实现检索增强生成 (RAG)。本教程演示如何开始使用带有语义内核的MongoDB Vector Search 对数据执行语义搜索并构建RAG实施。具体来说,您执行以下操作:
设置环境。
在MongoDB中存储自定义数据。
对数据创建MongoDB Vector Search索引。
对您的数据运行语义搜索查询。
使用MongoDB Vector Search 来回答有关数据的问题,从而实施 RAG。
背景
Semantic Kernel 是一个开源 SDK,可让您将各种 AI 服务和插件与您的应用程序相结合。 您可以将语义内核用于各种 AI 使用案例,包括RAG 。
通过将MongoDB Vector Search 与语义内核集成,您可以将MongoDB用作向量数据库,并使用MongoDB Vector Search 从数据中检索语义相似的文档来实现RAG。要学习;了解有关RAG的更多信息,请参阅使用MongoDB进行检索增强生成 (RAG)。
先决条件
如要完成本教程,您必须具备以下条件:
以下MongoDB 集群类型之一:
一个 Atlas 集群,运行 MongoDB 6.0.11、7.0.2 或更高版本。请确保您的 IP 地址包含在 Atlas 项目的访问列表中。
使用Atlas CLI创建的本地Atlas部署。要学习;了解更多信息,请参阅创建本地Atlas部署。
安装了Search 和 Vector Search的MongoDB Community或 Enterprise集群。
OpenAI API密钥。您必须拥有一个具有可用于API请求的积分的 OpenAI 帐户。要学习;了解有关注册 OpenAI 帐户的更多信息,请参阅 OpenAI API网站。
用于运行 .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集群的SRV连接字符串和 OpenAI API密钥添加到您的环境中。
export OPENAI_API_KEY="<Your OpenAI API Key>" export MONGODB_URI="<Your MongoDB Atlas SRV Connection String>"
注意
将 <connection-string> 替换为您的 Atlas 集群或本地部署的连接字符串。
连接字符串应使用以下格式:
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
要学习;了解更多信息,请参阅通过驱动程序连接到集群。
在MongoDB中存储自定义数据
在本部分中,您将初始化内核,它是用于管理应用程序的服务和插件的主接口。通过内核,您可以配置AI服务,将MongoDB实例化为向量数据库(也称为内存存储),并将自定义数据加载到MongoDB 集群。
将以下代码复制并粘贴到应用程序的 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:一种方法,用于获取字符串条目、为字符串生成嵌入、创建相应的记录,然后将这些记录更新或插入(upsert)到Atlas 集群的集合中。
创建一个
DataModel类,用于定义存储在MongoDB集合中的文档的结构。
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 ,则可以导航到Atlas 用户界面中的 semantic_kernel_db.test命名空间来验证向量嵌入。
运行向量搜索查询
创建向量嵌入后,您可以对数据运行向量搜索查询。
在 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 Vector Search 和语义内核实施RAG 的示例。现在,您已使用MongoDB Vector Search检索语义相似的文档,请将以下代码示例粘贴到 Program 类的末尾 Program.cs 中,以提示 法学硕士 根据这些文档回答问题。
此代码执行以下操作:
使用 OpenAI 的
gpt-4o创建新内核作为聊天模型以生成响应。使用向量存储创建新的文本搜索实例。
定义向聊天模型询问的问题,并初始化变量
retrievedContext以保存向量存储中的上下文。在
recordCollection中对问题When did I start using MongoDB?执行语义搜索,并返回最相关的搜索结果。构建提示模板,指示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 还提供以下开发者资源: