深入探讨Function Calling:实现外部函数调用的工作原理

function,calling · 浏览次数 : 0

小编点评

**引言** Function Calling 是一个允许大型语言模型 (LLM) 调用外部函数或服务的功能。它允许我们以 JSON 格式向 LLM 描述函数,并使用模型的推理能力来决定在生成响应之前是否调用该函数。 **核心参数** * `tool_choice`: 指定了模型是否应该自动选择是否调用函数。可选值是 `auto` 或 `none`。默认值为 `auto`。 * `tools`: 包含可执行函数的详细信息。 * `function_call`: 包含要执行函数的信息。 **方法** 1. 模型检查是否有可用的函数调用。 2. 如果有,模型会生成一个 `ToolCall` 请求。 3. `ToolCall` 请求包含以下信息: * 函数名称 * 函数参数 4. 模型执行函数。 5. 模型返回 `ToolCallResponse`,即函数执行结果。 6. 模型使用 `ToolCallResponse` 来生成最终的用户响应。 **流程图** ```mermaid graph LR A[用户] --> B[问题] B --> C[LLM 模型] C --> D[生成 ToolCall 请求] D --> E[应用程序] E --> F[应用程序响应] F --> G[LLM 模型] G --> H[用户] ``` **简化说明** * 模型通过 `tool_calls` 回参返回可执行函数的信息。 * 用户可以通过 `FunctionCallResponse` 中的 `name` 和 `content` 信息来生成最终的用户响应。 * 流程图展示了函数调用和响应的步骤。

正文

引言

Function Calling 是一个允许大型语言模型(如 GPT)在生成文本的过程中调用外部函数或服务的功能。
Function Calling允许我们以 JSON 格式向 LLM 模型描述函数,并使用模型的固有推理能力来决定在生成响应之前是否调用该函数。模型本身不执行函数,而是生成包含函数名称执行函数所需的参数JSON

function calling 执行原理

现在我们定义提示词像大语言模型问一下当前北京的天气?

因为 LLM 大语言模型缺乏实时数据,所以无法回答实时数据这种场景。

我们用SK来测试一下

Console.WriteLine("===>没有设置function calling=<===");
{
    var kernel = Kernel.CreateBuilder().AddAzureOpenAIChatCompletion(config.ModelId,
            endpoint: config.Endpoint,
    apiKey: config.ApiKey).Build();
    var template = "当前北京的天气?";
    Console.WriteLine($"User: {template}");
    var function = kernel.CreateFunctionFromPrompt(template);
    var functionResult = await function.InvokeAsync(kernel);
    Console.WriteLine($"Assistant:{functionResult}");
}

输出:

User: 当前北京的天气?
Assistant:对不起,作为一个AI,我无法为你提供实时信息。你可以查看可信的天气应用或网站来获取当前北京的天气。

这时候就需要用到 LLMFunction Calling 功能来帮助回答用户的问题

使用 OpenAI API function calling

OpenAIfunction calling的核心是我们将Prompts 提示词和可用函数列表一起发送给LLM

OpenAI Chat Completions 接口

{
  "tool_choice": "auto",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "我想知道现在北京的天气状况"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "Get_Weather_For_City",
        "description": "获取指定城市的天气",
        "parameters": {
          "type": "object",
          "properties": {
            "cityName": {
              "type": "string",
              "description": "城市名"
            }
          }
        }
      }
    }
  ]
}

核心参数解释

tool_choice:

这个参数决定了模型是否应该自动选择是否调用函数。值为 "auto" 表示模型将根据情况自动决定是否调用函数。 默认情况下,如果请求中不存在任何函数,则将其设置为“none”,则设置为“auto”

tools

tools 部分定义了一个函数,这个函数可以被 OpenAI 的模型调用。以下是 tools 部分参数的简单解释:

  • type: 指定了这个工具的类型,这里是 "function",表示这是一个函数调用。

  • function: 包含函数的详细信息,是一个对象。

    • name: 函数的名称,这里是 "Get_Weather_For_City",这是调用时使用的函数名。

    • description: 函数的描述,这里是 "获取指定城市的天气",用于说明这个函数的作用。

    • parameters: 定义了函数调用时需要的参数,是一个对象。

      • type: 参数对象的类型,这里是 "object",表示参数是一个对象类型。

      • properties: 包含具体的参数定义,是一个对象,每个属性对应一个参数。

        • cityName: 这是一个参数的名称,表示城市名称。
          • type: 此参数的类型,这里是 "string",表示参数应该是一个字符串。
          • description: 参数的描述,这里是 "城市名",用于解释这个参数的意义。

