Nota
L'accés a aquesta pàgina requereix autorització. Pots provar d'iniciar sessió o canviar de directori.
L'accés a aquesta pàgina requereix autorització. Pots provar de canviar directoris.
En este tutorial se explora la integración del patrón RAG mediante modelos de Open AI y funcionalidades de búsqueda vectorial en una aplicación .NET. La aplicación de ejemplo realiza búsquedas vectoriales en datos personalizados almacenados en Azure Cosmos DB para MongoDB y refina aún más las respuestas mediante modelos de IA generativas, como GPT-35 y GPT-4. En las secciones siguientes, configurará una aplicación de ejemplo y explorará ejemplos de código clave que muestran estos conceptos.
Prerrequisitos
- .NET 8.0
- Una cuenta de Azure
- Un servicio de Azure Cosmos DB con núcleo virtual para MongoDB
- Un servicio Azure Open AI
- Implementación del
text-embedding-ada-002modelo para incrustaciones - Implementación del
gpt-35-turbomodelo para finalizaciones de chat
- Implementación del
Información general de la aplicación
La aplicación Guía de recetas de Cosmos permite realizar búsquedas controladas por vectores e inteligencia artificial en un conjunto de datos de recetas. Puedes buscar directamente recetas disponibles o pedir a la aplicación nombres de ingredientes para encontrar recetas relacionadas. La aplicación y las secciones siguientes le guían a través del siguiente flujo de trabajo para demostrar este tipo de funcionalidad:
Cargue datos de ejemplo en una base de datos de Azure Cosmos DB para MongoDB.
Cree incrustaciones y un índice de vectores para los datos de ejemplo cargados mediante el modelo de Azure OpenAI
text-embedding-ada-002.Realice la búsqueda de similitud vectorial en función de las indicaciones del usuario.
Use el modelo de finalizaciones de Azure OpenAI
gpt-35-turbopara crear respuestas más significativas en función de los datos de los resultados de búsqueda.
Comienza
Clone el siguiente repositorio de GitHub:
git clone https://github.com/microsoft/AzureDataRetrievalAugmentedGenerationSamples.gitEn la carpeta C#/CosmosDB-MongoDBvCore , abra el archivo CosmosRecipeGuide.sln .
En el archivo appsettings.json , reemplace los siguientes valores de configuración por los valores de Azure OpenAI y Azure CosmosDB para MongoDb:
"OpenAIEndpoint": "https://<your-service-name>.openai.azure.com/", "OpenAIKey": "<your-API-key>", "OpenAIEmbeddingDeployment": "<your-ADA-deployment-name>", "OpenAIcompletionsDeployment": "<your-GPT-deployment-name>", "MongoVcoreConnection": "<your-Mongo-connection-string>"Inicie la aplicación presionando el botón Iniciar en la parte superior de Visual Studio.
Exploración de la aplicación
Al ejecutar la aplicación por primera vez, se conecta a Azure Cosmos DB e informa de que aún no hay recetas disponibles. Siga los pasos que muestra la aplicación para comenzar el flujo de trabajo principal.
Seleccione Cargar recetas en Cosmos DB y presione Entrar. Este comando lee archivos JSON de ejemplo del proyecto local y los carga en la cuenta de Cosmos DB.
El código de la clase Utility.cs analiza los archivos JSON locales.
public static List<Recipe> ParseDocuments(string Folderpath) { List<Recipe> recipes = new List<Recipe>(); Directory.GetFiles(Folderpath) .ToList() .ForEach(f => { var jsonString= System.IO.File.ReadAllText(f); Recipe recipe = JsonConvert.DeserializeObject<Recipe>(jsonString); recipe.id = recipe.name.ToLower().Replace(" ", ""); recipes.Add(recipe); } ); return recipes; }El
UpsertVectorAsyncmétodo del archivo VCoreMongoService.cs carga los documentos en Azure Cosmos DB para MongoDB.public async Task UpsertVectorAsync(Recipe recipe) { BsonDocument document = recipe.ToBsonDocument(); if (!document.Contains("_id")) { Console.WriteLine("UpsertVectorAsync: Document does not contain _id."); throw new ArgumentException("UpsertVectorAsync: Document does not contain _id."); } string? _idValue = document["_id"].ToString(); try { var filter = Builders<BsonDocument>.Filter.Eq("_id", _idValue); var options = new ReplaceOptions { IsUpsert = true }; await _recipeCollection.ReplaceOneAsync(filter, document, options); } catch (Exception ex) { Console.WriteLine($"Exception: UpsertVectorAsync(): {ex.Message}"); throw; } }Seleccione Vectorizar las recetas y almacenarlas en Cosmos DB.
Los elementos JSON cargados en Cosmos DB no contienen incrustaciones y, por lo tanto, no están optimizados para RAG a través de la búsqueda vectorial. Una inserción es una representación numérica densa de información del significado semántico de un fragmento de texto. Las búsquedas vectoriales pueden buscar elementos con incrustaciones contextualmente similares.
El
GetEmbeddingsAsyncmétodo del archivo OpenAIService.cs crea una inserción para cada elemento de la base de datos.public async Task<float[]?> GetEmbeddingsAsync(dynamic data) { try { EmbeddingsOptions options = new EmbeddingsOptions(data) { Input = data }; var response = await _openAIClient.GetEmbeddingsAsync(openAIEmbeddingDeployment, options); Embeddings embeddings = response.Value; float[] embedding = embeddings.Data[0].Embedding.ToArray(); return embedding; } catch (Exception ex) { Console.WriteLine($"GetEmbeddingsAsync Exception: {ex.Message}"); return null; } }En
CreateVectorIndexIfNotExistsel archivo VCoreMongoService.cs crea un índice vectorial, lo que le permite realizar búsquedas de similitud vectorial.public void CreateVectorIndexIfNotExists(string vectorIndexName) { try { //Find if vector index exists in vectors collection using (IAsyncCursor<BsonDocument> indexCursor = _recipeCollection.Indexes.List()) { bool vectorIndexExists = indexCursor.ToList().Any(x => x["name"] == vectorIndexName); if (!vectorIndexExists) { BsonDocumentCommand<BsonDocument> command = new BsonDocumentCommand<BsonDocument>( BsonDocument.Parse(@" { createIndexes: 'Recipe', indexes: [{ name: 'vectorSearchIndex', key: { embedding: 'cosmosSearch' }, cosmosSearchOptions: { kind: 'vector-ivf', numLists: 5, similarity: 'COS', dimensions: 1536 } }] }")); BsonDocument result = _database.RunCommand(command); if (result["ok"] != 1) { Console.WriteLine("CreateIndex failed with response: " + result.ToJson()); } } } } catch (MongoException ex) { Console.WriteLine("MongoDbService InitializeVectorIndex: " + ex.Message); throw; } }Seleccione la opción Preguntar al Asistente para IA (busque una receta por nombre o descripción o haga una pregunta) en la aplicación para ejecutar una consulta de usuario.
La consulta de usuario se convierte en una inserción mediante el servicio Open AI y el modelo de inserción. A continuación, la inserción se envía a Azure Cosmos DB para MongoDB y se usa para realizar una búsqueda vectorial. El
VectorSearchAsyncmétodo del archivo VCoreMongoService.cs realiza una búsqueda vectorial para buscar vectores que están cerca del vector proporcionado y devuelve una lista de documentos de Azure Cosmos DB para núcleos virtuales de MongoDB.public async Task<List<Recipe>> VectorSearchAsync(float[] queryVector) { List<string> retDocs = new List<string>(); string resultDocuments = string.Empty; try { //Search Azure Cosmos DB for MongoDB vCore collection for similar embeddings //Project the fields that are needed BsonDocument[] pipeline = new BsonDocument[] { BsonDocument.Parse( @$"{{$search: {{ cosmosSearch: {{ vector: [{string.Join(',', queryVector)}], path: 'embedding', k: {_maxVectorSearchResults}}}, returnStoredSource:true }} }}"), BsonDocument.Parse($"{{$project: {{embedding: 0}}}}"), }; var bsonDocuments = await _recipeCollection .Aggregate<BsonDocument>(pipeline).ToListAsync(); var recipes = bsonDocuments .ToList() .ConvertAll(bsonDocument => BsonSerializer.Deserialize<Recipe>(bsonDocument)); return recipes; } catch (MongoException ex) { Console.WriteLine($"Exception: VectorSearchAsync(): {ex.Message}"); throw; } }El
GetChatCompletionAsyncmétodo genera una respuesta de finalización de chat mejorada en función de la solicitud del usuario y los resultados de búsqueda vectorial relacionados.public async Task<(string response, int promptTokens, int responseTokens)> GetChatCompletionAsync(string userPrompt, string documents) { try { ChatMessage systemMessage = new ChatMessage( ChatRole.System, _systemPromptRecipeAssistant + documents); ChatMessage userMessage = new ChatMessage( ChatRole.User, userPrompt); ChatCompletionsOptions options = new() { Messages = { systemMessage, userMessage }, MaxTokens = openAIMaxTokens, Temperature = 0.5f, //0.3f, NucleusSamplingFactor = 0.95f, FrequencyPenalty = 0, PresencePenalty = 0 }; Azure.Response<ChatCompletions> completionsResponse = await openAIClient.GetChatCompletionsAsync(openAICompletionDeployment, options); ChatCompletions completions = completionsResponse.Value; return ( response: completions.Choices[0].Message.Content, promptTokens: completions.Usage.PromptTokens, responseTokens: completions.Usage.CompletionTokens ); } catch (Exception ex) { string message = $"OpenAIService.GetChatCompletionAsync(): {ex.Message}"; Console.WriteLine(message); throw; } }La aplicación también utiliza la ingeniería de prompts para asegurarse de que respeta los límites del servicio de Open AI y formatea la respuesta para las recetas proporcionadas.
//System prompts to send with user prompts to instruct the model for chat session private readonly string _systemPromptRecipeAssistant = @" You are an intelligent assistant for Contoso Recipes. You are designed to provide helpful answers to user questions about recipes, cooking instructions provided in JSON format below. Instructions: - Only answer questions related to the recipe provided below. - Don't reference any recipe not provided below. - If you're unsure of an answer, say ""I don't know"" and recommend users search themselves. - Your response should be complete. - List the Name of the Recipe at the start of your response followed by step by step cooking instructions. - Assume the user is not an expert in cooking. - Format the content so that it can be printed to the Command Line console. - In case there is more than one recipe you find, let the user pick the most appropriate recipe.";