注意
本教程使用语义内核C#库。有关使用Python库的教程,请参阅语义内核Python集成入门。
您可以将 MongoDB Vector Search 与 Microsoft 语义内核 集成,以构建 AI 应用程序并实现检索增强生成 (RAG)。 本教程演示如何开始使用带有语义内核的MongoDB Vector Search 对数据执行语义搜索并构建RAG实施。具体来说,您执行以下操作:
设置环境。
在MongoDB中存储自定义数据。
对数据创建MongoDB Vector Search索引。
对您的数据运行语义搜索查询。
使用MongoDB Vector Search 来回答有关数据的问题,从而实施 RAG。
背景
Semantic Kernel 是一个开源 SDK,可允许您将各种 AI 服务和插件与您的应用程序相结合。您可以将 Semantic Kernel 用于各种 AI 应用场景,包括 RAG。
通过将MongoDB Vector Search 与语义内核集成,您可以将MongoDB用作矢量数据库,并使用MongoDB Vector Search 从数据中检索语义相似的文档来实现RAG。要学习;了解有关 RAG 的更多信息,请参阅 使用MongoDB进行检索增强生成 (RAG)。
先决条件
如要完成本教程,您必须具备以下条件:
以下MongoDB 集群类型之一:
使用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 还提供以下开发者资源: