Skip to content

Instantly share code, notes, and snippets.

@LuceCarter
Created January 23, 2025 17:26
Show Gist options
  • Save LuceCarter/2efd3ae606da16aed1916ace5ef88595 to your computer and use it in GitHub Desktop.
Save LuceCarter/2efd3ae606da16aed1916ace5ef88595 to your computer and use it in GitHub Desktop.
ai_agent_with_semantic_kernel_mongodb
OpenAIPromptExecutionSettings settings = new()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
Console.WriteLine("What would you like to make for dinner?");
var input = Console.ReadLine();
string ingredientsPrompt = @"This is a list of ingredients available to the user:
{{IngredientsPlugin.GetIngredientsFromCupboard}}
Based on their requested dish " + input + ", list what ingredients they are missing from their cupboard to make that meal and return just the list of missing ingredients. If they have similar items such as pasta instead of a specific type of pasta, don't consider it missing";
var ingredientsResult = await kernel.InvokePromptAsync(ingredientsPrompt, new(settings));
var missing = ingredientsResult.ToString().ToLower()
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Where(line => line.StartsWith("- "))
.ToList();
var cuisineResult = await kernel.InvokeAsync(
plugins["GetCuisine"],
new() { { "cuisine", input } }
);
if (missing.Count >= 5)
{
string restaurantPrompt = @"This is the cuisine that the user requested: " + cuisineResult + @". Based on this cuisine, recommend a restaurant for the user to eat at. Include the name and address
{{RestaurantsPlugin.GetRecommendedRestaurant}}";
var kernelArguments = new KernelArguments(settings)
{
{ "cuisine", cuisineResult }
};
var restaurantResult = await kernel.InvokePromptAsync(restaurantPrompt, kernelArguments);
Console.WriteLine($"You have so many missing ingredients ({missing.Count}!), why bother? {restaurantResult}");
}
else if(missing.Count < 5 && missing.Count > 0)
{
Console.WriteLine($"You have most of the ingredients to make {input}. You are missing: ");
foreach (var ingredient in missing)
{
Console.WriteLine(ingredient);
}
string similarPrompt = @"The user requested to make " + input + @" but is missing some ingredients. Based on what they want to eat, suggest another meal that is similar from the " + cuisineResult + " cuisine they can make and tell them the name of it but do not return a full recipe";
var similarResult = await kernel.InvokePromptAsync(similarPrompt, new(settings));
Console.WriteLine(similarResult);
}
else {
Console.WriteLine("You have all the ingredients to make " + input + "!");
string recipePrompt = @"Find a recipe for making " + input;
var recipeResult = await kernel.InvokePromptAsync(recipePrompt, new(settings));
Console.WriteLine(recipeResult);
}
{
"schema": 1,
"type": "completion",
"description": "Identify the cuisine of the user's requested meal",
"execution_settings": {
"default": {
"max_tokens": 800,
"temperature": 0
}
},
"input_variables": [
{
"name": "cuisine",
"description": "Text from the user that contains their requested meal",
"required": true
}
]
}
kernel.ImportPluginFromType<RestaurantsPlugin>();
string apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new ArgumentNullException("Environment.GetEnvironmentVariable(\"OPENAI_API_KEY\")");
string modelName = Environment.GetEnvironmentVariable("OPENAI_MODEL_NAME") ?? "gpt-4o-mini";
memoryBuilder.WithOpenAITextEmbeddingGeneration(
"text-embedding-3-small",
"<YOUR OPENAI APIKEY>"
);
await GenerateEmbeddingsForCuisine();
dotnet run
string baseDir = AppContext.BaseDirectory;
string projectRoot = Path.Combine(baseDir, "..", "..", "..");
var plugins = kernel.CreatePluginFromPromptDirectory(projectRoot + "/Prompts");
using System.ComponentModel;
using Microsoft.SemanticKernel;
[KernelFunction, Description("Get a list of available ingredients")]
public static string GetIngredientsFromCupboard()
{
// Ensures that the file path functions across all operating systems.
string baseDir = AppContext.BaseDirectory;
string projectRoot = Path.Combine(baseDir, "..", "..", "..");
string filePath = Path.Combine(projectRoot, "Data", "cupboardinventory.txt");
return File.ReadAllText(filePath).ToLower();
}
kernel.ImportPluginFromType<IngredientsPlugin>();
using FoodAgentDotNet.Models;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.MongoDB;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Memory;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FoodAgentDotNet.Plugins;
#pragma warning disable
public class RestaurantsPlugin
{
static readonly string mongoDBConnectionString = Environment.GetEnvironmentVariable("MONGODB_ATLAS_CONNECTION_STRING");
static readonly string openAIApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
[KernelFunction, Description("Find a restaurant to eat at")]
public static async Task<List<Restaurant>> GetRecommendedRestaurant(
[Description("The cuisine to find a restaurant for")] string cuisine)
{
var mongoDBMemoryStore = new MongoDBMemoryStore(mongoDBConnectionString, "sample_restaurants", "restaurants_index");
var memoryBuilder = new MemoryBuilder();
memoryBuilder.WithOpenAITextEmbeddingGeneration(
"text-embedding-3-small",
openAIApiKey );
memoryBuilder.WithMemoryStore(mongoDBMemoryStore);
var memory = memoryBuilder.Build();
var restaurants = memory.SearchAsync(
"embedded_cuisines",
cuisine,
limit: 5,
minRelevanceScore: 0.5
);
List<Restaurant> recommendedRestaurants = new();
await foreach(var restaurant in restaurants)
{
recommendedRestaurants.Add(new Restaurant
{
Name = restaurant.Metadata.Description,
// We include the cuisine so that the AI has this information available to it
Cuisine = restaurant.Metadata.AdditionalMetadata,
});
}
return recommendedRestaurants;
}
}
var builder = Kernel.CreateBuilder();
builder.Services.AddOpenAIChatCompletion(
modelName,
apiKey);
var kernel = builder.Build();
Return a single word that represents the cuisine of the requested meal that is sent: {{$cuisine}}.
For example, if the meal is mac and cheese, return American. Or for pizza it would be Italian.
Do not return any extra words, just return the single name of the cuisine.
export OPENAI_API_KEY=”<REPLACE WITH YOUR OPEN AI API KEY>” # MacOS/Linux
set OPENAI_API_KEY=”<REPLACE WITH YOUR OPEN AI API KEY>” # Windows”
export OPENAI_MODEL_NAME=”<REPLACE WITH YOUR MODEL OF CHOICE>”
set OPENAI_MODEL_NAME_”<REPLACE WITH YOUR MODEL OF CHOICE>”
export MONGODB_ATLAS_CONNECTION_STRING=”<YOUR MONGODB ATLAS CONNECTION STRING>”
set MONGODB_ATLAS_CONNECTION_STRING=”<YOUR MONGODB ATLAS CONNECTION STRING>”
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment