Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
C#chevron-right

Introdução ao Semantic Kernel da Microsoft em C# e MongoDB Atlas

Luce Carter10 min read • Published Aug 05, 2024 • Updated Oct 10, 2024
IA.NETAzureC#
APLICATIVO COMPLETO
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
O Semantic Kernel se tornou extremamente popular no ecossistema da Microsoft. Na verdade, no Microsoft Build, Semantic Kernel e AI com MongoDB foram os tópicos mais discutidos em nosso estande.
Semantic Kernel é o AI SDK da Microsoft disponível em Java, Python e C#. Ele permite que você crie aplicativos de IA poderosos encadeando plug-ins personalizados prontos para uso, criados pela comunidade. Esses plug-ins trabalham juntos para criar planos que permitem realizar tarefas complexas. Isso pode ser qualquer coisa, desde arrumar a área de trabalho deScott Hanselman até resumir um bloco de texto e enviar o resumo por e-mail. As possibilidades são infinitas!
O Semantic Kernel é uma ferramenta para criar aplicativosde geração aumentada de recuperação (RAG). As partes R e A vêm da recuperação de informações a serem usadas como contexto na entrada do modelo de linguagem grande (LLM). É aqui que entra o MongoDB . O MongoDB é uma opção para armazenar dados, incluindo incorporações que representam esses dados, e até mesmo oferece a capacidade de Atlas Search os dados usando o Atlas Vector Search.
O Semantic Kernel tem suporte para o MongoDB Atlas graças a um connector. Portanto, você não apenas pode armazenar seus dados no MongoDB, incluindo as incorporações, mas também usa automaticamente o MongoDB Atlas Vector Search sob o capô para recuperar os resultados. Você obtém o melhor do Semantic Kernel e o melhor do MongoDB, o banco de dados de documentos mais popular para desenvolvedores C#!
Neste tutorial, você aprenderá como começar a usar o Semantic Kernel e o MongoDB, aproveitando o connector e o plugin-in SemanticTextMemorypara criar um bot que recomenda um filme para assistir, usando a OpenAI para criar incorporações e pesquisando o filme de amostra em nosso conjunto de dados de amostra.
Prefere aprender por meio de conteúdo em vídeo? Então assista à versão em vídeo disponível no Youtube!

Pré-requisitos

Para acompanhar este tutorial, você precisará de algumas coisas:
  • Um cluster MongoDB M0
  • Os dados de amostra carregados naquele cluster
  • Uma conta gratuita da OpenAI e chave de API do projeto
  • .NET 8 ou superior
  • Um IDE ou editor de texto para acompanhar
Se preferir simplesmente ler o código, você pode encontrá-lo no GitHub. Tem duas ramificações, dependendo se você tem acesso ao Azure OpenAI ou deseja usar o OpenAI. Usaremos o OpenAI para este tutorial, pois ele é gratuito e aberto a todos no momento em que escrevemos.

Criando o projeto

Agora que você tem os pré-requisitos, é hora de criar o projeto e adicionar os pacotes NuGet necessários para criar o bot.
  1. Crie um novo projeto de console, usando seu IDE ou por meio da DotNet CLI.
  2. Adicione os seguintes pacotes NuGet ao seu novo projeto
  • Microsoft.SemanticKernel
  • Microsoft.SemanticKernel.Connectors.MongoDB (NB: isso está em pré-lançamento)
  • Microsoft.SemanticKernel.Connectors.OpenAI

Configurando nossa configuração

Existem algumas variáveis de que precisaremos ao longo deste tutorial, portanto, começaremos configurando-as em Program.cs.
Como queremos criar pelo menos um outro método neste tutorial, também mudaremos para a estrutura tradicional da nossa classe de programa. Substitua o conteúdo pelo seguinte:
1using Microsoft.SemanticKernel.Memory;
2
3#pragma warning disable SKEXP0001, SKEXP0010, SKEXP0020, SKEXP0050
4public static class Program {
5 static string TextEmbeddingModelName = "text-embedding-ada-002";
6 static string OpenAIAPIKey = "<YOUR OPENAI PROJECT API KEY>";
7
8 static string MongoDBAtlasConnectionString = "<YOUR ATLAS CONNECTION STRING>";
9 static string SearchIndexName = "default";
10 static string DatabaseName = "semantic-kernel";
11 static string CollectionName = "movies";
12 static MemoryBuilder memoryBuilder;
13
14 public static async Task Main(string[] args) {
15
16 }
17}
A adiçãodopragma warning disable se deve ao fato de que muitos dos recursos são experimentais e isso desativará os erros.
Go em frente e substitua os espaços reservados para OpenAI e Atlas por seus próprios valores.

