文章目录
前言
一、Function函数特点
二、Function应用场景
三、Function参数说明
四、基于Function函数实现天气查询服务
五、基于Function函数实现数据平台查询
总结
前言
OpenAI大语言模型不仅在文本生成、翻译、问答等方面表现出色;同时引入了Function函数,通过Function函数对大模型能力进行扩展增强。本文将深入探讨Function函数的特点、功能和使用场景,让我们在开发学习中可以更好地理解和利用这一强大工具。
一、Function函数特点
Function函数是OpenAI大模型非常重要的一个功能点,它允许大模型在生成响应时,可以调用外部函数来获取回复结果。这些函数可以是任何类型的计算或数据检索操作,包括但不限于联网检索、数据库查询、复杂数学计算等。这种设计使得大模型不再局限于其内置的知识库,而是能够动态地获取和处理信息。
二、Function应用场景
1) 实时信息检索:通过Function函数,大模型可以接入互联网或其他数据源,获取最新的信息;如天气预报、股票价格查询等需要实时数据任务信息。
2)复杂计算:Function函数还可以用来执行复杂的计算任务,比如数据分析、图形渲染等。这使得模型能够在更复杂的应用场景中发挥作用。
3)代码解释与执行:通过Function函数,模型甚至可以解释和执行代码,这为开发者提供了一个强大的编程辅助工具。
4)个性化服务:Function函数还可以用来实现个性化服务,比如根据用户的特定需求生成定制化的内容。
三、Function参数说明
Function函数主要包括Function和Function_call两个参数配合使用;为了兼容后续的扩展;官网已经升级调整为tools和tool_choice,将Function调整为tools中的一种类型的工具
1)tools参数:自定义工具列表,配置自定义函数(目前Type只支持function),可以配置多个函数
2)tool_choice参数:设置是否需要大模型调用自定义的funcation函数(none/auto)
none:表示不调用自定义函数、auto:表示大模型可以自动选择生成消息或者调用函数
升级前:
#1.大模型API调用
#data = openai.ChatCompletion.create(model= GPT_MODEL,messages = messages,functions = functions,function_call = None)
data = openai.ChatCompletion.create(
model= GPT_MODEL,
messages = messages,
functions = functions,
function_call = {"name": "functionName1"}
)
#2.function函数定义
functions = [
{
"name": "functionName1", # 功能的名称
"description": "XXXX", # 功能的描述
"parameters": { # 定义该功能需要的参数
....
},
},
{
"name": "functionName2", # 功能的名称
"description": "XXXX", # 功能的描述
"parameters": { # 定义该功能需要的参数
....
},
},
..................
]
升级后:
#1.大模型API调用
data = client.chat.completions.create(
model= GPT_MODEL,
messages = messages,
tools = tools,
tool_choice={"type": "function", "function": {"name": "functionName1"} )
#2.function函数定义
tools = [
{
"type": "function", #固定设置为function,目前仅支持function
"function": {
"name": "functionName1",# 功能的名称
"description": "xxxxxx",# 功能的描述
"parameters": { # 定义该功能需要的参数
.......
},
}
},
{
"type": "function",
"function": {
"name": "functionName2",# 功能的名称
"description": "xxxxxx",# 功能的描述
"parameters": { # 定义该功能需要的参数
.......
},
}
},
..........................
]
四、基于Function函数实现天气查询服务
通过一个实战案例来演示如何使用Function函数实现天气查询服务。
1)环境准备pip install scipy tenacity tiktoken termcolor openai requests
2)导入依赖、定义客户端
import json
from openai import OpenAI
from tenacity import retry, wait_random_exponential, stop_after_attempt
from termcolor import colored
GPT_MODEL = "gpt-3.5-turbo-0613"
client = OpenAI()
#client.models.list()
3)请求封装
定义一个函数chat_completion_request,主要用于发送 聊天补全 请求到OpenAI服务器
def chat_completion_request(messages, tools=None, tool_choice=None, model=GPT_MODEL):
try:
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice=tool_choice,
)
return response
except Exception as e:
print("Unable to generate ChatCompletion response")
print(f"Exception: {e}")
return e
4)定义打印函数
定义一个函数pretty_print_conversation,用于打印消息对话内容
def pretty_print_conversation(messages):
# 为不同角色设置不同的颜色
role_to_color = {
"system": "red",
"user": "green",
"assistant": "blue",
"function": "magenta",
}
# 遍历消息列表
for message in messages:
# 如果消息的角色是"system",则用红色打印“content”
if isinstance(message, dict) and message["role"] == "system":
print(colored(f"system: {message['content']}\n", role_to_color[message["role"]]))
# 如果消息的角色是"user",则用绿色打印“content”
elif isinstance(message, dict) and message["role"] == "user":
print(colored(f"user: {message['content']}\n", role_to_color[message["role"]]))
# 如果消息的角色是"assistant",并且消息中包含"function_call",则用蓝色打印"function_call"
elif hasattr(message, 'role') and message.role == "assistant" and message.function_call:
print(colored(f"assistant: {message.function_call}\n", role_to_color[message.role]))
# 如果消息的角色是"assistant",但是消息中不包含"function_call",则用蓝色打印“content”
elif hasattr(message, 'role') and message.role == "assistant" and not message.function_call:
print(colored(f"assistant: {message.content}\n", role_to_color[message.role]))
elif isinstance(message, dict) and message["role"] == "function":
# 如果消息的角色是"function",则用品红色打印“function”
print(colored(f"function ({message['name']}): {message['content']}\n", role_to_color[message["role"]]))
5)自定义函数查询某地天气
定义一个tools 的工具集(函数列表),包含2个为function函数,这两个函数分别定义了相关功能的参数
# 第一个字典定义了一个名为"get_current_weather"的函数
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",# 函数的名称
"description": "Get the current weather",# 函数的描述
"parameters": {# 定义该函数需要的参数
"type": "object",
"properties": {# 参数的属性
"location": {# 地点参数
"type": "string",# 参数类型为字符串
"description": "The city and state, e.g. San Francisco, CA",# 参数的描述
},
"format": {# 温度单位参数
"type": "string",# 参数类型为字符串
"enum": ["celsius", "fahrenheit"],# 摄氏度,华氏 参数的取值
"description": "The temperature unit to use. Infer this from the users location.",# 参数的描述
},
},
"required": ["location", "format"],# 该函数需要的必要参数
},
}
},
# 第二个字典定义了一个名为"get_n_day_weather_forecast"的函数
{
"type": "function",
"function": {
"name": "get_n_day_weather_forecast",
"description": "Get an N-day weather forecast",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location.",
},
"num_days": {
"type": "integer",
"description": "The number of days to forecast",
}
},
"required": ["location", "format", "num_days"]
},
}
},
]
6)函数调用:咨询今天天气
messages = []
messages.append({"role": "system", "content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."})
messages.append({"role": "user", "content": "What's the weather like today"})
chat_response = chat_completion_request(
messages, tools=tools
)
assistant_message = chat_response.choices[0].message
messages.append(assistant_message)
#assistant_message
# 打印助手的回复消息
pretty_print_conversation(messages)
7)函数调用:回复当前地点
messages.append({"role": "user", "content": "I'm in ShenZhen, China."})
#大模型自己选择是否使用函数
#chat_response = chat_completion_request(messages, tools=tools)
#强制使用函数
chat_response = chat_completion_request(messages, tools=tools, tool_choice={"type": "function", "function": {"name": "get_current_weather"}})
assistant_message = chat_response.choices[0].message
messages.append(assistant_message)
#assistant_message
# 打印助手的回复消息
pretty_print_conversation(messages)
8)设置问答样例,用于咨询未来5天的天气
messages = []
messages.append({"role": "system", "content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."})
messages.append({"role": "user", "content": "what is the weather going to be like in Glasgow, Scotland over the next x days"})
chat_response = chat_completion_request(
messages, tools=tools
)
assistant_message = chat_response.choices[0].message
messages.append(assistant_message)
#assistant_message
# 打印助手的回复消息
pretty_print_conversation(messages)
9)咨询未来5天天气
messages = []
messages.append({"role": "system", "content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."})
messages.append({"role": "user", "content": "Give me a weather report for Toronto, Canada."})
chat_response = chat_completion_request(
messages, tools=tools, tool_choice={"type": "function", "function": {"name": "get_n_day_weather_forecast"}}
)
chat_response.choices[0].message
五、基于Function函数实现数据平台查询
1)定义数据库信息
import sqlite3
conn = sqlite3.connect("data/chinook.db")
print("Opened database successfully")
2)定义获取数据库信息的函数
首先定义三个函数get_table_names、get_column_names和get_database_info,用于从数据库连接对象中获取数据库的表名、表的列名以及整体数据库的信息;作为大模型的知识背景进行使用
def get_table_names(conn):
"""返回一个包含所有表名的列表"""
table_names = [] # 创建一个空的表名列表
# 执行SQL查询,获取数据库中所有表的名字
tables = conn.execute("SELECT name FROM sqlite_master WHERE type='table';")
# 遍历查询结果,并将每个表名添加到列表中
for table in tables.fetchall():
table_names.append(table[0])
return table_names # 返回表名列表
def get_column_names(conn, table_name):
"""返回一个给定表的所有列名的列表"""
column_names = [] # 创建一个空的列名列表
# 执行SQL查询,获取表的所有列的信息
columns = conn.execute(f"PRAGMA table_info('{table_name}');").fetchall()
# 遍历查询结果,并将每个列名添加到列表中
for col in columns:
column_names.append(col[1])
return column_names # 返回列名列表
def get_database_info(conn):
"""返回一个字典列表,每个字典包含一个表的名字和列信息"""
table_dicts = [] # 创建一个空的字典列表
# 遍历数据库中的所有表
for table_name in get_table_names(conn):
columns_names = get_column_names(conn, table_name) # 获取当前表的所有列名
# 将表名和列名信息作为一个字典添加到列表中
table_dicts.append({"table_name": table_name, "column_names": columns_names})
return table_dicts # 返回字典列表
# 获取数据库信息,并存储为字典列表
database_schema_dict = get_database_info(conn)
# 将数据库信息转换为字符串格式,方便后续使用
database_schema_string = "\n".join(
[
f"Table: {table['table_name']}\nColumns: {', '.join(table['column_names'])}"
for table in database_schema_dict
]
)
database_schema_string
3)自定义Function函数
定义 functions让 GPT 模型帮我们构造一个完整的 SQL 查询
# 定义一个功能列表,其中包含一个功能字典,该字典定义了一个名为"ask_database"的功能,用于回答用户关于音乐的问题
tools = [
{
"type": "function",
"function": {
"name": "ask_database",
"description": "Use this function to answer user questions about music. Input should be a fully formed SQL query.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": f"""
SQL query extracting info to answer the user's question.
SQL should be written using this database schema:
{database_schema_string}
The query should be returned in plain text, not in JSON.
""",
}
},
"required": ["query"],
},
}
}
]
4)定义SQL执行函数
用于根据大模型返回的SQL,执行查询操作
def ask_database(conn, query):
"""使用 query 来查询 SQLite 数据库的函数。"""
try:
results = str(conn.execute(query).fetchall()) # 执行查询,并将结果转换为字符串
except Exception as e: # 如果查询失败,捕获异常并返回错误信息
results = f"query failed with error: {e}"
return results # 返回查询结果
def execute_function_call(message):
"""执行函数调用"""
# 判断功能调用的名称是否为 "ask_database"
if message.tool_calls[0].function.name == "ask_database":
#if message["function_call"]["name"] == "ask_database":
# 如果是,则获取功能调用的参数,这里是 SQL 查询
#query = json.loads(message["function_call"]["arguments"])["query"]
query = json.loads(message.tool_calls[0].function.arguments)["query"]
# 使用 ask_database 函数执行查询,并获取结果
results = ask_database(conn, query)
else:
# 如果功能调用的名称不是 "ask_database",则返回错误信息
#results = f"Error: function {message['function_call']['name']} does not exist"
results = f"Error: function {message.tool_calls[0].function.name} does not exist"
return results # 返回结果
5)调用大模型API获取查询SQL
# 创建一个空的消息列表
messages = []
# 向消息列表中添加一个系统角色的消息,内容是 "Answer user questions by generating SQL queries against the Chinook Music Database."
messages.append({"role": "system", "content": "Answer user questions by generating SQL queries against the Chinook Music Database."})
# 向消息列表中添加一个用户角色的消息,内容是 "Hi, who are the top 5 artists by number of tracks?"
## 根据曲目数量排名前五的艺术家是谁?
messages.append({"role": "user", "content": "Hi, who are the top 5 artists by number of tracks?"})
# 使用 chat_completion_request 函数获取聊天响应
chat_response = chat_completion_request(messages, tools)
# 从聊天响应中获取助手的消息
assistant_message = chat_response.choices[0].message
#查看大模型,调用自定义函数生成的SQL
#print(assistant_message)
6)根据大模型返回的SQL, 执行查询操作获取结果
# 将助手的消息添加到消息列表中
assistant_message.content = str(assistant_message.tool_calls[0].function)
messages.append({"role": assistant_message.role, "content": assistant_message.content})
# 如果助手的消息中有功能调用
if assistant_message.tool_calls:
# 使用 execute_function_call 函数执行功能调用,并获取结果
results = execute_function_call(assistant_message)
#print(results)
# 将功能的结果作为一个功能角色的消息添加到消息列表中
messages.append({"role": "function", "tool_call_id": assistant_message.tool_calls[0].id, "name": assistant_message.tool_calls[0].function.name, "content": results})
# 使用 pretty_print_conversation 函数打印对话
pretty_print_conversation(messages)
总结
Function函数为OpenAI大模型提供了强大的扩展能力,使其能够在更广泛的应用场景中发挥作用。通过Function函数,大模型可以动态地获取和处理信息,从而为用户提供更加丰富和个性化的服务。希望这篇文章能帮助你更好地理解和使用Function函数,发挥大模型的全部潜力。