Semantic-Kernel throwing error when calling local Plugin

326 Views Asked by At

I'm trying to follow Microsoft's example for calling a native plugin, albeit in a LinqPad script.

The Pluging I've added to my script is identical to the example here.

When I call it "directly" using the following code, it works just fine:

double resultDirect = await kernel.InvokeAsync<double>(
    nameof(Plugins.MathPlugin), nameof(Plugins.MathPlugin.Sqrt),
    new()
    {
        {"number1", 12 },
    })!;

resultDirect.Dump();

However...when following the example Allow the AI to automatically call your function then the following line throws an exception:

await foreach (var content in result)

I get a Microsoft.SemanticKernel.HttpOperatonException thrown:

Unrecognized request arguments supplied: tool_choice, tools Status: 400 (model_error)

Content:
{
  "error": {
    "message": "Unrecognized request arguments supplied: tool_choice, tools",
    "type": "invalid_request_error",
    "param": null,
    "code": null
  }
}

I'm consuming the following NuGet packages:

  • Microsft.SemanticKernel 1.1.0

  • Microsft.SemanticKernel.Plugins.Core(pre) 1.1.0-alpha

  • Microsft.SemanticKernel.Planners.Handlebars(pre) 1.1.0-preview

1

There are 1 best solutions below

0
On

The "tools" and "tool_choice" are relative new addition to OpenAI api which might not be avaliable in the model you were using. Try a later version model and it should work.

To confirm, I tested with the exact same version of NuGet packages and followed the same code example. Only difference was that I was using Azure OpenAI GPT-3.5-turbo-1106 and GPT-4-1106-Preview as AI service. Both worked well.

Here is the polygon notebook code:

#r "nuget: Microsoft.SemanticKernel, 1.1.0"
#r "nuget: Microsoft.SemanticKernel.Core, 1.1.0-alpha"
#r "nuget: Microsoft.SemanticKernel.Planners.Handlebars, 1.1.0-preview"

using System.ComponentModel;
using Microsoft.SemanticKernel;

public class MathPlugin
{
    [KernelFunction, Description("Take the square root of a number")]
    public static double Sqrt(
        [Description("The number to take a square root of")] double number1
    )
    {
        return Math.Sqrt(number1);
    }

    [KernelFunction, Description("Add two numbers")]
    public static double Add(
        [Description("The first number to add")] double number1,
        [Description("The second number to add")] double number2
    )
    {
        return number1 + number2;
    }

    [KernelFunction, Description("Subtract two numbers")]
    public static double Subtract(
        [Description("The first number to subtract from")] double number1,
        [Description("The second number to subtract away")] double number2
    )
    {
        return number1 - number2;
    }

    [KernelFunction, Description("Multiply two numbers. When increasing by a percentage, don't forget to add 1 to the percentage.")]
    public static double Multiply(
        [Description("The first number to multiply")] double number1,
        [Description("The second number to multiply")] double number2
    )
    {
        return number1 * number2;
    }

    [KernelFunction, Description("Divide two numbers")]
    public static double Divide(
        [Description("The first number to divide from")] double number1,
        [Description("The second number to divide by")] double number2
    )
    {
        return number1 / number2;
    }

    [KernelFunction, Description("Raise a number to a power")]
    public static double Power(
        [Description("The number to raise")] double number1,
        [Description("The power to raise the number to")] double number2
    )
    {
        return Math.Pow(number1, number2);
    }

    [KernelFunction, Description("Take the log of a number")]
    public static double Log(
        [Description("The number to take the log of")] double number1,
        [Description("The base of the log")] double number2
    )
    {
        return Math.Log(number1, number2);
    }

    [KernelFunction, Description("Round a number to the target number of decimal places")]
    public static double Round(
        [Description("The number to round")] double number1,
        [Description("The number of decimal places to round to")] double number2
    )
    {
        return Math.Round(number1, (int)number2);
    }

    [KernelFunction, Description("Take the absolute value of a number")]
    public static double Abs(
        [Description("The number to take the absolute value of")] double number1
    )
    {
        return Math.Abs(number1);
    }

    [KernelFunction, Description("Take the floor of a number")]
    public static double Floor(
        [Description("The number to take the floor of")] double number1
    )
    {
        return Math.Floor(number1);
    }

    [KernelFunction, Description("Take the ceiling of a number")]
    public static double Ceiling(
        [Description("The number to take the ceiling of")] double number1
    )
    {
        return Math.Ceiling(number1);
    }

    [KernelFunction, Description("Take the sine of a number")]
    public static double Sin(
        [Description("The number to take the sine of")] double number1
    )
    {
        return Math.Sin(number1);
    }

    [KernelFunction, Description("Take the cosine of a number")]
    public static double Cos(
        [Description("The number to take the cosine of")] double number1
    )
    {
        return Math.Cos(number1);
    }

    [KernelFunction, Description("Take the tangent of a number")]
    public static double Tan(
        [Description("The number to take the tangent of")] double number1
    )
    {
        return Math.Tan(number1);
    }

    [KernelFunction, Description("Take the arcsine of a number")]
    public static double Asin(
        [Description("The number to take the arcsine of")] double number1
    )
    {
        return Math.Asin(number1);
    }

    [KernelFunction, Description("Take the arccosine of a number")]
    public static double Acos(
        [Description("The number to take the arccosine of")] double number1
    )
    {
        return Math.Acos(number1);
    }

    [KernelFunction, Description("Take the arctangent of a number")]
    public static double Atan(
        [Description("The number to take the arctangent of")] double number1
    )
    {
        return Math.Atan(number1);
    }
}

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;

// Create chat history
ChatHistory history = [];
// Create kernel
var builder = Kernel.CreateBuilder();
// Add a text or chat completion service using either:
builder.Services.AddAzureOpenAIChatCompletion(
    "gpt-35-turbo",                   // Azure OpenAI *Deployment Name*
    "https://mydeplyment.openai.azure.com",    // Azure OpenAI *Endpoint*
    "<Your-Azure-OpenAI-API-Key>",          // Azure OpenAI *Key*
    serviceId: "Azure_gpt_4"  
);
// builder.Services.AddAzureOpenAITextGeneration()
// builder.Services.AddOpenAIChatCompletion()
// builder.Services.AddOpenAITextGeneration()

builder.Plugins.AddFromType<MathPlugin>();
var kernel = builder.Build();

IChatCompletionService chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

// Start the conversation
// while (true)
// {
    // Get user input
    // Console.Write("User > ");
    // history.AddUserMessage(Console.ReadLine()!);
    history.AddUserMessage("Take the square root of 12");
    // 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)
    {
        if (content.Role.HasValue && first)
        {
            Console.Write("Assistant > ");
            first = false;
        }
        Console.Write(content.Content);
        fullMessage += content.Content;
    }
// }