DEV Community

Rocky LIU Yan
Rocky LIU Yan

Posted on • Edited on

Building a Semantic Kernel with F# for Enhanced AI Interaction

This blog base from https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/GettingStarted/Step2_Add_Plugins.cs

F# code is here https://github.com/rocklau/fsharpPlayground

In the age of artificial intelligence, leveraging powerful tools to interact seamlessly with users is crucial. Semantic Kernels serve as versatile frameworks that enable AI models to comprehend and respond to queries intelligently. In this blog post, we’ll explore how to create a Semantic Kernel using F#, integrating plugins to enhance functionality and improve user interaction.

Setting Up the Semantic Kernel

The foundation of our Semantic Kernel is built on several key components:

  1. Time Information Plugin: This plugin retrieves the current time in UTC.
  2. Widget Factory Plugin: This plugin allows users to create widgets with specified types and colors.

Let's take a look at the code implementation for these plugins.

Time Information Plugin

This simple plugin is designed to provide the current UTC time, making it accessible for any application requiring time-related information.

type TimeInformationPlugin() =
    [<KernelFunction>]
    [<Description("Retrieves the current time in UTC.")>]
    member this.GetCurrentUtcTime() = DateTime.UtcNow.ToString("R")
Enter fullscreen mode Exit fullscreen mode

Widget Factory Plugin

The widget factory plugin is more complex, allowing users to generate custom widgets based on their preferences. The plugin utilizes enumerated types to specify widget characteristics.

type WidgetType =
    | [<Description("A widget that is useful.")>] Useful = 0 
    | [<Description("A widget that is decorative.")>] Decorative = 1 

type WidgetColor =
    | [<Description("Use when creating a red item.")>] Red = 0 
    | [<Description("Use when creating a green item.")>] Green = 1
    | [<Description("Use when creating a blue item.")>] Blue = 2

type WidgetDetails =
    {
        SerialNumber: string
        Type: WidgetType
        Colors: WidgetColor[]
    }

type WidgetFactoryPlugin() =
    [<KernelFunction>]
    [<Description("Creates a new widget of the specified type and colors")>]    
    member this.CreateWidget(widgetType: WidgetType, widgetColors: WidgetColor[]) = 
        let number = $"{widgetType}-{String.Join('-',widgetColors)}-{Guid.NewGuid()}"
        Console.WriteLine $"Call a widget {number}"
        {
            SerialNumber = number
            Type = widgetType
            Colors = widgetColors
        }
Enter fullscreen mode Exit fullscreen mode

Configuring the Kernel

After implementing the plugins, we construct the kernel and register our plugins. This is achieved by configuring the OpenAI API for chat functionalities.

let builder = Kernel.CreateBuilder()
                .AddOpenAIChatCompletion(modelId = "gpt-4o-mini", endpoint = Uri("https://api.chatgpt.com/v1/chat/completions"), apiKey = "sk-")
                .Plugins.AddFromType<TimeInformationPlugin>()
                .AddFromType<WidgetFactoryPlugin>()

let kernel = builder.Build()
Enter fullscreen mode Exit fullscreen mode

Example Use Cases

Once the kernel and plugins are set up, we can create various examples to demonstrate their capabilities. Below are a few examples.

Example 1: Basic Interaction

In this example, we query the kernel about the color of the sky.

let example1 =
    fun () ->
        task {
            printfn "example1"
            let! response = kernel.InvokePromptAsync("What color is the sky?")
            Console.WriteLine response
        }
Enter fullscreen mode Exit fullscreen mode

Example 2: Streaming Responses

We can also create streaming interactions, which allow us to get real-time responses from the AI.

let example2 =
    fun () ->
        asyncEx {
            printfn "example2"
            let arguments = new KernelArguments()
            arguments.Add("topic", "forest")
            let stream = kernel.InvokePromptStreamingAsync("What color is {{$topic}}?", arguments)

            for item in stream do
                Console.Write item
        }
Enter fullscreen mode Exit fullscreen mode

Example 3: Using Plugins

We can directly utilize our plugins within prompts. For instance, we can retrieve the current UTC time and ask how many days remain until Christmas.

let example4 = fun() ->
    asyncEx {
        let! response = kernel.InvokePromptAsync("The current time is {{TimeInformationPlugin.GetCurrentUtcTime}}. How many days until Christmas?")
        Console.WriteLine response
    }
Enter fullscreen mode Exit fullscreen mode

Example 5: Creating Widgets

Finally, we can automatically invoke functions to create customizable widgets.

let example5 = fun() ->
    asyncEx {
        let settings = OpenAIPromptExecutionSettings()
        settings.ToolCallBehavior <- ToolCallBehavior.AutoInvokeKernelFunctions
        let arguments = new KernelArguments(settings)

        let! response2 = kernel.InvokePromptAsync("Create a beautiful scarlet colored widget for me.", arguments) 
        Console.WriteLine(response2)
    }
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this blog, we've explored how to build a Semantic Kernel using F#. By combining plugins with real-time AI interaction, we can create dynamic applications that respond intuitively to user queries. This framework not only enhances user experiences but also opens doors to countless possibilities for future developments in AI interactions.

Feel free to expand upon this framework, experiment with additional plugins, and integrate it into your own applications to fully realize the capabilities of semantic technology and AI!

Top comments (3)

Collapse
 
jkone27 profile image
jkone27

could be interesting to implement agents with MailboxProcessor

devblogs.microsoft.com/semantic-ke...

Collapse
 
rockfire profile image
Rocky LIU Yan

Yeah, light and fast

Collapse
 
bogomil profile image
Bogomil Shopov - Бого

Great article. I little bit more explanation about the Semantic Kernel would be nice!