Table of Contents

Use function call in AutoGen agent

Typically, there are three ways to pass a function definition to an agent to enable function call:

  • Pass function definitions when creating an agent. This only works if the agent supports pass function call from its constructor.
  • Passing function definitions in GenerateReplyOptions when invoking an agent
  • Register an agent with FunctionCallMiddleware to process and invoke function calls.
Note

To use function call, the underlying LLM model must support function call as well for the best experience. If the model does not support function call, it's likely that the function call will be ignored and the model will reply with a normal response even if a function call is passed to it.

Pass function definitions when creating an agent

In some agents like AssistantAgent or @AutoGen.OpenAI.GPTAgent, you can pass function definitions when creating the agent

Suppose the TypeSafeFunctionCall is defined in the following code snippet:

public partial class TypeSafeFunctionCall
{
    /// <summary>
    /// Get weather report
    /// </summary>
    /// <param name="city">city</param>
    /// <param name="date">date</param>
    [Function]
    public async Task<string> WeatherReport(string city, string date)
    {
        return $"Weather report for {city} on {date} is sunny";
    }
}

You can then pass the WeatherReport to the agent when creating it:

var function = new TypeSafeFunctionCall();
var assistantAgent = new AssistantAgent(
    name: "assistant",
    systemMessage: "You are an assistant that convert user input to upper case.",
    llmConfig: new ConversableAgentConfig
    {
        Temperature = 0,
        ConfigList = new[]
        {
            llmConfig
        },
        FunctionContracts = new[]
        {
            function.WeatherReportFunctionContract,
        },
    });

var response = await assistantAgent.SendAsync("hello What's the weather in Seattle today? today is 2024-01-01");
response.Should().BeOfType<ToolCallMessage>();
var toolCallMessage = (ToolCallMessage)response;
toolCallMessage.ToolCalls.Count.Should().Be(1);
toolCallMessage.ToolCalls[0].FunctionName.Should().Be("WeatherReport");
toolCallMessage.ToolCalls[0].FunctionArguments.Should().Be(@"{""location"":""Seattle"",""date"":""2024-01-01""}");

Passing function definitions in GenerateReplyOptions when invoking an agent

You can also pass function definitions in GenerateReplyOptions when invoking an agent. This is useful when you want to override the function definitions passed to the agent when creating it.

var function = new TypeSafeFunctionCall();
var reply = agent.GenerateReplyAsync(messages, new GenerateReplyOptions
{
    Functions = new[] { function.WeatherReportFunctionContract },
});

Register an agent with FunctionCallMiddleware to process and invoke function calls

You can also register an agent with FunctionCallMiddleware to process and invoke function calls. This is useful when you want to process and invoke function calls in a more flexible way.

var function = new TypeSafeFunctionCall();
var functionCallMiddleware = new FunctionCallMiddleware(
    functions: new[] { function.WeatherReportFunctionContract },
    functionMap: new Dictionary<string, Func<string, Task<string>>>
    {
        { function.WeatherReportFunctionContract.Name, function.WeatherReportWrapper },
    });

agent = agent!.RegisterMiddleware(functionCallMiddleware);
var reply = await agent.SendAsync("What's the weather in Seattle today? today is 2024-01-01");

Invoke function call inside an agent

To invoke a function instead of returning the function call object, you can pass its function call wrapper to the agent via functionMap.

You can then pass the WeatherReportWrapper to the agent via functionMap:

var function = new TypeSafeFunctionCall();
var assistantAgent = new AssistantAgent(
    name: "assistant",
    llmConfig: new ConversableAgentConfig
    {
        Temperature = 0,
        ConfigList = new[]
        {
            llmConfig
        },
        FunctionContracts = new[]
        {
            function.WeatherReportFunctionContract,
        },
    },
    functionMap: new Dictionary<string, Func<string, Task<string>>>
    {
        { function.WeatherReportFunctionContract.Name, function.WeatherReportWrapper }, // The function wrapper for the weather report function
    });

When a function call object is returned, the agent will invoke the function and uses the return value as response rather than returning the function call object.

var response = await assistantAgent.SendAsync("What's the weather in Seattle today? today is 2024-01-01");
response.Should().BeOfType<TextMessage>();
var textMessage = (TextMessage)response;
textMessage.Content.Should().Be("Weather report for Seattle on 2024-01-01 is sunny");

Invoke function call by another agent

You can also use another agent to invoke the function call from one agent. This is a useful pattern in two-agent chat, where one agent is used as a function proxy to invoke the function call from another agent. Once the function call is invoked, the result can be returned to the original agent for further processing.

var function = new TypeSafeFunctionCall();
var assistant = new AssistantAgent(
    "assistant",
    llmConfig: new ConversableAgentConfig
    {
        ConfigList = new[] { config },
        FunctionContracts = new[]
        {
            function.WeatherReportFunctionContract,
        },
    });

var user = new UserProxyAgent(
    name: "user",
    functionMap: new Dictionary<string, Func<string, Task<string>>>
    {
        { function.WeatherReportFunctionContract.Name, function.WeatherReportWrapper },
    });

await user.InitiateChatAsync(assistant, "what's weather in Seattle today, today is 2024-01-01", 10);