Configurar o plugin de memória e o armazenamento de memória

Você deve ter notado na última seção que adicionou uma variável MemoryBuilder. Esse construtor é o que dá acesso ao plug-in de memória, um plug-in pronto para uso para trabalhar com dados armazenados.
Então agora vamos configurar este plugin, usar este construtor e também conectá-lo ao MongoDB Atlas como nosso armazenamento de memória.
Cole o código abaixo dentro do seu Main método:
1memoryBuilder = new MemoryBuilder();
2
3 memoryBuilder.WithOpenAITextEmbeddingGeneration(
4 TextEmbeddingModelName,
5 OpenAIAPIKey
6 );
O Construtor de Memória vem com alguns métodos auxiliares. Neste caso, estamos usando o WithOpenAITextEmbeddingGeneration que ajuda você a configurar o plugin de memória.
Como estamos trabalhando com texto neste projeto, precisamos ser capazes de gerar embeddings de texto para que nossos dados sejam usados na pesquisa. É aqui que entra o OpenAI. Ao passar a esse método o nome do modelo que queremos usar e a chave da API OpenAI, o plugin tem tudo de que precisa para lidar automaticamente com o resto para nós — ótimo!
Certifique-se de que as seguintes instruções de uso estão presentes no arquivo:
1using Microsoft.SemanticKernel;
2using Microsoft.SemanticKernel.Connectors.MongoDB;
3using Microsoft.SemanticKernel.Connectors.OpenAI;
4using Microsoft.SemanticKernel.Memory;
5using MongoDB.Driver;
6using Kernel = Microsoft.SemanticKernel.Kernel;
Usar um banco de dados que suporta vetores e pesquisas de vetores, como o MongoDB Atlas, é uma parte fundamental da adição das partes de recuperação e aumento aos seus aplicativos RAG.
O MongoDB Connector do Semantic Kernel adiciona suporte não apenas para o uso do MongoDB como armazenamento de dados para suas incorporações, mas também para os recursos de pesquisa vetorial do MongoDB para realizar a pesquisa.
Cole o código abaixo após o anterior, dentro do seu Main método :
1var mongoDBMemoryStore = new MongoDBMemoryStore(MongoDBAtlasConnectionString, DatabaseName, SearchIndexName);
2 memoryBuilder.WithMemoryStore(mongoDBMemoryStore);
3 var memory = memoryBuilder.Build();
Simples assim, com algumas linhas de código, temos o plugin de memória configurado e ele está configurado para usar o MongoDB.

Adicionando documentos ao nosso armazenamento de memória

