引言

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的简单调用已经完成了

具体的流程可以总结为

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

总结

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

  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:实现外部函数调用的工作原理的更多相关文章

  1. function calling convention

    这是2013年写的一篇旧文,放在gegahost.net上面 http://raison.gegahost.net/?p=31 February 19, 2013 function calling c ...

  2. How Javascript works (Javascript工作原理) (一) 引擎,运行时,函数调用栈

    个人总结:该系列文章对JS底层的工作原理进行了介绍. 这篇文章讲了 运行时:js其实是和AJAX.DOM.Settimeout等WebAPI独立分离开的 调用栈:JavaScript的堆内存管理 和 ...

  3. 【深度探索c++对象模型】Function语义学之成员函数调用方式

    非静态成员函数 c++的设计准则之一就是:非静态成员函数至少和一般的非成员函数有相同的效率.编译器内部已将member函数实体转换为对等的nonmember函数实体. 转化步骤: 1.改写函数原型以安 ...

  4. PatentTips – Java native function calling

    BACKGROUND OF INVENTION This invention relates to a system and method for providing a native functio ...

  5. [转]ARM64 Function Calling Conventions

    from apple In general, iOS adheres to the generic ABI specified by ARM for the ARM64 architecture. H ...

  6. JavaScript外部函数调用AngularJS的函数、$scope

    x 场景: 需要在用FusionCharts画的柱状图中添加点击事件,But弹出框是Angularjs搞的,我想的是直接跳到弹出框的那个路由里,然后在弹出框的控制器中绑定数据即可: /* 点击事件 * ...

  7. V-rep学习笔记:外部函数调用方式

    The remote API functions are interacting with V-REP via socket communication in a way that reduces l ...

  8. Python 外部函数调用库ctypes简介

    Table of Contents 1. 参考资料 2. ctypes简介 2.1. 数据类型 2.2. 调用.so/.dll 2.2.1. 加载动态链接库 2.2.2. 调用加载的函数 2.2.3. ...

  9. java8学习之Lambda表达式继续探讨&Function接口详解

    对于上次[http://www.cnblogs.com/webor2006/p/8186039.html]已经初步引入的Java8中Stream流的概念,其中使用了map的操作,它需要接受一个Func ...

  10. Java HashMap工作原理深入探讨

    大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...

随机推荐

  1. 【开发者说】XstoryMaker快速书写剧本场景动画

    原文:https://mp.weixin.qq.com/s/63V0dfD2IufbX92JeD-G_A,点击链接查看更多技术内容. [开发者说]栏目是为HarmonyOS开发者提供的展示和分享平台, ...

  2. 构建动态交互式H5导航栏:滑动高亮、吸顶和锚点导航技巧详解

    功能描述 产品要求在h5页面实现集锚点.吸顶及滑动高亮为一体的功能,如下图展示的一样.当页面滑动时,内容区域对应的选项卡高亮.当点击选项卡时,内容区域自动滑动到选项卡正下方. 布局设计 css 布局 ...

  3. mysql 必知必会整理—数据库的维护[十八]

    前言 简单介绍一下数据库的维护. 正文 像所有数据一样,MySQL的数据也必须经常备份. 由于MySQL数据库是基于磁盘的文件,普通的备份系统和例程就能备份MySQL的数据. 但是,由于这些文件总是处 ...

  4. 树莓派和esp8266在局域网下使用UDP通信,esp8266采集adc数据传递给树莓派,树莓派在web上显示结果

    树莓派和esp8266需要在同一局域网下 esp8266使用arduino开发: 接入一个电容土壤湿度传感器,采集湿度需要使用adc #include <ESP8266WiFi.h> #i ...

  5. 很强!4.7k star,推荐一款Python工具,可实现自动化操作!!

    1.介绍 在日常工作中,肯定会遇到一些重复性的工作,不管是点击某个按钮.写东西,打印东西,还是复制粘贴拷贝资料之类的,需要进行大量的重复操作.按键精灵大家都听说过,传统的方式,大家可以使用按键精灵将操 ...

  6. 力扣423(java)-从英文中重建数字(中等)

    题目: 给你一个字符串 s ,其中包含字母顺序打乱的用英文单词表示的若干数字(0-9).按 升序 返回原始的数字. 示例 1: 输入:s = "owoztneoer"输出:&quo ...

  7. 力扣67(java)-二进制求和(简单)

    题目: 给你两个二进制字符串,返回它们的和(用二进制表示). 输入为 非空 字符串且只包含数字 1 和 0. 示例 1: 输入: a = "11", b = "1&quo ...

  8. anconda配置tensorflow环境

    一.anconda的安装 1.进入Anaconda官网并按照电脑配置选择合适的安装包 Anaconda官网:https://www.anaconda.com/ 点击进入 不同的三个版本,分别是wind ...

  9. 居然之家:核心业务系统全面上云,采用PolarDB替代传统商业数据库

    ​简介: 国内家居零售龙头企业居然之家完成7大核心业务系统全面上云工作,并实现ERP等核心业务系统从传统商业数据库向阿里云PolarDB云数据库的替换,助力业务系统整体处理能力提升50%以上,弹性能力 ...

  10. dotnet C# 序列化 XML 时进行自动格式化

    默认的序列化对象为 XML 字符串时,是没有进行格式化的,也就是所有的内容都在相同的一行.本文告诉大家方法,在序列化对象时,转换的 XML 是格式化的.或者说拿到 XML 字符串,对这个 XML 字符 ...