文章目录
一、Plugins、Actions 扩展
1、GPT 大模型缺陷 - 引入 Plugins、Actions 扩展
GPT 大模型 有如下三种缺陷 :
- 非全知全能 : 用于训练的都是 公开知识文本 , GPT 不知道 内部 或 保密 知识信息 ;
- 时效性差 : 大模型训练需要 半年 以上的时间 , 使用的都是半年以前的知识 ;
- 没有真逻辑 : 基于概率生成文本 , 无法处理复杂的逻辑问题 ;
为了解决上述三种缺陷 , OpenAI 在 GPT 大模型中引入了 Plugins 和 Actions 两种 扩展机制 , 用于增强模型的功能 , 使 GPT 大模型 能够处理 更复杂 和 特定的 任务 ;
2、Plugins 插件
ChatGPT 的 Plugins 插件 可 用于扩展 ChatGPT 功能 , 允许 大模型 与 外部系统 进行交互 ; 可实现如下功能 :
- 连接 数据库 : 访问公司数据库 , 获取数据 , 检索内部知识库或个人笔记 ;
- 调用 外部 API : 实现 预订航班 , 订票 等功能 ;
- 调用 其他软件服务 : 获取 股票价格 , 天气预报 , 最新新闻 等实时信息 ;
ChatGPT 的 Plugins 插件 功能 仅对 付费会员开放 , 只支持 GPT4 以上的模型 在 设置中 开启插件功能 , 之后才能在 聊天过程中 使用 Plugins 插件 ;
3、Plugins 插件开发流程
ChatGPT 的 插件 开发 流程如下 :
- 开发环境搭建 : 申请 OpenAI 的开发者账号 , 获取 API 访问权限 , 配置 Python 或者 Node.js 开发环境 ;
- 开发插件 : 定义 插件的 功能和接口 , 编写代码实现相应的插件逻辑 , 并在本地测试环境运行插件确保能返回正确结果 ;
- 发布插件 : 将开发好的插件代码提交的 OpenAI 后台 , 按照流程发布审核 , 通过审核后用户即可在 ChatGPT 控制面板中 搜索、安装、使用 该插件 ;
4、Plugins 插件弊端 - Actions 引入
Plugins 插件 在 产品设计 层面 不完善 , 使用 Plugins 插件 需要靠用户 手工选择使用 哪三个 Plugin 插件 , 并不能 自动识别 并 自动调用 对应的插件 , 因此 Plugins 插件 功能 在 ChatGPT 中没有推广开 ;
基于上述问题 , OpenAI 将 Plugins 升级为了 Actions , 内置到了 GPTs 大模型中 , 解决了上述问题 ;
5、Actions 简介
Actions 是 ChatGPT 内置的一种特定扩展功能 , 通常是为了执行简单、快速的任务 ;
Actions 由 ChatGPT 平台的开发团队开发 , 外部开发者无法开发 Actions , Actions 开发完成后由 ChatGPT 平台直接支持 , 不需要额外安装 , 可以保证执行效率 和 安全性 ;
与 Actions 对比 , Plugins 需要额外安装 , 并且只能选 3 个 ;
二、ChatGPT 的平替 - Coze、Dify
ChatGPT 经常封号 , 账号申请很麻烦 , 注册各种给添堵 , 即使是付费用户也会被封 , 这里推荐两个平替 ;
字节跳动 coze : https://www.coze.com/ , 可以直接使用 +86 的中国手机号注册使用 , 这个需要挂上梯子才能用 , 对中国用户比较友好 ;
免费 ;
只提供了 Web 界面访问 , 不提供 API 访问 ;
Dify : https://dify.ai/zh , 这是开源的生成式 AI 平台 , 可以在本地局域网内部部署 ;
- GitHub : https://github.com/langgenius/dify
提供了 Web 界面访问 和 API 访问 两种方式 ;
收费的 , 费用不便宜 ;
三、函数调用 Function Calling 引入
ChatGPT 引入 Plugins、Actions 扩展 , 这些都是针对通用需求开发的 , 并不能针对某个公司的某项需求进行功能的适配 , 开发 , 调优 , 集成到公司的某项业务中 , 也不是很方便 ;
因此 OpenAI 提供了 函数调用 Function Calling 技术 , 用户可以将 自己的业务系统 与 ChatGPT 大模型进行关联使用 ;
函数调用 Function Calling 官方文档 : https://platform.openai.com/docs/guides/function-calling
函数调用 流程 :
① 开发者 开发的 应用程序 通过 API 调用 OpenAI ,
② 开发者 需要将
- Prompt 提示词
- Function 函数定义
传给 OpenAI 大模型 ;
③ OpenAI GPT 大模型 分析 提示词 , 然后分析出 " 函数参数 " , 将 函数调用的参数 返回给 应用软件 ;
④ 在 应用软件 中 调用函数 , 传入 大模型返回的 参数 ;
⑤ 应用软件 调用 函数 得到 结果 , 将结果传递给 GPT 大模型 ;
⑥ GPT 大模型 结合 提示词 和 应用软件 函数调用结果 , 使用 自然语言 返回最终生成结果 ;
四、函数调用开发流程
1、调用 OpenAI 的接口
① 开发者 开发的 应用程序 通过 API 调用 OpenAI ; 在应用软件中 , 正常调用 OpenAI 软件包的函数 API 即可 ;
2、函数定义
② 开发者 需要将
- Prompt 提示词
- Function 函数定义
传给 OpenAI 大模型 ;
提示词 就是 普通的文本 , 这里着重分析下 函数定义 ;
函数定义 , 需要在 client.chat.completions.create 函数中的 tools 参数中传入 , 此处可以传入多个 json 格式的函数定义 ;
下面开始分析 函数调用 中 函数定义 的 json 描述字段 :
"type": "function"
表示这是一个 函数描述 ;description: "加法函数,可用于计算若干个数字之和"
这是 对 函数功能 的描述 ;parameters
字段描述 函数的参数信息 ;type: "object"
表示 函数参数是对象 ;properties
字段 描述对象的属性 ;numbers
表示 一个数组 , 包含了数字类型的元素 , 表示函数接受一个数字数组作为参数 ;
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0.5,
# 使用 json 描述 函数调用 的 函数信息 , 包括 函数名 函数描述 函数参数信息 等
# 可以定义多个 函数调用 , 具体调用哪个函数 , 由大模型决定
# 大模型根据 函数的描述信息 , 决定调用哪个函数
tools=[{
"type": "function",
"function": {
"name": "sum",
"description": "加法函数,可用于计算若干个数字之和",
"parameters": {
"type": "object",
"properties": {
"numbers": {
"type": "array",
"items": {
"type": "number"
}
}
}
}
}
}],
)
3、大模型回调
③ OpenAI GPT 大模型 分析 提示词 , 然后 分析出 " 函数参数 " , 将 函数调用的参数 返回给 应用软件 ;
大模型 收到 提示词 和 函数描述后 , 跟自动判定是否需要 调用 本地提供的 函数调用 ,
如果需要 , 则大模型会返回如下信息 ,
ChatCompletionMessage(content='', role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_LTy6rJlBVFLxAW3OAx3dIJSl', function=Function(arguments='{"numbers":[1,2,3,4,5]}', name='sum'), type='function')])
ChatCompletionMessage
是消息的主要对象 , 用于描述聊天模型生成的一条完成消息 ;content=''
是 消息的内容 , 空的 , 这是由于 GPT 大模型判断出 需要 进行函数调用 , 本次返回信息专门返回函数调用的一系列参数 ;role='assistant'
表示 消息的角色 , 消息是由 assistant 生成的 ;function_call=None
描述一个 函数调用的对象 , 但在这个例子中是空的 ;tool_calls
:工具调用 , 此处放的是 函数调用的 参数信息 ;ChatCompletionMessageToolCall
是 工具调用的描述对象 , 包含了多个工具调用信息 ;
核心就是
tool_calls=[ChatCompletionMessageToolCall(id='call_LTy6rJlBVFLxAW3OAx3dIJSl', function=Function(arguments='{"numbers":[1,2,3,4,5]}', name='sum'), type='function')]
id='call_LTy6rJlBVFLxAW3OAx3dIJSl'
: 是 工具调用的唯一标识符 , 可能用于跟踪和识别特定的调用。function=Function(arguments='{"numbers":[1,2,3,4,5]}', name='sum')
参数描述了一个 函数调用 ;arguments='{"numbers":[1,2,3,4,5]}'
表示 函数调用的参数 ;name='sum'
表示 调用的函数名是 sum ;
type='function'
表示 这个工具调用是一个函数类型的调用;
4、本地代码逻辑
④ 在 应用软件 中 调用函数 , 传入 大模型返回的 参数 ;
如果发现 GPT 大模型返回的 tool_calls 字段 , 就说明需要进行函数调用 , 收到对应的 函数调用 请求后 , 开始进行逻辑计算 ;
将计算结果 封装到 json 中 , 如下代码所示 :
# 将本地的 函数调用结果 封装为指定格式的 json 串
messages.append(
{
"tool_call_id": tool_call.id, # 用于标识函数调用的 ID
"role": "tool",
"name": "sum",
"content": str(result) # 数值result 必须转成字符串
}
)
"tool_call_id": tool_call.id
用于标识函数调用的 ID , 在前面的 函数调用 参数 json 中可以找到 , 是 call_LTy6rJlBVFLxAW3OAx3dIJSl 值 ;"role": "tool"
指示 条目的角色是工具 tool , 与前面提到的role='assistant'
相对应 ;"name": "sum"
设置函数的名称 , 这里是 sum 函数调用结果 ;"content": str(result)
是 函数调用的结果 , 转为字符串 ;
5、第二次大模型调用
⑤ 应用软件 调用 函数 得到 结果 , 将结果传递给 GPT 大模型 ;
⑥ GPT 大模型 结合 提示词 和 应用软件 函数调用结果 , 使用 自然语言 返回最终生成结果 ;
五、函数调用代码示例
代码示例 :
import json
from openai import OpenAI
client = OpenAI(
api_key="sk-6o3KJuuocEXpb1Ug39D0A4913a844fCaBa892eDe9814Df8a",
base_url="https://api.xiaoai.plus/v1",
)
def get_completion(messages, model="gpt-3.5-turbo-1106"):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0.5,
# 使用 json 描述 函数调用 的 函数信息 , 包括 函数名 函数描述 函数参数信息 等
# 可以定义多个 函数调用 , 具体调用哪个函数 , 由大模型决定
# 大模型根据 函数的描述信息 , 决定调用哪个函数
tools=[{
"type": "function",
"function": {
"name": "sum",
"description": "加法函数,可用于计算若干个数字之和",
"parameters": {
"type": "object",
"properties": {
"numbers": {
"type": "array",
"items": {
"type": "number"
}
}
}
}
}
}],
)
return response.choices[0].message
# 提示词
prompt = "计算 1+2+3+4+5 的结果"
# 将提示词封装到 message 中
messages = [
{"role": "system", "content": "计算数学式子"},
{"role": "user", "content": prompt}
]
# 第一次调用 : 将 提示词 和 函数定义 传给 GPT 大模型
response = get_completion(messages)
# 解决 OpenAI 400 bug
if (response.content is None):
response.content = ""
# 把大模型的回复加入到对话历史中
messages.append(response)
print("第一次 将 提示词 和 函数定义 传给 GPT 大模型 的 回复 :")
print(response)
# 拿到第一次回复后 , 查看是否需要执行 函数调用
# 如果 tool_calls 不为空 , 则需要进行函数调用
# 下面就是 tool_calls 字段
# tool_calls=[ChatCompletionMessageToolCall(id='call_Qr0uXYu6C6CZ2JhTWWnPNVl9', function=Function(arguments='{"numbers":[1,2,3,4,5,6,7,8,9,10]}', name='sum'), type='function')]
if (response.tool_calls is not None):
# 是否要调用 sum
tool_call = response.tool_calls[0]
# 判定 大模型 要调用的函数的 函数名称 , 就是 name 字段
# 根据不同的函数名称 , 执行不同的代码逻辑
if (tool_call.function.name == "sum"):
# 获取函数的一系列参数
args = json.loads(tool_call.function.arguments)
# 调用 Python 内置函数 , 进行加法运算
result = sum(args["numbers"])
print("\nsum 函数调用 返回结果 : ")
print(result)
# 将本地的 函数调用结果 封装为指定格式的 json 串
messages.append(
{
"tool_call_id": tool_call.id, # 用于标识函数调用的 ID
"role": "tool",
"name": "sum",
"content": str(result) # 数值result 必须转成字符串
}
)
# 再次调用大模型
print("\n第二次将 提示词 函数定义 和 函数调用结果 传给 GPT 大模型 的 回复 : ")
print(get_completion(messages).content)
执行结果 :
Y:\002_WorkSpace\PycharmProjects\pythonProject\venv\Scripts\python.exe Y:/002_WorkSpace/PycharmProjects/HelloPython/FunctionCalling.py
第一次 将 提示词 和 函数定义 传给 GPT 大模型 的 回复 :
ChatCompletionMessage(content='', role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_LTy6rJlBVFLxAW3OAx3dIJSl', function=Function(arguments='{"numbers":[1,2,3,4,5]}', name='sum'), type='function')])
sum 函数调用 返回结果 :
15
第二次将 提示词 函数定义 和 函数调用结果 传给 GPT 大模型 的 回复 :
1 + 2 + 3 + 4 + 5 = 15.
Process finished with exit code 0