这个 tools 部分定义了一个名为 Get_Weather_For_City 的函数,它需要一个名为 cityName 的字符串参数,用于指定想要查询天气的城市。当模型需要调用这个函数时,它将使用这个参数来获取相应的天气信息。

function calling 输出

{
  "id": "chatcmpl-9TOuIqnuMirU3BUDluCrHMTlsjz97",
  "object": "chat.completion",
  "created": 1716794282,
  "model": "gpt-4",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_DQU6OKHWyv3HVLyWVjSRqvwZ",
            "type": "function",
            "function": {
              "name": "Get_Weather_For_City",
              "arguments": "{\n  \"cityName\": \"北京\"\n}"
            }
          }
        ]
      },
      "logprobs": null,
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 83,
    "completion_tokens": 20,
    "total_tokens": 103
  },
  "system_fingerprint": null
}

最核心的方法是tool_calls回参里面返回了我们需要的方法名和一个 json 参数 比如"{\n \"cityName\": \"北京\"\n}"包含了我们的参数和值。

返回函数结果上下文

{
    "max_tokens": 3000,
    "tool_choice": "auto",
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user",
            "content": "我想知道北京的天气状况"
        },
        {
            "role": "assistant",
            "function_call": {
                "name": "Get_Weather_For_City",
                "arguments": "{\n  \"cityName\": \"北京\"\n}"
            }
        },
        {
            "role": "function",
            "name": "Get_Weather_For_City",
            "content": "27度,晴朗"
        }
    ],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "Get_Weather_For_City",
                "description": "获取指定城市的天气",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "cityName": {
                            "type": "string",
                            "description": "城市名"
                        }
                    }
                }
            }
        },
        {

需要把上下文信息和function callingresult回答的信息传给LLM

  • ToolCall上下文信息
{
  "role": "assistant",
  "function_call": {
    "name": "Get_Weather_For_City",
    "arguments": "{\n  \"cityName\": \"北京\"\n}"
  }
}
  • ToolCallResponse
{
  "role": "function",
  "name": "Get_Weather_For_City",
  "content": "27度,晴朗"
}

LLM 输出

{
  "id": "chatcmpl-9TRZBqCcRMBYIojuZimio6GOpsTi4",
  "object": "chat.completion",
  "created": 1716804505,
  "model": "gpt-4",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "北京的天气状况是27度,晴朗。"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 133,
    "completion_tokens": 19,
    "total_tokens": 152
  },
  "system_fingerprint": null
}

到现在为止简单的function calling的简单调用已经完成了
具体的流程可以总结为

image

可以看到function calling跟大预言模型至少有两次交互的的过程

总结

根据文档中的描述,OpenAI的函数调用(function calling)过程可以简化为以下几个步骤,并且可以用一个流程图来表示:

image

  1. 用户提出问题。
  2. 系统接收到问题,并检查是否有可用的函数可以调用。
  3. 如果有,系统会生成一个工具调用请求(ToolCall),并发送给应用程序。
  4. 应用程序执行请求的函数,并返回结果。
  5. 系统将函数的响应(ToolCallResponse)发送回 LLM 模型。
  6. LLM 模型使用这个响应来生成最终的用户响应。

下面是一个简化的流程图,描述了上述过程:

在这个流程图中:

  • A 代表用户。
  • B 是用户提出的问题。
  • C 是 LLM 模型,它检查是否有函数可以调用。
  • D 是生成工具调用(ToolCall)的步骤。
  • E 是应用程序,它接收 ToolCall 并执行相应的函数。
  • F 是应用程序返回的 ToolCallResponse,即函数执行的结果。
  • G 是 LLM 模型,它使用 ToolCallResponse 来生成用户响应。
  • H 是最终接收到用户响应的用户。

这个流程图是基于文档内容的简化表示,实际的系统可能包含更多的细节和步骤。

最后

