如何使用Azure OpenAI进行函数调用

10
这是我的代码

response = openai.ChatCompletion.create(
    engine="XXX", # The deployment name you chose when you deployed the ChatGPT or GPT-4 model.
    messages=[
        {"role": "system", "content": "Assistant is a large language model trained by OpenAI."},
        {"role": "user", "content": "Calculate the circumference of circle with radius 5?"}
    ],
    functions=[{'name': 'circumference_calc', 'description': 'Calculate the circumference of circle given the radius', 'parameters': {'type': 'object', 'properties': {'radius': {'description': 'The radius of the circle', 'type': 'number'}}}, 'required': ['radius']}]
)

结果为:

InvalidRequestError: 提供的请求参数未被识别:functions

编写了上述代码


我在使用langchain代理和openai函数时遇到了相同的问题:https://github.com/hwchase17/langchain/issues/6777 - user2180171
我在使用Langchain代理和OpenAI函数时遇到了同样的问题:https://github.com/hwchase17/langchain/issues/6777 - user2180171
我在使用Langchain代理和OpenAI功能时遇到了相同的问题:https://github.com/hwchase17/langchain/issues/6777 - undefined
6个回答

23
更新(2023年7月13日): Azure现在支持在API版本2023-07-01-preview上调用函数,适用于以下模型:
  • gpt-4-0613
  • gpt-4-32k-0613
  • gpt-35-turbo-0613(感谢Joel)
  • gpt-35-turbo-16k-0613

之前的回答:

只有版本 gpt-3.5-turbo-0613gpt-4-0613 支持函数调用(ref),而Azure OpenAI服务目前仅支持这些版本(ref):

  • gpt-3.5-turbo-0301
  • gpt-4-0314
  • gpt-4-32k-0314
希望Azure OpenAI服务团队能尽快支持0613版本。
更新(2023年7月3日):尽管0613已经发布,但似乎他们仍不支持将functions作为参数,正如其他人在这里指出的那样。我已经尝试使用2023-06-01-preview,这应该是最新的API接口(根据这些规格),但没有成功。我还发现2023-07-01-preview版本也可以工作,但也没有成功。(现在情况已经改变,请参见顶部的更新)

你能找到微软的任何文档吗?还是它和Open AI的实现完全一样? - Chuanqi Sun
我假设这是 Azure 文档,暂时使用这个链接:https://github.com/Azure/azure-rest-api-specs/blob/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/preview/2023-07-01-preview/generated.json#L527(ChatCompletionsOptions)。在这些“文档”和 OpenAI 的文档之间只有一些细微的差异,但是通过测试,我发现这些差异实际上并不存在(比如 Azure 的“文档”表示 stop 参数只能是一个数组,但实际上字符串也有效)。我认为你现在可以假设实现是相同的(除了 OpenAI 的 model 参数)。 - NiklasMH
成功将其与gpt-35-turbo-0613和gpt-35-turbo-16k配合使用。只需在openai.ChatCompletion.create函数调用中添加api_version="2023-07-01-preview"参数即可。 - Joel Carneiro
@JoelCarneiro 你觉得这是一个故障/变通方法还是他们支持但尚未发布的功能?因为如果将来无法使用,我就不想使用它。谢谢。 - DevOpsInfo
我可以确认所有列出的模型对我都有效。感谢 @NiklasMH 带来这个好消息。 - Chuanqi Sun
显示剩余5条评论

3

现在已经开始工作了。请确保您的模型版本是0613。我已经使用gpt-35-turbo进行了测试。

import openai

openai.api_type = "azure"
openai.api_key = "XXX"
openai.api_base = "https://XXXX.openai.azure.com/"
openai.api_version = "2023-07-01-preview"

response = openai.ChatCompletion.create(
    engine="XXX",
    messages=[{"role": "user", "content": "what is current date?"}],
    functions=[
        {
            "name": "get_current_date",
            "description": "Get the current date in YYYY-MM-DD format",
            "parameters": {"type": "object", "properties": {}, "required": []},
        }
    ],
)
print(response["choices"][0])

回复:
<OpenAIObject at 0x10d2c1790> JSON: {
  "index": 0,
  "finish_reason": "function_call",
  "message": {
    "role": "assistant",
    "function_call": {
      "name": "get_current_date",
      "arguments": "{}"
    }
  },
  "content_filter_results": {}
}