Os dados de amostra do MongoDB vêm com diferentes bancos de dados e collection para uma variedade de casos de uso. Uma das mudanças recentes foi no banco de dados sample_mflix. Esse banco de dados existe nos dados de amostra há muito tempo, mas adicionamos recentemente uma nova collection dentro do banco de dados chamada embedded_movies. Você já deve ter notado isso se tiver navegado em seu novo cluster. Essa collection contém incorporações vetoriais no campo plot a partir de um grande número de documentos da collection de filmes e facilita muito para os desenvolvedores experimentar o Atlas Vector Search do MongoDB em uma variedade de linguagens de programação.
Em um mundo ideal, usaremos esta coleção com o Semantic Kernel. Infelizmente, há uma limitação com o Semantic Kernel no nome do campo que contém o valor de incorporações, bem como na forma dos documentos que ele pode usar. Então, por esse motivo, para fins deste tutorial, vamos importar alguns documentos do nosso banco de dados sample_mflix e salvá-los em uma nova coleção, usando o Semantic Kernel. Isso gerará as incorporações automaticamente usando o OpenAI e as salvará no formato que o Semantic Kernel pode usar posteriormente.
Primeiro, precisamos criar um modelo que represente o documento de filme. Portanto, crie uma nova classeMovie.cs em seu projeto e cole o seguinte:
1public class Movie
2{
3 [BsonId]
4 [BsonRepresentation(BsonType.ObjectId)]
5 public string Id { get; set; }
6
7 [BsonElement("plot")]
8 public string Plot { get; set; }
9
10 [BsonElement("genres")]
11 public List<string> Genres { get; set; }
12
13 [BsonElement("runtime")]
14 public int Runtime { get; set; }
15
16 [BsonElement("cast")]
17 public List<string> Cast { get; set; }
18
19 [BsonElement("num_mflix_comments")]
20 public int NumMflixComments { get; set; }
21
22 [BsonElement("poster")]
23 public string Poster { get; set; }
24
25 [BsonElement("title")]
26 public string Title { get; set; }
27
28 [BsonElement("fullplot")]
29 public string Fullplot { get; set; }
30
31 [BsonElement("languages")]
32 public List<string> Languages { get; set; }
33
34 [BsonElement("released")]
35 public DateTime Released { get; set; }
36
37 [BsonElement("directors")]
38 public List<string> Directors { get; set; }
39
40 [BsonElement("writers")]
41 public List<string> Writers { get; set; }
42
43 [BsonElement("awards")]
44 public Awards Awards { get; set; }
45
46 [BsonElement("rated")]
47 public string? Rated { get; set; }
48
49 [BsonElement("lastupdated")]
50 public string Lastupdated { get; set; }
51
52
53 [BsonElement("year")]
54 public object Year { get; set; }
55
56 [BsonElement("imdb")]
57 public Imdb Imdb { get; set; }
58
59 [BsonElement("countries")]
60 public List<string> Countries { get; set; }
61
62 [BsonElement("type")]
63 public string Type { get; set; }
64
65 [BsonElement("tomatoes")]
66 public Tomatoes Tomatoes { get; set; }
67
68 [BsonElement("metacritic")]
69 public int? Metacritic { get; set; }
70
71 [BsonElement("awesome")]
72 public bool? Awesome { get; set; }
73}
74
75public class Awards
76{
77 [BsonElement("wins")]
78 public int Wins { get; set; }
79
80 [BsonElement("nominations")]
81 public int Nominations { get; set; }
82
83 [BsonElement("text")]
84 public string Text { get; set; }
85}
86
87public class Imdb
88{
89 [BsonElement("id")]
90 public object ImdbId { get; set; }
91
92 [BsonElement("votes")]
93 public object Votes { get; set; }
94
95 [BsonElement("rating")]
96 public object Rating { get; set; }
97}
98
99public class Tomatoes
100{
101 [BsonElement("viewer")]
102 public Viewer Viewer { get; set; }
103
104 [BsonElement("lastUpdated")]
105 public DateTime LastUpdated { get; set; }
106
107 [BsonElement("dvd")]
108 public DateTime? DVD { get; set; }
109
110 [BsonElement("website")]
111 public string? Website { get; set; }
112
113 [BsonElement("production")]
114 public string? Production { get; set; }
115
116 [BsonElement("critic")]
117 public Critic? Critic { get; set; }
118
119 [BsonElement("rotten")]
120 public int? Rotten { get; set; }
121
122 [BsonElement("fresh")]
123 public int? Fresh { get; set; }
124
125 [BsonElement("boxOffice")]
126 public string? BoxOffice { get; set; }
127
128 [BsonElement("consensus")]
129 public string? Consensus { get; set; }
130
131}
132
133public class Viewer
134{
135 [BsonElement("rating")]
136 public double Rating { get; set; }
137
138 [BsonElement("numReviews")]
139 public int NumReviews { get; set; }
140
141 [BsonElement("meter")]
142 public int Meter { get; set; }
143}
144
145public class Critic
146{
147 [BsonElement("rating")]
148 public double Rating { get; set; }
149
150 [BsonElement("numReviews")]
151 public int NumReviews { get; set; }
152
153 [BsonElement("meter")]
154 public int Meter { get; set; }
155}
Se o seu IDE ou editor de texto não adicionar automaticamente as instruções de uso necessárias, adicione o seguinte na parte superior da classe:
1using MongoDB.Bson;
2using MongoDB.Bson.Serialization.Attributes;
Agora que temos o modelo disponível que reflete nosso documento, é hora de usá-lo.
Cole o seguinte código na sua classeProgram.cs:
1private static async Task FetchAndSaveMovieDocuments(ISemanticTextMemory memory, int limitSize)
2 {
3 MongoClient mongoClient = new MongoClient(MongoDBAtlasConnectionString);
4 var movieDB = mongoClient.GetDatabase("sample_mflix");
5 var movieCollection = movieDB.GetCollection<Movie>("movies");
6 List<Movie> movieDocuments;
7
8 Console.WriteLine("Fetching documents from MongoDB...");
9
10 movieDocuments = movieCollection.Find(m => true).Limit(limitSize).ToList();
11
12 movieDocuments.ForEach(movie =>
13 {
14 if (movie.Plot == null)
15 {
16 movie.Plot = "UNKNOWN";
17 }
18 });
19
20 foreach (var movie in movieDocuments)
21 {
22 try
23 {
24 await memory.SaveReferenceAsync(
25 collection: CollectionName,
26 description: movie.Plot,
27 text: movie.Plot,
28 externalId: movie.Title,
29 externalSourceName: "Sample_Mflix_Movies",
30 additionalMetadata: movie.Year.ToString());
31 }
32 catch (Exception ex)
33 {
34 Console.WriteLine(ex.Message);
35
36 }
37 }
38 }
Vamos dar uma olhada no que está acontecendo:
  • Usamos o driver C# do MongoDB, que está disponível para nós no connector, para criar um novo cliente e apontá-lo para nosso banco de dados e coleção existentes.
  • Em seguida, criamos uma nova lista de filmes, obtendo o número solicitado de documentos e adicionando-os à lista.
  • Para cada filme, fazemos alguma higiene de dados para quaisquer gráficos nulos, pois isso pode causar erros mais tarde, e simplesmente marcá-lo como anulável não funcionará, infelizmente.
  • Depois de termos uma lista limpa de filmes, iteramos cada um deles e o salvamos em nossa nova coleção por meio do armazenamento de memória.
    • O documento que o Semantic Kernel cria com o plug-in tem alguns campos que queremos preencher, então atribuímos a esses os valores mais sensatos dos campos disponíveis em nosso documento de filme.