本章的主要了解function calling及其工作原理的简单介绍。在下一篇博客中,我们 x 学习在Semantic kernel下使用使用function calling

参考资料

openai-function-calling

与深入探讨Function Calling:实现外部函数调用的工作原理相似的内容:

深入探讨Function Calling:实现外部函数调用的工作原理

引言 Function Calling 是一个允许大型语言模型(如 GPT)在生成文本的过程中调用外部函数或服务的功能。 Function Calling允许我们以 JSON 格式向 LLM 模型描述函数,并使用模型的固有推理能力来决定在生成响应之前是否调用该函数。模型本身不执行函数,而是生成包含函

深入探讨Function Calling:在Semantic Kernel中的应用实践

引言 上一章我们熟悉了 OpenAI 的 function calling 的执行原理,这一章节我们讲解一下 function calling 在 Semantic Kernel 的应用。 在OpenAIPromptExecutionSettings跟 LLM 交互过程中,ToolCallBehav

深入学习Semantic Kernel:创建和配置prompts functions

引言 上一章我们熟悉了一下 Semantic Kernel 的理论知识,Kernel 创建以及简单的Sample熟悉了一下 SK 的基本使用。在Semantic Kernel中的 kernel functions由两部分组成第一部分是prompts functions(提示函数),第二部分Nativ

Service Mesh技术详解

深入探讨Service Mesh的基本概念和核心技术,涵盖了服务发现、负载均衡、断路器与熔断机制,以及数据平面与控制平面的详细工作原理和实现方法。 关注作者,复旦博士,分享云服务领域全维度开发技术。拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,复旦机器人智能实验室成员,国家级大学生赛事

< Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓

深入探讨Python中的并发编程,特别关注多线程和多进程的应用。我们将先从基本概念开始,然后通过详细举例探讨每一种机制,最后分享一些实战经验以及一种优雅的编程技巧。

深入探讨Java面试中内存泄漏:如何识别、预防和解决

引言 在编写和维护Java应用程序时,内存泄漏是一个重要的问题,可能导致性能下降和不稳定性。本文将介绍内存泄漏的概念,为什么它在Java应用程序中如此重要,并明确本文的目标,即识别、预防和解决内存泄漏问题。 内存泄漏的概念 内存泄漏是指应用程序中分配的内存(通常是堆内存)在不再需要时未能正确释放。这

用户空间协议栈设计和netmap综合指南

深入探讨用户空间协议栈设计和netmap技术,以提高网络效率。我们将详细介绍用户空间协议栈的工作原理、优点和挑战,并提供一系列优化策略。

深入探讨安全验证:OAuth2.0、Cookie与Session、JWT令牌、SSO与开放授权平台设计

这篇文章讨论了认证和授权的概念,并探讨了设计权限认证框架的原则。它还比较了Cookie和Session的区别,并探讨了处理分布式部署时的Session保存问题。此外,文章还介绍了CSRF攻击及其防范方法,以及OAuth2.0、JWT令牌和SSO的概念。最后,文章提出了设计开放授权平台时需要考虑的因素。

深入探讨进程间通信的重要性:理解不同的通信机制(上)

本文旨在探讨进程间通信的重要性,并介绍了不同的通信机制,如管道、消息队列、共享内存、信号量、信号和套接字。通过理解这些通信机制的特点和应用场景,可以更好地实现进程间的高效数据共享。同时,本文还强调了同步和互斥机制的重要性,以确保数据的一致性和正确性。最后,还介绍了套接字作为一种跨网络和同一主机上进程间通信的通信机制,为读者提供了更全面的了解。通过阅读本文,读者将能够深入理解进程间通信的概念和不同机制,为实现有效的数据共享提供指导。

深入探讨进程间通信的重要性:理解不同的通信机制(下)

本文旨在探讨进程间通信的重要性,并介绍了不同的通信机制,如管道、消息队列、共享内存、信号量、信号和套接字。通过理解这些通信机制的特点和应用场景,可以更好地实现进程间的高效数据共享。同时,本文还强调了同步和互斥机制的重要性,以确保数据的一致性和正确性。最后,还介绍了套接字作为一种跨网络和同一主机上进程间通信的通信机制,为读者提供了更全面的了解。通过阅读本文,读者将能够深入理解进程间通信的概念和不同机制,为实现有效的数据共享提供指导。