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.CreateFunctionFromMethodKernelFunctionFactory.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
HelloUserwith user's name as its argument.We then created a Kernel function called
HelloUser_and registered it with plugin namedUserGreetingsPluginTo register the kernel function we used
kernel.CreatePluginFromFunctionsmethod and this method expects a typeIEnumeration<KernelFunction>in the argument.We created an Enumerator called
IEnumerateGreetingsof typeKernelFunctionand added the kernelfunctionHelloUser_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 !!!