Agora, precisamos realmente chamar esse método. Podemos fazer isso simplesmente chamando await FetchAndSaveMovieDocuments(memory, 1500); de nosso métodoMain, após o código existente. Isso preencherá nossa collection vinculada ao armazenamento de memória com documentos 1500 . Você pode escolher um número diferente, se desejar.
Execute o aplicativo para preencher nosso novo banco de dados e coleção com dados usando o Kernel Semântico. Depois de exibir "Fetching documents from MongoDB…", aguarde alguns minutos para que ele seja preenchido em segundo plano e feche o aplicativo. Gerar as incorporações de texto em um número tão grande de documentos usando o Kernel Semântico pode demorar um pouco. Este não é um gargalo devido ao soberbo driver C# do MongoDB.
dotnet run
Isso só precisa ser executado uma vez para que tenhamos alguns dados disponíveis. Portanto, se você quiser executar esse aplicativo novamente no futuro, não há problema em comentar a chamada para o método FetchAndSaveMovieDocuments ou removê-lo completamente.
Isso criará um novo banco de dados em seu cluster chamado semantic-kernel com uma coleção chamada embedded_movies, contendo os dados conforme preenchidos usando o Semantic Kernel.
Documento de exemplo mostrando o objeto de metadados e o campo de incorporação gerado pelo Kernel Semantic

Criando o índice de pesquisa vetorial

Você deve ter notado anteriormente que, quando adicionamos nosso armazenamento de memória MongoDB, passamos o nome do índice de pesquisa. Esse índice de pesquisa é usado para identificar quais campos queremos usar em nossa pesquisa. Mas isso ainda não existe em nosso MongoDB database.
Agora que você executou o aplicativo uma vez, os dados estarão disponíveis na coleção para uso no índice de pesquisa.
Já temos uma ótima documentação sobre como criar um índice de pesquisa vetorial para que você possa consultá-la sobre como acessar o assistente na interface do usuário do Atlas para criar o novo índice.
O seguinte JSON pode ser utilizado para definir o índice:
1{
2 "fields": [
3 {
4 "numDimensions": 1536,
5 "path": "embedding",
6 "similarity": "dotProduct",
7 "type": "vector"
8 }
9 ]
10}
Isso usa o campo de incorporação que foi gerado pelo Semantic Kernel. O modelo "text-embedding-ada-002" da OpenAI que estamos usando para a incorporação de texto gera 1536 dimensões. Você verá isso nos documentos gerados, pois a matriz de incorporação contém 1536 elementos.
Você precisará usar o nome do índice "default" para corresponder à variável codificada em seu código. Se você nomear o índice de pesquisa outra coisa, certifique-se de atualizar a variável.

