Skip to main content

Command Palette

Search for a command to run...

Integrating C# Native Functions with Semantic Kernel

Published
5 min read
Integrating C# Native Functions with Semantic Kernel

In this blog post, we will explore two interesting approaches for integrating C# native functions with Semantic Kernel.

Let’s assume you have a C# function called HelloUserand this function takes the user’s name as an argument and returns “Hello {user}”based on the value passed to the function.

public static string HelloUser(string user)
{
    return $"Hello from : {user}";
}

To register this function as a Semantic Kernel function with the option to pass argument/s the following approaches can be utilised.

  • Kernel.CreateFunctionFromMethod

  • KernelFunctionFactory.CreateFromMethod

Kernel.CreateFunctionFromMethod

Lets take the example of the HelloUser function that greets the user based on the argument passed to it.

 public static string HelloUser(string user)
 {
     return $"Hello from : {user}";
 }

What we want is to execute the above function as a Kernel function and pass the arguments to it as Kernel arguments.

At first, we create a kernel object

  var builder = Kernel.CreateBuilder();
  var kernel = builder.Build(); 

Next, declare a KernelFunction named HelloUser_ through the native C# method using kernel.CreateFunctionFromMethod

KernelFunction HelloUser_ = kernel.CreateFunctionFromMethod(HelloUser, functionName: "HelloUser_", description: "Greets the user");

The arguments to the kernel.CreateFunctionFromMethod method are :

  • C# function name

  • Kernel function name

  • Description

We should register this function to the kernel plugin. We can do this by using the kernel.CreatePluginFromFunctions method

KernelPlugin UserGreetingsPlugin = kernel.CreatePluginFromFunctions("UserGreetingsPlugin", IEnumerateGreetings);

the arguments to kernel.CreateFunctionFromMethod are

  • PluginName

  • IEnumerable

We already have created a Kernel function HelloUser_ but the above method expects an IEnumerable of KernelFunctions.

This is because it provides the flexibility to register multiple Kernel functions within a single plugin. We will look at that example later in the article.

Next, we create an IEnumerable of KernelFunctions to add our KernelFunction HelloUser_to it

IEnumerable<KernelFunction> IEnumerateGreetings = new List<KernelFunction> { HelloUser_ };

Create a plugin called UserGreetingsPlugin

KernelPlugin UserGreetingsPlugin = kernel.CreatePluginFromFunctions("UserGreetingsPlugin", IEnumerateGreetings);

and add the kernel function HelloUser_ to it.

 kernel.Plugins.Add(UserGreetingsPlugin);

At this stage if you are confused of the steps performed till now , let me briefly list them

  • We created a C# function called HelloUser with user's name as its argument.

  • We then created a Kernel function called HelloUser_and registered it with plugin named UserGreetingsPlugin

  • To register the kernel function we used kernel.CreatePluginFromFunctionsmethod and this method expects a type IEnumeration<KernelFunction> in the argument.

  • We created an Enumerator called IEnumerateGreetings of type KernelFunction and added the kernelfunction HelloUser_ to the Enumerator.

  • And finally we registered the UserGreetingsPluginto the kernel's Plugin collection.

Next, to pass argument value to the C# function HelloUser , we pass the arguments to it through the Semantic Kernel function HelloUser_.

To do that we have to invoke the kernel function through kernel.InvokeSync. It expects function name and argument values.

var response = await kernel.InvokeAsync(HelloUser_, new KernelArguments()
  {
      ["user"] = "Sachin"
  });

 Console.WriteLine(response);

The output of the invoking the function returns the following output.

To send multiple arguments to the C# function through the Kernel function , we can pass them through KernelArguments.

Consider the following C# function that expects multiple arguments.

public static string HelloUsers(string user1, string user2)
{
    return $"Hello from : {user1} and {user2}";
}

we set multiple arguments for KernelArguments

KernelFunction HelloUsers_ = kernel.CreateFunctionFromMethod(HelloUsers, functionName: "HelloUsers_", description: "Greets the users");

