This article is a guide to developing your first semantic kernel app using dotnet and C#, enabling you to add dynamic features to your AI solution.

Banner

Challenge and Problem Statement

A common limitation of AI models is their static nature. For instance, when asked “Is the queen still alive?” ChatGPT might respond affirmatively based on outdated information. Such models struggle with dynamically changing information and complex calculations not readily available in public documents.

What Time Is It?

Ever wondered why ChatGPT can’t provide the current date and time? As a text-generating engine, it relies on predictions from existing data. Attempting to ask for the current date, time, or day of the week yields no response.

Below is the initial version of my sample application with no additional plugins.

Sample1

To enhance your AI solution’s intelligence, you can leverage the plugin feature of the open-source Semantic Kernel SDK. This enables you to write your own “features” for a large language model.

Requirements

To create your first semantic kernel plugin, I recommend using the latest version of dotnet and Visual Studio Code.

Additionally, you’ll need to install the Semantic Kernel SDK in your project with: dotnet add package Microsoft.SemanticKernel.

You’ll also need an existing Azure OpenAI Service in your Azure Tenant.

Code

The demo application is a basic console chat application offering only rudimentary mathematical and datetime calculation functions.

Configuration

Create a configuration file named appsetting.json, and include your model’s name, endpoint, and key in the json.

{
  "OpenAIEndpoint": "",
  "OpenAPIKey": "",
  "ModelName": ""
}

Plugin Code

To write a plugin it is only required to add attributes to methods and parameters. Those attributes indicate the methods with intentions to return data.

Create a new file with the name DateTimePlugin.cs.

using Microsoft.SemanticKernel;
using System.ComponentModel;

namespace Oliver.AI.Samples.ChatGPTPlugin.Plugins
{
    public sealed class DateTimePlugin
    {
        [KernelFunction, Description("What date is today?")]
        public static DateTime GetDate()
        {
            return DateTime.Today;
        }

        [KernelFunction, Description("What day of week is today?")]
        public static DayOfWeek GetDay()
        {
            return DateTime.Today.DayOfWeek;
        }

        [KernelFunction, Description("What time is it?")]
        public static DateTime GetTime()
        {
            return DateTime.Now;
        }
    }
}

The Console Application Code

The magic to add the plugin to the existing ChatCompletionService is just s single line of code:

builder.Plugins.AddFromType<DateTimePlugin>();

The complete code with the file name Program.cs.

using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Oliver.AI.Samples.ChatGPTPlugin.Plugins;

#region Configuration

// Read the condiguration from an appsettings.json file
// to avoid exploiting the API key and endpoint in a demo

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", true)
    .AddJsonFile("appsettings.Development.json", true)
    .Build();

string endpoint = configuration["OpenAIEndpoint"] ?? "";
string modelName = configuration["ModelName"] ?? "";
string apiKey = configuration["OpenAPIKey"] ?? "";

#endregion 

// Create kernel
IKernelBuilder builder = Kernel.CreateBuilder();

// Add a text or chat completion service using either:
builder.Services.AddAzureOpenAIChatCompletion(modelName, endpoint, apiKey);
builder.Plugins.AddFromType<MathPlugin>();
builder.Plugins.AddFromType<DateTimePlugin>();

Kernel kernel = builder.Build();

// Create chat history
ChatHistory history = [];

// Get chat completion service
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

Console.WriteLine("Olivers ChatGPT Plugins");
Console.WriteLine("-----------------------");
Console.WriteLine("Type 'exit' to quit the conversation");
Console.WriteLine();

// Start the conversation
while (true)
{
    // Get user input
    Console.Write("User > ");
    string userInput = Console.ReadLine()!;
    if (userInput.ToLower() == "exit")
    {
        break;
    }
    history.AddUserMessage(userInput);

    // Enable auto function calling
    OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
    {
        ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
    };

    // Get the response from the AI
    var result = chatCompletionService.GetStreamingChatMessageContentsAsync(
        history,
        executionSettings: openAIPromptExecutionSettings,
        kernel: kernel);

    // Stream the results
    string fullMessage = "";
    var first = true;
    await foreach (var content in result.ConfigureAwait(false))
    {
        if (content.Role.HasValue && first)
        {
            Console.Write("Assistant > ");
            first = false;
        }
        Console.Write(content.Content);
        fullMessage += content.Content;
    }
    Console.WriteLine();
    Console.WriteLine();

    // Add the message from the agent to the chat history
    history.AddAssistantMessage(fullMessage);
}

Console.WriteLine("Goodbye!");

Running the Application

Run the application and ask some of the following questions:

  • Which day is today?
  • What time is it?
  • Which day of the week is today?
  • Welcher Wochentag ist heute?

Iimage2

Video

I’ve recorded a short video demonstrating this process, which I’ve posted on YouTube.

English Version | German Version

Conclusion

With the Semantic Kernel, you can create scenarios beyond simple questions. You can retrieve data from internal sources, engage in more intensive dialogs, and much more. Stay tuned for further developments.

You can find more information here.