ChatGPT 推出以来,大模型已经在全球范围内引起了公众的广泛关注。更令人兴奋的是,它们吸引了世界各地开发者的想象力。我们已经看到很多人将人工智能集成到应用程序中,使用语言模型来构建全新的产品,并提出与计算机交互的全新方式。自然语言交互终于成为了可能,并且质量很高。
但是也存在局限性和问题。对于任何使用过 ChatGPT 的人来说,我们都知道它的训练数据是 2021 年 9 月之前的,所以它不知道当前的事件。
在大多数情况下,像 ChatGPT 这样的语言模型是根据训练中的记忆进行操作的,因此它们与当前事件或所有 API、我们每天使用的自己的应用程序和网站无关。它不会连接到你公司的数据库和你公司的内部知识库等等。这使得 LLMs 的使用受到了限制。你可以使用LLMs 写一首诗,可以写一篇文章,可以从中得到一个很棒的笑话,可以搜索一些东西。但如何将语言模型与外部世界联系起来呢?如何增强人工智能的能力,让它来代表你执行行动,让它做比它固有能力更多的事情呢?
接下来讨论三件事。首先,讨论 LLMs 及其局限性。快速了解它们是什么以及它们是如何工作的。先对 LLMs 有个直观认识。然后还要了解 LLMs 的不足之处。其次,将介绍 ChatGPT 发布的一个全新特性,即使用 GPT 进行函数调用。函数调用是将 OpenAI 的 GPT 模型插入外部世界并让它执行操作的方式。最后,将通过几个演示样例来演示如何使用 OpenAI 模型和 GPT 函数调用功能,并将其集成到公司产品和辅助项目中。
LLMs 及其局限性
首先,对 LLM 做一个概述:它们做什么,它们是什么,它们如何工作。然后再了解一它们开箱即用的一些限制。
非常高层级的 GPT 模型,包括 ChatGPT、GPT-4、GPT-3.5-turbo,它们都是我们所说的自回归语言模型。这意味着它们是巨大的人工智能模型,它们接受过庞大的数据集的训练,包括互联网、维基百科、公共 GitHub 代码和其他授权材料。它们被称为自回归,因为它们所做的只是综合所有这些信息。它们接受一个 prompt,或者我们可以称之为上下文。它们查看 prompt。然后它们基本上只是决定,给定这个 prompt,给定这个输入,下一个单词应该是什么?它实际上只是在预测下一个单词。
例如,如果给定 GPT 的输入是,“the largest city in the United States is“(美国最大的城市是),那么答案就是 New York City(纽约市)。LLMs 会一个字一个字地思考,LLMs 会返回 “New”、“York”,然后是“City”。同样,在更具对话性的环境中,如果我们问它地球和太阳之间的距离是多少。GPT 已经从互联网上学过这个,它将输出 9400 万英里。它是根据输入逐个单词逐个单词思考的。
在底层,LLMs 真正做的是每次输出单词时,都会查看一堆候选单词并为它们分配概率。例如,在最初的例子中,“美国最大的城市是”,它可能有很多候选城市,New 代表“纽约”(New York),或者“新泽西”(New Jersey),或者其他什么,Los 代表“洛杉矶”(Los Angeles),然后还有其他一些可能的例子。你可以看到,它确实认为“New York City”(纽约市)可能是正确的答案,因为 New 的概率为 95%。在这种情况下,它通常会选择最有可能的结果,所以它会选择 New,然后继续前进。这个单词出现后,我们现在就知道 New 是第一个单词,所以它对下一个单词是什么就有了更多的限制。
我们可以看到,现在它认为 New York(纽约)的可能性要高得多,但它也在考虑 New Brunswick(新不伦瑞克)、New Mexico(新墨西哥)和 New Delhi(新德里)等。直到完成第二个单词,这基本上是模型的叠加。它基本上知道答案是 New York City,概率几乎是 100%。但它仍在考虑其他一些剩余概率很低的选项,比如 County(县)、New York Metro(纽约地铁)、New York Times(纽约时报),但最终它选择了 City 并给出答案。
对于更专业的 LLM 人士来说,这在技术上过于简单化了。LLMs 并不是真正在预测单词,而是在预测 token,比如单词片段,这实际上是一种更有效的表达英语的方式,主要是因为单词片段会在一堆不同的单词中重复,而不是单词本身会重复。但概念仍然是一样的。LLM 在这种上下文中,很可能会连续输出一堆不同的 token。就是这样,这就是这些语言模型的真正含义。
任何一个已经学习了 LLM 一段时间的人都会意识到,最大的一个是开箱即用的 LLM 或 GPT 实际上是一个装在盒子里的人工智能。它无法进入外部世界。它不知道任何其他信息。它就在那里,有它自己的记忆。感觉就像你在学校里参加考试时,只有你和考试,你只能根据记忆来回忆一些东西。
想象一下,如果考试是开放的,可以使用手机或类似的东西,我们会做得更好。GPT 今天真的只是在它自己的盒子里。正因为如此,作为工程师,我们希望使用 GPT 并将其集成到我们的系统中。限制 GPT,不允许它与我们的内部系统对话,这对于你可能想做的事情来说是非常有限的。此外,即使它确实可以访问某些工具,因为语言模型是概率性的,有时也很难保证模型与外部工具交互的方式。如果你有一个 API 或其他你想要使用的东西,当前模型不能保证总是能与你 API 可能想要的输入相匹配时,这最终也会成为一个问题。
例如,如果构建一个应用程序,并将此输入提供给 GPT,基本上就是说,下面是一个剧本的文本,从中提取一些信息,并以这种 JSON 格式对其进行结构化。让它推断出一种类型和一个子类型,以及其中的一些角色和年龄范围,就像 JSON 输出一样。
也许这是一个关于哈利波特的浪漫故事之类的剧本。它知道这是浪漫的,青少年的浪漫,它看到罗恩(Ron)和赫敏(Hermione),并以这种 JSON 格式准确输出。这太棒了,因为可以获取这个输出,可以使用它并将其放入 API 中。然后我就像在我的代码中一样,一切都正常。
但是,并不是一直稳定的输出,它会尝试并提供额外的帮助,做一些像这样的事情,它会说:“当然,我可以为你做。下面是你要求的 JSON 格式的信息。”这是非常有用的,但如果试图将其插入到 API 中,因为前面所有这些随机文本,我们的 API 并不知道如何解析它。这显然是非常令人失望的。这不是我们真正想要的。
使用 GPT 进行调用函数
为了解决上面的问题, OpenAI 发布的 API 的一个新变化,它使函数调用能够以一种非常友好的方式更好地使用 GPT 模型。举个例子,如果问 GPT 这样的问题,what's the weather like in Brooklyn today? (今天布鲁克林的天气怎么样?)如果你问一个普通的 GPT 这个问题,它基本上会说,“作为一个由 OpenAI 训练的人工智能模型,我无法提供实时信息。”这是真的,因为它实际上无法访问任何东西。它在一个盒子里。它怎么会知道今天天气怎么样呢?
这显然确实限制了它的能力,这是不可取的。OpenAI 更新了 GPT-4 和 gpt-3.5-turbo 模型。收集了大量的工具使用和函数调用数据,根据这些数据对模型进行了微调,使其真正擅长选择是否使用工具。这些模型现在可以更智能地使用工具和调用函数。在这个特殊的例子中,当我们询问模型“今天布鲁克林的天气怎么样?”时,LLMs 现在能做的就是解析这个输入,同时告诉 LLMs 一组函数,如果需要帮助,它应该尝试并调用这个函数。
在本例中,为 LLMs 提供一个名为 get_current_filther
的函数。该函数接收一个带有 location(位置)的字符串,然后它就知道它可以使用这个。当我们询问模型“今天布鲁克林的天气怎么样?”时,GPT 将表达它打算调用 get_current_filther
函数的意图。然后,我们可以根据需要在自己的系统中自行调用该函数。假设得到的输出是 “22 Celsius and Sunny”(22 摄氏度和阳光明媚)。可以将其解析回 GPT,LLMs 会综合这些信息,并返回给用户说:the weather in Brooklyn is currently sunny, with a temperature of 22 degrees Celsius(目前布鲁克林天气晴朗,温度为 22 摄氏度。)
稍微解释一下,真正发生的事情是 GPT 知道一组函数,并且它会智能地自行表达调用其中某个函数的意图。然后执行调用,并将其解析回 GPT。这就是我们最终将它与外界联系起来的方式。 应用程序在底层实际做的事情将经历一个三步的过程,首先调用 OpenAI,然后使用我们自己的函数,最后再次调用 OpenAI 或 GPT。
第一步,是用户问了一个问题,在本例中,问题是 what's the weather like in Brooklyn today?(“今天布鲁克林的天气怎么样?”)然后下一步是,在应用程序中,调用模型,调用 OpenAPI,并非常具体地告诉它它可以访问的函数集以及用户输入的参数解析。
这是一个 LLMs 现在可以解析的新参数,在这里解析的是,列出了这个模型应该知道的一组函数,它应该可以访问的函数集。在本例中,我们只有一个函数,它就是 get_current_tweather
函数。在这里还放了一个自然语言描述。描述这个函数可以获取特定位置的当前天气。LLMs 还需要输入函数签名。并且我们告诉它有两个参数。一个参数是 location(位置),这是一个字符串,包含城市和州,格式是这样的:旧金山,加州(San Francisco, California.)。另一个参数时 unit(单位),即摄氏度(Celsius)或华氏度(Fahrenheit)。
在下图中,还有另一个参数,该参数表示唯一必须的属性是位置。从技术上讲,只需要解析位置,这里不需要单位。我们将该请求解析到 GPT,然后 GPT 将作出响应。在过去中,GPT 可能只会以文本形式进行响应。它会说:“我不能这样做,因为我没有访问权限。”在本例中,我们的 API 响应的是调用天气函数的意图。
这里真正发生的事情是 GPT 凭自己的决策,为了弄清楚今天的天气,我自己做不到,但我可以访问 get_current_weither
这个函数,所以我会选择调用它,所以我要表达要调用它的意图。GPT 在这里所做的是,它在这里构造参数。它在告诉我们,它想调用get_current_tweather
,它想用参数位置(Brooklyn, New York;纽约布鲁克林)来调用该函数。
下一步是,LLMs 弄清楚到底想要如何调用这个函数。可以根据特定参数从get_current_tweather
的函数调用中获取相应的返回值。然后我们可以自己执行。它可以是本地的,在我们自己的 Web 服务器上运行。它也可以是系统中的另一个 API,还可能是一个外部 API,我们可以调用 weather.com API。
第一个基本上是对意图的重申,所以基本上是说助理或 GPT 想要用纽约布鲁克林的这个参数来调用get_current_tweather
函数。然后,我们还添加了第三条消息,它基本上说明了我们所进行的函数调用的结果,因此这是get_current_filther
的结果。然后,内联这里输出的数据,即温度“22”、单位“摄氏度”和描述“晴天”,然后将所有数据解析给 GPT。在此时,GPT 接收了它,并决定它想要做什么。
此时,模型已经足够智能了,它能够意识到“我将调用这个函数。这是输出。我实际上已经掌握了实际完成请求所需的所有信息。”它现在最终会通过文本方式来做出回应,并显示“今天布鲁克林天气晴朗,温度为 22 摄氏度”。这时,得到了 GPT 的最终输出。然后回应就可以用户的问题了。
总结整个流程:用户询问“今天布鲁克林的天气怎么样?” LLMs 的服务器会思考一下,GPT 表达意图,调用了我们的函数。最终,用户看到的是“今天布鲁克林天气晴朗,气温为 22 摄氏度。成功”
小结:首先,我们了解了语言模型是如何工作的,以及它们的一些局限性,因为它们没有所有的训练数据,它们没有连接到外部世界,它们的结构化输出并不总是可解析的。我们还了解了新模型的新特性、函数调用和 API 的工作原理,以及如何将函数解析为 API 并获取输出,以及如何让 GPT 以面向用户的方式来总结响应。让我们通过几个演示来了解如何将所有这些组合起来,并将其应用到我们的产品和应用程序中。
? OpenAI Function Calling 与 LangChain Agent 工作原理及区别 ?
示例
将自然语言转换为数据表查询
示例是,假设你正在构建一个数据分析应用程序或商业智能工具,比如 Tableau 或 Looker。大多数情况下,我只想问数据库,谁是顶级用户,然后得到响应。今天终于有可能了。我们将使用 GPT,将给它一个称为 SQL 查询的函数,它只需要一个参数,即一个字符串“query”。
它应该是针对我们数据库的一个有效 SQL 字符串。让我们看看它是如何工作的。首先,我们将为模型提供一条系统消息,描述它应该做什么。我们称之为 SQL GPT,可以将自然语言查询转换为 SQL。当然,模型需要访问数据库模式。在本例中,我们有两个表,用户表(users)和订单表(orders)。用户表有姓名、电子邮件和生日。订单表有用户 ID、购买金额和购买日期。现在我们可以开始使用一些自然语言来查询数据库了。
我们来问这样一个问题“根据上周的消费金额,找出排名前 10 的用户姓名”(get me the names of the top 10 users by amount spent over the last week.)。这是一个相当正常的业务问题,GPT 可以立即编写 SQL 就能解决的问题,
调用外部 API 和多个函数
假设我们正在纽约参加一个会议,我们想预订今晚的晚餐。我们将使用两个函数来调用 GPT。第一个是 get_current_location
。它在设备上本地运行,比如在你的手机或浏览器上,并获取你所在位置的纬度(Lat
)和经度(Long
)。第二个函数是 Yelp 搜索,它使用 Yelp 的 API,也就是流行餐厅评价应用程序,我们可以对纬度、经度和查询进行解析。
把 GPT 变成了一个有用的助手。我说“我正在参加一个会议,想在附近吃晚饭,有什么选择吗?我的公司会支付这笔费用,这样我们就可以尽情享受了”。让我们用 GPT 来运行一下它,看看它是如何做的。
当然,GPT 不知道我们在哪里,所以它说 get_current_location
,我们将调用本地 API 来获取我们的纬度和经度。我们已经获取到了。是纽约的布鲁克林(Brooklyn, New York)的某个地方。我们会将其返回给 GPT,看它怎么说。它已经有了所需的信息,现在它想调用 Yelp,它说“纬度、经度和查询”,并且会说“美食”。这很好。这就是我想要的。让我们调用 Yelp 并获取一些数据。
我们从 Yelp API 中获取了一堆餐馆。当然,我希望它能给出一个漂亮的总结,所以让我们再次运行它。它回复说“你附近有一些高档餐饮可选择,La Vara、Henry's End、Colonie、Estuary”。上面还写着“请检查营业时间,尽情用餐。”这听起来很美味。再次感谢 GPT 帮助我们组织今晚的晚宴。
这是一个使用 GPT 和函数调用外部 API(在本例中为 Yelp API)以及协调多个函数的示例。它能够凭借推理能力解析用户意图,并依次执行多个步骤的操作,以实现最终目标。
总结
首先,我们讨论了 LLM 及其局限性。我们了解了 LLM 是如何工作的,它是 token 预测机。我们了解了它的局限性。它被时间限制住了。它并不总是输出结构化的输出等等。
其次,我们了解了这个新特性,即使用 GPT 进行函数调用,这是对 API 和模型的更新。它允许模型表达何时调用函数的意图,并为我们构建有效的参数,然后在我们的终端上调用该函数。
通过 Function Calling 的方式将语言模型与外部世界联系起来,增强人工智能的能力,让它来代表你执行行动,让它做比它固有能力更多的事情。
推荐阅读
OpenAI Function Calling 与 LangChain Agent 工作原理及区别 ReAct Agent 回答 RAG 系统中的复杂问题 更智能的 Agent,Plan-and-Execute Agents 计划和执行 高级 RAG(Self-Reflective RAG)
作者简介
Sherwin Wu 是 OpenAI 的技术人员。他在开发者平台团队工作,负责开发允许开发者基于 OpenAI 模型和功能构建产品的产品。
Atty Eleti 是 OpenAI 的软件工程师,致力于他们的 API 和开发者平台。此前,他在 Stripe 花了很多年时间构建 API。
参考资料
A Bicycle for the (AI) Mind: GPT-4 + Tools (https://www.infoq.com/presentations/bicycle-ai-gpt-4-tools/)
Function calling - OpenAI API (https://platform.openai.com/docs/guides/function-calling)