Published on

OpenAI Function calling

Authors
  • avatar
    Name
    Pursue
    Twitter

目录

开篇

最近 OpenAI 在 6 月 13 号发布了新 feature,主要针对模型进行了优化,提供了 function calling 的功能,该 feature 对于很多集成 OpenAI 的应用来说绝对是一个“神器”。

Prompt 的演进

如果初看 OpenAI 官网对function calling的介绍,似乎不足以体现它的重要性。为了更进一步理解它的作用,我们先来简单回顾一下在使用 OPenAI 时 Prompt 是如何演进的。

Prompt 1.0

还记得 chatGPT 在最一开始大火时,除了 AI 强大的能力作为一个吸引点之外,“低门槛的要求使得所有人都可以使用”也扮演着至关重要的角色。也正是如此,大家不再对 AI 感到陌生,借助和 AI 对话,随便一个 Prompt 就可以让使用者直接或间接的获得帮助。

但是随着使用深度的增加,大家慢慢发现chatGPT有时会思维发散,往往不能聚焦关键问题,甚至会“无言乱语”。

在此之上,1.0 版本的 Prompt 出现,它要求对话开始前需要设定上下文。在这样的提示下,AI 能够有较好的表现,并且不再发散,可以解决较为简单的问题。

Prompt 2.0

随着使用场景的复杂化,单纯的设置一个上下文给chatGPT已经远远不够。你必须给“足”上下文,最简单的方式就是提供exmaple,这种做法的背后逻辑和 COT(Chain of Thought)是一样的。

2.0 版本的 Prompt 是使用最广泛的也是最可靠的。

Prompt 3.0

3.0 版本的 Prompt 并非比 2.0 要高级,只是在需求上不一样。因为随着大量 AI 工具和 OpenAI 集成,想要充分利用 AI 的能力,让更多的系统和模块和你结合,就必须得提取参数或者返回特定的输出。

因此,3.0 聚焦更多的是集成。

Function calling

Prompt 在迭代到 3.0 版本后,AI 的缺点已经一览无遗。虽然chatGPT有大量的知识储备,但它的数据都是预训练的,由于不能联网,所以它并不是“无所不知”的。

因此,集成第三方系统对模型的赋能就成为了当下众多 AI 应用的首要方案。可赋能就代表得知道用户到底要知道什么,这就是 3.0 版本的努力方向。但是 3.0 的版本其实并不能非常稳定的输出特定格式,或者即便格式可以固定,json 数据的类型也不能很好的控制。比如上面的 3.0 例子里,不是所有的 AI 模型都能稳定输出price: 1500,也有可能是$1500(Bard)。 也许你会觉得1500$1500的差异并不大,大不了可以处理一下前缀之类的问题,那就大错特错了。因为这是作为 不同模块(或系统)链接的桥梁,就如同 API 之间集成的契约一般,必须有严格的定义。

一个典型的例子就是前段时间大火的Auto-GPT, 在 3.5 turbo 的模型下,它很难完成一个任务,往往会陷入无限的循环,主要的原因就是它需要非常严格的上下文衔接来集成各种 command,但凡有一丁儿点的差异都会导致“连接”失败。

在此背景下,function calling出现了。

它允许用户定义一个或多个 function 描述,该描述满足 API doc 的规范,定义了参数的类型和含义。AI 在经过 function calling 的调教后,可以准确的理解这种规范并按照上下文去决定是否可以“命中”该方法,如果“命中”,则会返回该方法的参数。

到此它已经解决了参数提取的问题,但并没有结束。此时开发者可以利用这个参数去集成第三方系统,获取特定的信息然后把结果反馈给模型,这样模型就有了这个方法的输入和输出,看起来像是模型“执行”了该方法,而实际是模型被动的获取了它没有的知识。

最后,AI 根据新获得的知识和信息,给用户输出最后的结果。

Example: DB 搜索