Fazendo perguntas sobre nossos dados

Agora que temos os dados disponíveis e o índice de pesquisa criado, é hora de adicionar a capacidade de realmente fazer perguntas sobre nossos dados.
Cole o código a seguir em seu métodoMain, após o código existente:
1Console.WriteLine("Welcome to the Movie Recommendation System!");
2Console.WriteLine("Type 'x' and press Enter to exit.");
3Console.WriteLine("============================================");
4Console.WriteLine();
5
6while(true)
7{
8 Console.WriteLine("Tell me what sort of film you want to watch..");
9 Console.WriteLine();
10
11 Console.Write("> ");
12
13 var userInput = Console.ReadLine();
14
15 if(userInput.ToLower() == "x")
16 {
17 Console.WriteLine("Exiting application..");
18 break;
19 }
20
21 Console.WriteLine();
22
23 var memories = memory.SearchAsync(CollectionName, userInput, limit: 3, minRelevanceScore: 0.6);
24
25 Console.WriteLine(String.Format("{0,-20} {1,-50} {2,-10} {3,-15}", "Title", "Plot", "Year", "Relevance (0 - 1)"));
26 Console.WriteLine(new String('-', 95)); // Adjust the length based on your column widths
27
28 await foreach (var mem in memories)
29 {
30 Console.WriteLine(String.Format("{0,-20} {1,-50} {2,-10} {3,-15}",
31 mem.Metadata.Id,
32 mem.Metadata.Description.Length > 47 ? mem.Metadata.Description.Substring(0, 47) + "..." : mem.Metadata.Description, // Truncate long descriptions
33 mem.Metadata.AdditionalMetadata,
34 mem.Relevance.ToString("0.00"))); // Format relevance score to two decimal places
35 }
36}
Muito desse código é sobre a entrada do usuário e a formatação da saída. Mas vamos dar uma olhada nas linhas de código que importam:
memory.SearchAsync é como realizamos a pesquisa. Passamos a ele o nome de onde queremos pesquisar, também conhecido como collection, o que queremos pesquisar, quantos resultados receber e qual pontuação de 0 a 1 consideramos um limite para "relevant enough. " await foreach (var mem in memories) é ligeiramente diferente do forreach que você pode estar usando. A variável de memória que recebeu o resultado da pesquisa é do tipo `''IAsyncEnumerable
então temos que realizar um await forreach para iterar por ele.

Experimentando

Agora temos tudo pronto para executar o aplicativo e realmente fazer uma pergunta. Por que não tentar pedir um filme sobre tubarões ou outro tema que você adora?
O bot de busca de filmes em ação

Resumo

Simples assim, você criou um bot simples de recomendações de chat de filme usando o Microsoft, o MongoDB Atlas e o connector para MongoDB no Microsoft.
Se você quiser saber mais, Escrevi um tutorial sobre como usar o Atlas Vector Search nativamente em um aplicativo .NET!
Você pode ver o código completo acessando o repositório no GitHub.
Há também uma ramificação principal desse repositório que usa o AzureOpenAI para aqueles que têm acesso.
Por que não experimentar hoje e ver qual filme você pode querer assistir esta noite?
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.
Iniciar a conversa

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Usando o LINQ para consultar o MongoDB em um aplicativo .NET Core


Jun 10, 2024 | 6 min read
Tutorial

Introdução ao MongoDB Atlas e ao Azure Functions usando .NET e C#


Apr 02, 2024 | 8 min read
Tutorial

Salvando dados no Unity3D usando o PlayPrefs


Sep 09, 2024 | 11 min read
Tutorial

Trabalhando com transações MongoDB com C# e .NET Framework


Sep 11, 2024 | 3 min read
Sumário