Function calling Azure OpenAI C#
Function calling Azure OpenAI C#

In this article I will show you how to implement function calling in C# language. Function calling is extremely important in building AI applications because it allows your app to become something more than the bot that produces unstructured data. Now you can ask LLM to generate the data that you can process with the code. Let’s do it.

Nuget packages

What Nuget packages do you need?

Azure.AI.OpenAI

How to create a function?

How to configure tools? First you need to create a JSON description for your tool. What do you need to send SMS?

Typically we need 2 properties:

  • phone number of the reepient
  • message to be sent

We need to define their types – here both properties are strings.

We also need to define their description – this value will be used by LLM to actual arguments and inject them in the place of formal parameters. The specific actual arguments values will be deduced from the onversation which is great feature of LLM. Why? Because LLM will understand the prompt like this:

PROMPT: sent SMS "I'd like to order 10 'Clean Code' books" to 666-111-222

using System.Text.Json;
using Azure.AI.Inference;
using OpenAI.Chat;

namespace DarekApp.Services;

public class SmsService
{
    static public ChatTool GetTool()
    {
        ChatTool tool = ChatTool.CreateFunctionTool(
            nameof(SendSms),
            "send SMS",
            BinaryData.FromString(
                @"
            {
              ""type"": ""object"",
              ""properties"": {
                ""message"": {
                  ""type"": ""string"",
                  ""description"": ""text of SMS""
                },
                ""phoneNumber"": {
                  ""type"": ""string"",
                  ""description"": ""phone number of recepient""
                }
              },
              ""required"": [""message"", ""phoneNumber""]
            }
        ")
        );

        return tool;
    }

    public static string SendSms(string message, string phoneNumber)
    {
        return "SMS sent!";
    }
}

How to call the function?

Now, when our function is in place, we need to call it. There is no better tool for C# AI developers than Semantic Kernel. But here we will not use Semantic Kernel. Instead we’ll use another library from Microsoft that is called Azure.AI.OpenAI. It’s SDK that you can connect to Azure OpenAI deployment. And as a next step you can easily connect to all the tools that you’ve created. (TIP: Tool is a method that can be called by LLM when necessary. Tool is a concept similar to Plugins that are specific to Semanic Kernel, and we’ll be talking about them soon in a different post)



using Azure.AI.OpenAI;
using OpenAI.Chat;
using System.ClientModel;
using System.Text.Json;

namespace DarekApp.Services;


public class ChatServiceFunctionCalling
{
    public async Task<string> GetResponse(List<ChatMessageViewModel> messages)
    {
        AzureOpenAIClient azureClient = new(
            new Uri("https://openai-example.openai.azure.com/"),
            new ApiKeyCredential("API_KEY"));
        ChatClient chatClient = azureClient.GetChatClient("gpt-4o");

        List<ChatMessage> chatMessages = new List<ChatMessage>();

        var systemPrompt = "You are helpdesk assistant, you are polite and helpful. At the beginning of the conversation, you always ask user for their mobile phone.";
        var systemMessage = new SystemChatMessage(systemPrompt);
        chatMessages.Add(systemMessage);

        foreach (var message in messages)
        {
            if (message.Role == "user")
            {
                var userMessage = new UserChatMessage(message.Message);
                chatMessages.Add(userMessage);
            }
            else
            {
                var assistantMessage = new AssistantChatMessage(message.Message);
                chatMessages.Add(assistantMessage);
            }
        }

        var chatMessagesArray = chatMessages.ToArray();

        var options = new ChatCompletionOptions()
        {
            //Here we inject SMS tool that can send SMS directly from our app
            Tools = { SmsService.GetTool() },
        };

        ChatCompletion completion = chatClient.CompleteChat(chatMessagesArray, options);

        if (completion.FinishReason == ChatFinishReason.ToolCalls)
        {
            var toolCall = completion.ToolCalls[0];
            if (toolCall.FunctionName == "SendSms")
            {
                using JsonDocument argumentsDocument = JsonDocument.Parse(toolCall.FunctionArguments);

                argumentsDocument.RootElement.TryGetProperty("message", out JsonElement message);
                argumentsDocument.RootElement.TryGetProperty("phoneNumber", out JsonElement phoneNumber);

                return SmsService.SendSms(message.GetString()!, phoneNumber.GetString()!);
            }
            else
            {
                return "I couldn't send SMS.";
            }
        }
        else
        {
            string result = completion.Content[0].Text;
            var tokens = completion.Usage.TotalTokenCount;

            return $"{result}({tokens})";
        }
    }
}

What’s next?

Now feel free to copy the above code, and make some experiments adjusted to your needs. For example you might want to create your own tools that:

  • Send email
  • Read data from Database
  • Insert data to database
  • Read data from Azure AI Search

Remember: the most important concept is that LLM can call function automatically and pass proper arguments to the method. You don’t need to make up the arguments values on your own, LLM will do it for you. This is exactly the power of function calling.

Good luck!

By admin

Leave a Reply

Your email address will not be published. Required fields are marked *