1

0

0

0
我在这里使用API发布了一个示例:递归Azure OpenAI函数调用
 // *** Define the Functions ***
        string fnTodosPOSTDescription = "Creates a new TODO item. ";
        fnTodosPOSTDescription += "Use this function to add ";
        fnTodosPOSTDescription += "a new TODO item to the list";
        string fnTodosGETDescription = "Retrieves the TODO list. ";
        fnTodosGETDescription += "Use this function to view the TODO list.";
        string fnTodosDELETEDescription = "Deletes a specific TODO item ";
        fnTodosDELETEDescription += "from the list. Use this function to ";
        fnTodosDELETEDescription += "remove a TODO item from the list.";
        var fnTodosPOST = new FunctionDefinition();
        fnTodosPOST.Name = "Todos_POST";
        fnTodosPOST.Description = fnTodosPOSTDescription;
        fnTodosPOST.Parameters = BinaryData.FromObjectAsJson(new JsonObject
            {
                ["type"] = "object",
                ["properties"] = new JsonObject
                {
                    ["TodoRequest"] = new JsonObject
                    {
                        ["type"] = "object",
                        ["properties"] = new JsonObject
                        {
                            ["todo"] = new JsonObject
                            {
                                ["type"] = "string",
                                ["description"] = @"The TODO item to be added."
                            }
                        },
                        ["required"] = new JsonArray { "todo" }
                    }
                },
                ["required"] = new JsonArray { "TodoRequest" }
            });
        var fnTodosGET = new FunctionDefinition();
        fnTodosGET.Name = "Todos_GET";
        fnTodosGET.Description = fnTodosGETDescription;
        fnTodosGET.Parameters = BinaryData.FromObjectAsJson(new JsonObject
            {
                ["type"] = "object",
                ["properties"] = new JsonObject { }
            });
        var fnTodosDELETE = new FunctionDefinition();
        fnTodosDELETE.Name = "Todos_DELETE";
        fnTodosDELETE.Description = fnTodosDELETEDescription;
        fnTodosDELETE.Parameters = BinaryData.FromObjectAsJson(new JsonObject
            {
                ["type"] = "object",
                ["properties"] = new JsonObject
                {
                    ["TodoIndexRequest"] = new JsonObject
                    {
                        ["type"] = "object",
                        ["properties"] = new JsonObject
                        {
                            ["todoIdx"] = new JsonObject
                            {
                                ["type"] = "integer",
                                ["description"] = @"The index of the TODO item to be deleted."
                            }
                        },
                        ["required"] = new JsonArray { "todoIdx" }
                    }
                },
                ["required"] = new JsonArray { "TodoIndexRequest" }
            });
        // Create a new list of FunctionDefinition objects
        List<FunctionDefinition> DefinedFunctions = new List<FunctionDefinition>();
        // Add the FunctionDefinition objects to the list
        DefinedFunctions.Add(fnTodosPOST);
        DefinedFunctions.Add(fnTodosGET);
        DefinedFunctions.Add(fnTodosDELETE);

调用Azure OpenAI服务
        // Create a new ChatCompletionsOptions object
        var chatCompletionsOptions = new ChatCompletionsOptions()
            {
                Temperature = (float)0.7,
                MaxTokens = 2000,
                NucleusSamplingFactor = (float)0.95,
                FrequencyPenalty = 0,
                PresencePenalty = 0,
            };
        chatCompletionsOptions.Functions = DefinedFunctions;
        chatCompletionsOptions.FunctionCall = FunctionDefinition.Auto;
        // Add the prompt to the chatCompletionsOptions object
        foreach (var message in ChatMessages)
        {
            chatCompletionsOptions.Messages.Add(message);
        }
        // Call the GetChatCompletionsAsync method
        Response<ChatCompletions> responseWithoutStream =
        await client.GetChatCompletionsAsync(
            DeploymentOrModelName,
            chatCompletionsOptions);
        // Get the ChatCompletions object from the response
        ChatCompletions result = responseWithoutStream.Value;
        // Create a new Message object with the response and other details
        // and add it to the messages list
        var choice = result.Choices.FirstOrDefault();
        if (choice != null)
        {
            if (choice.Message != null)
            {
                ChatMessages.Add(choice.Message);
            }
        }
        // Update the total number of tokens used by the API
        TotalTokens = TotalTokens + result.Usage.TotalTokens;

