系列篇章💥
AI大模型探索之路-实战篇4:DB-GPT数据应用开发框架调研实践
AI大模型探索之路-实战篇5: Open Interpreter开放代码解释器调研实践
目录
- 系列篇章💥
- 一、前言
- 二、Function Calling详细流程剖析
- 1、创建OpenAI客户端
- 2、定义函数
- 3、创建数据参数对象
- 4、对象转化
- 5、函数调用测试
- 6、定义工具函数
- 7、发送OpenAI 对话请求测试
- 8、指定工具函数进行调用
- 9、存储返回的结果信息
- 10、查看函数名称和参数
- 11、调用工具函数
- 12、将第一次返回的结果合并到消息列表
- 13、将functiona的信息合并到消息列表
- 14、第二次OpenAI API调用
- 三、Function Calling完整样例
- 四、结语
一、前言
继之前对DB-GPT和Open Interpreter技术的深入调研,本文将转向对OpenAI的Function Calling技术进行回顾与探讨。此次分析的目的旨在为即将到来的智能数据分析平台的顺利落地做好充分的技术储备。通过对Function Calling技术的深度剖析,我们希望建立更加坚实的理论基础,并在此基础上探索其在实际应用中的潜在价值和实施路径。这将不仅有助于我们更好地理解语言模型如何与程序代码交互,而且为未来的开发工作提供指导和灵感。
二、Function Calling详细流程剖析
本章节旨在深入剖析从OpenAI客户端的创建到数据参数的定义,再到函数的定义、调用以及最终结果的整理输出的完整过程。这一详尽的解析将帮助我们深入理解Function Calling技术的每一个细节和实际应用中的操作流程。
1、创建OpenAI客户端
首先,我们需要创建一个有效的OpenAI客户端。这包括获取必要的API密钥和配置环境参数。通过这个过程,我们可以确保在后续步骤中顺畅地与OpenAI的服务器进行通信。
import openai
import os
import numpy as np
import pandas as pd
import json
import io
from openai import OpenAI
import inspect
# 从环境变量中获取OpenAI API密钥
openai.api_key = os.getenv("OPENAI_API_KEY")
# 使用API密钥创建OpenAI客户端实例
client = OpenAI(api_key=openai.api_key)
2、定义函数
定义了一个名为sunwukong_function的函数,该函数接受一个字符串类型的数据集作为参数,并将其转换为pandas DataFrame对象。然后,它将DataFrame中的每个元素乘以10,并将结果转换为JSON格式的字符串返回。
def sunwukong_function(data):
"""
孙悟空算法函数,该函数定义了数据集计算过程
:param data: 必要参数,表示带入计算的数据表,用字符串进行表示
:return:sunwukong_function函数计算后的结果,返回结果为表示为JSON格式的Dataframe类型对象
"""
data = io.StringIO(data)
df_new = pd.read_csv(data, sep='\s+', index_col=0)
res = df_new * 10
return json.dumps(res.to_string())
3、创建数据参数对象
接下来,我们需要定义数据参数。这些参数将作为输入传递给Function Call函数,以生成相应的输出结果。在本例中,我们将使用一个简单的数学计算任务作为示例。
#创建了一个名为df的DataFrame对象,其中包含两列数据x1和x2。
df = pd.DataFrame({'x1':[1, 2], 'x2':[3, 4]})
df
输出
4、对象转化
#将df对象转换为字符串类型。
df_str = df.to_string()
df_str
输出
5、函数调用测试
#将df字符串传递给sunwukong_function函数进行计算。最后,它将计算结果打印出来。
result_json=sunwukong_function(df_str)
result_json
6、定义工具函数
# 定义一个工具函数
sunwukong={
"type": "function",
"function": {"name": "sunwukong_function",
"description": "用于执行孙悟空算法函数,定义了一种特殊的数据集计算过程",
"parameters": {"type": "object",
"properties": {"data": {"type": "string",
"description": "执行孙悟空算法的数据集"},
},
"required": ["data"],
},
}
}
# 放入工具列表
tools = [sunwukong]
7、发送OpenAI 对话请求测试
我们通过大模型的对话请求API进行确认,大模型是否能能正确找到对应的函数工具。
# 这段代码定义了一个名为messages的列表,其中包含两个字典对象。第一个字典对象表示系统角色,其内容为数据集data的描述信息;第二个字典对象表示用户角色,其内容为执行孙悟空算法的请求。
messages=[
{"role": "system", "content": "数据集data:%s,数据集以字符串形式呈现" % df_str},
{"role": "user", "content": "请在数据集data上执行孙悟空算法"}
]
# 使用OpenAI API中的chat.completions.create方法来生成响应。该方法接受两个参数:model和messages。model参数指定要使用的模型版本,这里使用的是gpt-3.5-turbo模型;messages参数是要发送给API的消息列表,这里传入的是前面定义的messages列表。
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages
)
# 从响应中提取出第一个选择的消息,并将其打印出来。这个消息应该是由API根据输入的数据集和请求生成的孙悟空算法的结果。
response.choices[0].message
输出:
ChatCompletionMessage(content='抱歉,我不清楚您指的“孙悟空算法”是什么意思。请问您能提供更多关于该算法的背景或者说明吗?这样我才能帮助您更好地实现您的目标。', role='assistant', function_call=None, tool_calls=None)
当前对话中没有设置工具函数,因此大模型并没有找到自定义的工具函数
8、指定工具函数进行调用
我们再次进行大模型API调用,这一次我们指定功能工具函数tools,设置为自动选择(tool_choice=“auto”,)让模型自己检查判断是否需要调用工具函数。
messages=[
{"role": "system", "content": "数据集data:%s,数据集以字符串形式呈现" % df_str},
{"role": "user", "content": "请在数据集data上执行孙悟空算法"}
]
# 重新初始化消息列表后,设置tools参数和tool_choice,让大模型自己选择是否使用工具
# 不会直接执行function_call函数。这段代码是调用OpenAI API的chat.completions.create方法,用于生成聊天机器人的回答。其中,model参数指定了使用的模型版本,messages参数传入了要发送给API的消息列表,tools参数传入了工具列表,tool_choice参数指定了选择工具的方式。
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
tools=tools,
tool_choice="auto",
)
# 查看消息结果,返回内容为空,但是找到返回了工具函数
response.choices[0].message
输出:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_z16cI8SX4FkoW71SNV95hjIL', function=Function(arguments='{"data":"x1 x2\\n0 1 3\\n1 2 4"}', name='sunwukong_function'), type='function')])
从输出结果可以看到,工具配置生效,大模型已经找到了工具函数
9、存储返回的结果信息
将结果信息存储到first_response
# 打印出消息,可以看到消息中已经找到了函数sunwukong_function
first_response = response.choices[0].message
first_response
输出:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_z16cI8SX4FkoW71SNV95hjIL', function=Function(arguments='{"data":"x1 x2\\n0 1 3\\n1 2 4"}', name='sunwukong_function'), type='function')])
查看结果信息中的工具信息
response.choices[0].message.tool_calls
输出:
[ChatCompletionMessageToolCall(id='call_z16cI8SX4FkoW71SNV95hjIL', function=Function(arguments='{"data":"x1 x2\\n0 1 3\\n1 2 4"}', name='sunwukong_function'), type='function')]
10、查看函数名称和参数
将工具函数放入到字典中,再循环获取到工具列表中的每一个函数的名称,参数
#定义了一个名为available_tools的字典,其中包含了可用的工具函数
available_tools = {
"sunwukong_function": sunwukong_function,
}
#从API返回的回答中提取出工具调用信息,并遍历每个工具调用。对于每个工具调用,获取函数名、函数参数,并使用这些信息调用相应的工具函数。
tool_calls = response.choices[0].message.tool_calls
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_tools[function_name]
function_args = json.loads(tool_call.function.arguments)
function_response = function_to_call(**function_args)
# 打印出函数名、函数参数和函数响应。
print(function_name)
print(function_args)
print(function_response)
输出:
11、调用工具函数
#调用工具函数并获取其响应。它首先使用工具函数名和参数调用相应的工具函数,并将返回值存储在名为function_response的变量中。然后打印出这个响应
function_response = function_to_call(**function_args)
function_response
输出:
12、将第一次返回的结果合并到消息列表
# 追加第一次模型返回结果消息
messages.append(first_response)
messages
输出:
[{'role': 'system',
'content': '数据集data: x1 x2\n0 1 3\n1 2 4,数据集以字符串形式呈现'},
{'role': 'user', 'content': '请在数据集data上执行孙悟空算法'},
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_z16cI8SX4FkoW71SNV95hjIL', function=Function(arguments='{"data":"x1 x2\\n0 1 3\\n1 2 4"}', name='sunwukong_function'), type='function')])]
13、将functiona的信息合并到消息列表
# 追加function返回消息
messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response,
}
)
messages
输出:
[{'role': 'system',
'content': '数据集data: x1 x2\n0 1 3\n1 2 4,数据集以字符串形式呈现'},
{'role': 'user', 'content': '请在数据集data上执行孙悟空算法'},
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_z16cI8SX4FkoW71SNV95hjIL', function=Function(arguments='{"data":"x1 x2\\n0 1 3\\n1 2 4"}', name='sunwukong_function'), type='function')]),
{'tool_call_id': 'call_z16cI8SX4FkoW71SNV95hjIL',
'role': 'tool',
'name': 'sunwukong_function',
'content': '" x1 x2\\n0 10 30\\n1 20 40"'}]
14、第二次OpenAI API调用
第二次调用大模型API,让大模型帮忙整理响应信息
# 再次调用,由大模型重新整理工具函数返回的结果信息(主要是将结果信息整理的更加方便可视化)
second_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
)
print(second_response.choices[0].message.content)
三、Function Calling完整样例
完整的Function Calling函数使用代码如下
from openai import OpenAI
import json
openai.api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(api_key=openai.api_key)
# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def sunwukong_function(data):
"""
孙悟空算法函数,该函数定义了数据集计算过程
:param data: 必要参数,表示带入计算的数据表,用字符串进行表示
:return:sunwukong_function函数计算后的结果,返回结果为表示为JSON格式的Dataframe类型对象
"""
data = io.StringIO(data)
df_new = pd.read_csv(data, sep='\s+', index_col=0)
res = df_new['x1'] * 10
return json.dumps(res.to_string())
df_str=pd.DataFrame({'x1':[1, 2], 'x2':[3, 4]}).to_string
def run_conversation():
# 步骤1:将对话和可用函数发送给模型
messages=[
{"role": "system", "content": "数据集data:%s,数据集以字符串形式呈现" % df_str},
{"role": "user", "content": "请在数据集data上执行孙悟空算法"}
]
tools = [
{
"type": "function",
"function": {"name": "sunwukong_function",
"description": "用于执行孙悟空算法函数,定义了一种特殊的数据集计算过程",
"parameters": {"type": "object",
"properties": {"data": {"type": "string",
"description": "执行孙悟空算法的数据集"},
},
"required": ["data"],
},
}
}]
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
tools=tools,
tool_choice="auto", # auto is default, but we'll be explicit
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
# 步骤2:检查模型是否想要调用函数
if tool_calls:
# 步骤3:调用函数
# 注意:JSON响应可能不总是有效的;确保处理错误
available_functions = {
"sunwukong_function": sunwukong_function,
} # 这个例子中只有一个函数,但您可以有多个函数
messages.append(response_message) # 将助手的回复扩展到对话中
# 步骤4:将每个函数调用和函数响应的信息发送给模型
for tool_call in tool_calls:
function_name = tool_call.function.name
function_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",
messages=messages,
) # 从模型获取新的响应,其中可以看到函数响应
return second_response
result=run_conversation()
result.choices[0].message.content
输出:
# 使用StringIO将字符串转换为文件对象
df_str='\\n x1\\n0 10\\n1 20\\n.'
data = io.StringIO(df_str)
# 使用read_csv()函数读取数据,并设置第一列为索引
df_new = pd.read_csv(data, sep='\s+', index_col=0)
df_new
输出:
四、结语
本文深入探讨了函数调用的全过程,详细阐述了其每一个细节步骤。在回顾函数调用的实践应用中,我们不仅加深了对其运作机制的理解,还体会到了其在编程实践中的强大功能和灵活性。通过逐步剖析与实际操作的结合,本文档旨在为读者提供一个全面而实用的指南,以促进对函数调用概念的掌握及其在实际编程中的应用。希望读者能够借此更好地利用函数调用,优化代码结构,提升开发效率。
🎯🔖更多专栏系列文章:AIGC-AI大模型探索之路
如果文章内容对您有所触动,别忘了点赞、⭐关注,收藏!加入我,让我们携手同行AI的探索之旅,一起开启智能时代的大门!