我在六月份写了一篇关于GPT 函数调用(Function calling) 的博客https://blog.csdn.net/xindoo/article/details/131262670,其中介绍了函数调用的方法,但之前的函数调用,在一轮对话中只能调用一个函数。就在上周,OpenAI在开发者大会上,升级了函数调用的功能,在新的gpt-3.5和gpt-4模型中,可以在单次对话中调用多个函数了,而且在python SDK中也提供了并发函数调用相关的接口,无疑这将大幅减少大语言模型和现实世界之间交互的开发复杂度,接下来就让我用一个具体的示例,带你了解下OpenAI的新特性。
这里假设我需要利用gpt实现一个百度、谷歌、必应三个搜索引擎搜索结果汇总的功能。我现在有以下的几个搜索函数(我们假装已经实现了从分别从百度、谷歌、必应获取搜索结果的逻辑)。
def search_baidu(keyword):"""从百度搜索引擎中搜索关键词"""return f"{keyword}是一个技术博主"def search_google(keyword):"""从谷歌搜索引擎中搜索关键词"""return f"{keyword}是一个后端工程师"def search_bing(keyword):"""从必应搜索引擎中搜索关键词"""return f"{keyword}是一个Python爱好者"
接下来我们需要将这三个搜索函数按照openai给定的格式用json字符串描述出来,具体可以参考官方文档,我这里直接给出上面三个函数的json描述。
tools = [{"type": "function","function": {"name": "search_baidu","description": "从百度搜索引擎中搜索关键词","parameters": {"type": "object","properties": {"keyword": {"type": "string","description": "搜索关键词",}},"required": ["keyword"],},}}, {"type": "function","function": {"name": "search_google","description": "从google搜索引擎中搜索关键词","parameters": {"type": "object","properties": {"keyword": {"type": "string","description": "搜索关键词",}},"required": ["keyword"],},}}, {"type": "function","function": {"name": "search_bing","description": "从bing搜索引擎中搜索关键词","parameters": {"type": "object","properties": {"keyword": {"type": "string","description": "搜索关键词",}},"required": ["keyword"],},}}
]
available_functions = { "search_baidu": search_baidu, "search_google": search_google, "search_bing": search_bing }
上面这个的目的是将所有函数的作用和使用方法(入参)描述给gpt,让gpt知道如何去调用。available_functions是为了保存函数名和函数的映射关系,方便我们后续通过函数名去调用函数。
接下来我们实现一个函数,其功能就是给定一个关键词(keyword),返回百度、谷歌、必应三个搜索引擎搜索结果的汇总,这要在之前的函数调用方式下,你必须通过多轮对话获取到所有需要调用的函数,然后将结果汇总后在发给gpt。而在支持了多函数调用后,仅需要一轮对话就可以完成所有的功能,完整的代码如下:
from openai import OpenAI
import json
client = OpenAI(base_url='https://thales.xindoo.xyz/openai/v1/')def search(keyword):messages = [{"role": "user", "content": f"汇总下百度、谷歌、必应三个搜索引擎关于'{keyword}'的结果"}]# 发起首次请求,告诉gpt要做什么,已经有哪些函数可以调动 response = client.chat.completions.create(model="gpt-3.5-turbo-1106",messages=messages,tools=tools,tool_choice="auto", )response_message = response.choices[0].messagetool_calls = response_message.tool_calls# 检查是否需要调用函数if tool_calls:# 解析所有需要调用的函数及参数messages.append(response_message) # 注意这里要将openai的回复也拼接到消息列表里# 将所有函数调用的结果拼接到消息列表里for tool_call in tool_calls:function_name = tool_call.function.namefunction_to_call = available_functions[function_name]function_args = json.loads(tool_call.function.arguments)function_response = function_to_call(**function_args)messages.append({"tool_call_id": tool_call.id,"role": "tool","name": function_name,"content": function_response,}) second_response = client.chat.completions.create(model="gpt-3.5-turbo-1106",messages=messages,) return second_response.choices[0].message.contentprint(search("xindoo"))
输出的结果是根据百度、谷歌和必应三个搜索引擎的结果,'xindoo'可能是一个技术博主、后端工程师以及Python爱好者。
这里需要提醒以下两点:
- 目前只有gpt-4-1106-preview和gpt-3.5-turbo-1106两个模式支持单词对话同时调用多个模型的,其他模型均不支持。
- openAI改变了api中传递function的参数,废弃了 functions和 function_call,改用了tools和tool_choice两个新参数,我猜测是为了未来增加更多的工具支持。
这里额外说下,上面的三个函数调用是串行调用,如果每个函数都比较耗时的话,会增加整体的调用时长,而在最新的assistant api中增加了并行执行函数的api,这个我们放到下篇文章中讲解。