IEnumerable<KernelFunction> IEnumerateGreetings = new List<KernelFunction> { HelloUsers_ };

 KernelPlugin UserGreetingsPlugin = kernel.CreatePluginFromFunctions("UserGreetingsPlugin", IEnumerateGreetings);

 kernel.Plugins.Add(UserGreetingsPlugin);

 var response = await kernel.InvokeAsync(HelloUsers_, new KernelArguments()
   {
       ["user1"] = "Sachin1",
       ["user2"] = "Sachin2"

   });

   Console.WriteLine(response.ToString());

KernelFunctionFactory.CreateFromMethod

Most of the steps are similar to the Kernel.CreateFunctionFromMethod approach, with the added advantage that there is no need to add the kernel function to the kernel’s plugin collection.

Below is the code that illustrates this.

KernelFunction HelloUsers_ = KernelFunctionFactory.CreateFromMethod(HelloUsers, functionName: "HelloUsers_", description: "Greets the users");

IEnumerable<KernelFunction> IEnumerateGreetings = new List<KernelFunction> { HelloUsers_ };

kernel.Plugins.AddFromFunctions("UserGreetingsPlugin", IEnumerateGreetings);

 var response_= await kernel.InvokeAsync(HelloUsers_, new KernelArguments()
  {
      ["User1"] = "Sachin1",
      ["User2"] = "Sachin2"
  });

  Console.WriteLine(response_.ToString());

As we see above, there is no need to manually add the function to the plugin the way we did with the kernel.CreateFunctionFromMethod approach through kernel.Plugins.Add

Apart from the above, there really isn't any advantages/disadvantages of using either of the approaches.

Register multiple kernel functions within a single Plugin

Earlier in the article, I mentioned that we would see how to register multiple functions within a single plugin.

Assume there are two functions

public static string HelloUser1(string user1)
{
    return $"Hello from : {user1}";
}
 public static string HelloUser2(string user2)
 {
     return $"Hello from : {user2}";
 }

The ask is to register the above functions under a single plugin.

Using the kernel.CreateFunctionFromMethod,we create two kernel functions HelloUser1_ and HelloUser2_ and add these functions to the KernelFunctionIEnumerator IEnumerateGreetings

KernelFunction HelloUser1_ = kernel.CreateFunctionFromMethod(HelloUser1, functionName: "HelloUser1", description: "Greets user1");

KernelFunction HelloUser2_ = kernel.CreateFunctionFromMethod(HelloUser2, functionName: "HelloUser2", description: "Greets user2");

IEnumerable<KernelFunction> IEnumerateGreetings = new List<KernelFunction> { HelloUser1_, HelloUser2_ };

KernelPlugin UserGreetingsPlugin = kernel.CreatePluginFromFunctions("UserGreetingsPlugin", IEnumerateGreetings);

kernel.Plugins.Add(UserGreetingsPlugin);

var user1response = await kernel.InvokeAsync(HelloUser1_, new KernelArguments()
{
    ["user1"] = "Sachin1"

});
var user2response = await kernel.InvokeAsync(HelloUser2_, new KernelArguments()
{
    ["user2"] = "Sachin2"

});

  Console.WriteLine(user1response.ToString());
  Console.WriteLine(user2response.ToString());

Invoking both the kernel functions we get the expected output

Conclusion

In this article we explored two approaches to creating Semantic Kernel functions from C# native methods. The first approach uses KernelFunctionFactory.CreateFromMethod, which directly registers the function with the kernel. The second approach uses kernel.CreateFunctionFromMethod which offers greater flexibility by allowing functions to be created independently and later associated with plugins.

We also saw how multiple functions can be grouped under a single plugin, making it easier to organize and manage functionality within Semantic Kernel applications.

Thanks for reading !!!

More from this blog

My Ramblings On Microsoft Data Stack

87 posts

Unlike many out there I am an Expert in NOTHING !!!

From Synapse Analytics, Power BI, Spark, Microsoft Fabric,ASP.NET Core and recently Agentic AI on .NET I try to explore, learn and share all aspects of Microsoft Data Stack in this blog.