看看ChatGPT是否作为响应想要调用一个函数。
    if (result.Choices.FirstOrDefault().FinishReason == "function_call")
    {
        // Chat GPT wants to call a function
        // To allow ChatGPT to call multiple functions
        // We need to start a While loop
        bool FunctionCallingComplete = false;
        while (!FunctionCallingComplete)
        {
            // Call the function
            ChatMessages = ExecuteFunction(result, ChatMessages);
            // *** Call Azure OpenAI Service ***
            // Get a response from ChatGPT
            // (now that is has the results of the function)
            // Create a new ChatCompletionsOptions object
            chatCompletionsOptions = new ChatCompletionsOptions()
                {
                    Temperature = (float)0.7,
                    MaxTokens = 2000,
                    NucleusSamplingFactor = (float)0.95,
                    FrequencyPenalty = 0,
                    PresencePenalty = 0,
                };
            chatCompletionsOptions.Functions = DefinedFunctions;
            chatCompletionsOptions.FunctionCall = FunctionDefinition.Auto;
            // Add the prompt to the chatCompletionsOptions object
            foreach (var message in ChatMessages)
            {
                chatCompletionsOptions.Messages.Add(message);
            }
            // Call the GetChatCompletionsAsync method
            Response<ChatCompletions> responseWithoutStreamFn =
            await client.GetChatCompletionsAsync(
                DeploymentOrModelName,
                chatCompletionsOptions);
            // Get the ChatCompletions object from the response
            result = responseWithoutStreamFn.Value;
            var FunctionResult = result.Choices.FirstOrDefault();
            // Create a new Message object with the response and other details
            // and add it to the messages list
            if (FunctionResult.Message != null)
            {
                ChatMessages.Add(FunctionResult.Message);
            }
            if (FunctionResult.FinishReason == "function_call")
            {
                // Keep looping
                FunctionCallingComplete = false;
            }
            else
            {
                // Break out of the loop
                FunctionCallingComplete = true;
            }
        }
    }
}
catch (Exception ex)
{
    // Set ErrorMessage to the exception message if an error occurs
    ErrorMessage = ex.Message;
}
finally
{
    // Clear the prompt variable
    prompt = "";
    // Set Processing to false to indicate
    // that the method is done processing
    Processing = false;
    // Call StateHasChanged to refresh the UI
    StateHasChanged();
}

执行一个函数
private List<ChatMessage> ExecuteFunction(
    ChatCompletions ChatCompletionResult, List<ChatMessage> ParamChatPrompts)
    {
        // Get the arguments
        var functionArgs =
        ChatCompletionResult.Choices.FirstOrDefault()
        .Message.FunctionCall.Arguments.ToString();
        // Get the function name
        var functionName =
        ChatCompletionResult.Choices.FirstOrDefault()
        .Message.FunctionCall.Name;
        // Variable to hold the function result
        string functionResult = "";
        // Use select case to call the function
        switch (functionName)
        {
            case "Todos_POST":
                var NewTODO =
                JsonSerializer.Deserialize<ToDoAddRequest>(functionArgs);
                if (NewTODO != null)
                {
                    functionResult = AddTodo(NewTODO.TodoRequest.todo);
                }
                break;
            case "Todos_GET":
                functionResult = GetTodos();
                break;
            case "Todos_DELETE":
                var DeleteTODO =
                JsonSerializer.Deserialize<ToDoRemoveRequest>(functionArgs);
                if (DeleteTODO != null)
                {
                    functionResult =
                    DeleteTodo(DeleteTODO.TodoIndexRequest.todoIdx);
                }
                break;
            default:
                break;
        }
        // Return with the results of the function
        var ChatFunctionMessage = new ChatMessage();
        ChatFunctionMessage.Role = ChatRole.Function;
        ChatFunctionMessage.Content = functionResult;
        ChatFunctionMessage.Name = functionName;
        ParamChatPrompts.Add(ChatFunctionMessage);
        return ParamChatPrompts;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接