假设我们想利用 AI 在 DB 层建立搜索接口,我们可以按照以下步骤:

    1. 将 DB 的 meta 数据作为上下文,定义 ask_database 的方法规范
{
  "functions": [
    {
      "name": "ask_database",
      "description": "Use this function to answer user questions about music. Output should be a fully formed SQL query.",
      "parameters": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "SQL query extracting info to answer the user\\'s question.SQL should be written using this database schema:\"Table name: album_tb; Columns: album(string), published_at(string), likes(string)\".The query should be returned in plain text, not in JSON."
          }
        },
        "required": ["query"]
      }
    }
  ]
}
    1. 设定 system 上下文,提示模型如果 user 的 prompt 无法命中 function 的话就不要强行“脑补”

这很有用,说明不是所有的 Prompt 都需要被 function 来解析,有点类似 if else,这样可以回归到正常的对话中。

{
  "role": "system",
  "content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."
}
    1. 提问
{
  "role": "user",
  "content": "What are the top 2 the albums"
}
    1. 模型命中 function 并且返回解析的参数
{
  "role": "assistant",
  "content": null,
  "function_call": {
    "name": "ask_database",
    "arguments": "{\n  \"query\": \"SELECT * FROM album_tb ORDER BY likes DESC LIMIT 5\"\n}"
  }
}
    1. 查询 DB,将数据返回给我模型(赋能)
{
  "role": "function",
  "name": "ask_database",
  "content": "[{\"album\":\"Tanya\",\"published_at\":\"2000-01-01\",\"likes\":\"10000\"},{\"artist\":\"Im OK\",\"published_at\":\"1999-01-01\",\"likes\":\"20000\"}]"
}
    1. 模型根据新的知识储备响应用户的 Prompt
{
  "role": "assistant",
  "content": "The top 2 albums are \"Im OK\" with 20,000 likes and \"Tanya\" with 10,000 likes."
}
    1. 再次提问,测试新的知识储备是否被模型深刻理解
{
  "role": "user",
  "content": "What are the most popular one"
}
    1. 模型可以准确的在新的知识储备进行搜索
{
  "role": "assistant",
  "content": "The most popular album is \"Im OK\" with 20000 likes."
}

完整的 API 请求如下:

ask_database.json
{
	"model": "gpt-3.5-turbo-0613",
	"messages": [
		{
			"role": "system",
			"content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."
		},
		{
			"role": "user",
			"content": "What are the top 2 the albums"
		},
		{
			"role": "assistant",
			"content": null,
			"function_call": {
					"name": "ask_database",
					"arguments": "{\n  \"query\": \"SELECT * FROM album_tb ORDER BY likes DESC LIMIT 5\"\n}"
				}
		},
		{
			"role": "function",
			"name": "ask_database",
			"content": "[{\"album\":\"Tanya\",\"published_at\":\"2000-01-01\",\"likes\":\"10000\"},{\"artist\":\"Im OK\",\"published_at\":\"19999-01-01\",\"likes\":\"20000\"}]"

		},
		{
			"role": "user",
			"content": "What are the most popular one"
		}
	],
	"functions": [
		{
			"name": "ask_database",
			"description": "Use this function to answer user questions about music. Output should be a fully formed SQL query.",
			"parameters": {
				"type": "object",
				"properties": {
					"query": {
						"type": "string",
						"description": "SQL query extracting info to answer the user\\'s question.SQL should be written using this database schema:\"Table name: album_tb; Columns: album(string), published_at(string), likes(string)\".The query should be returned in plain text, not in JSON."
					}
				},
				"required": [
					"query"
				]
			}
		}
	]
}

模型

OpenAI 在 6 月 13 号的 release 中,专门针对 function calling 发布了新的模型,无论是价格还是上下文的长度都有比较大的变化,以下为 3.5(免费)的模型列表:

最后

function calling 对与模型精准的理解 Prompt 和集成外部知识储备系统绝对是一个强大的工具,未来 Prompt 的趋势肯定也会朝着个方向去设计,拭目以待吧。