三、OpenAI之Function Calling实战

黑8决心将对 OpenAI API 的学习应用到更多实际场景中,以展示新时代技术的巨大潜力。在接下来的日子里,他不断探索和尝试,将 API 中的各种功能融入到不同的生活场景中,取得了一系列令人瞩目的成果。

首先,他将 OpenAI API 中的文本生成功能应用到了日常写作中。通过简单的 function calling,他可以请求 API 生成文章大纲、段落或完整的文章。例如,在准备一个关于项目的解决方案时,他使用 API 生成了一份生动而具有说服力的文章,引起了人们的关注和共鸣。

接着,他将 API 中的图像识别功能应用到了家庭生活中。通过 function calling,他可以上传家里的照片并请求 API 分析其中的内容。比如,当他的女儿画了一幅画作时,他使用 API 对画作进行分析,并得到了有关主题、色彩和风格的反馈,从而为女儿提供更专业的指导和建议。

此外,他还将 API 中的语言理解功能应用到了教育领域。通过 function calling,他可以向 API 提出问题并获得详细的解答,帮助孩子们更好地理解学习内容。比如,当他的儿子遇到数学难题时,他可以使用 API 进行智能辅导,为儿子提供个性化的学习支持。

随着时间的推移,黑8不断完善和拓展自己的应用案例,将 OpenAI API 的功能发挥到了极致。他的努力和成就得到了革委会的认可和赞赏,成为了新时代技术应用的典范。通过 function calling,他不仅改变了自己的生活方式,还为身边的人们带来了更多便利和惊喜,展示了科技的力量和魅力。

1. 接口(Interface)

两种常用接口:

  • 人机交互接口,User Interface(UI)
  • 应用程序编程接口,Application Programming Interface(API)

2. 接口的进化(Interface evolution)

UI进化的趋势:越来越适应人的习惯,越来越自然

  • 命令行:Command Line Interface(CLI) Dos,Unix/Linux shell,Windows Power Shell
  • 图形界面:Graphical User Interface(GUI)Windows,MacOS,IOS,Android
  • 语言界面:Conversational User Interface(CUL) Natural Language User Interface(NLUI)
  • 脑机接口:Brain Computer Interface(BCI)
    在这里插入图片描述
    API:
  • 从本地到远程,从同步到异步,媒介发生很多变化,但本质一直没有变:程序员的约定
  • 现在开始进化为自然语言接口,Natural Language Interface(NLI)

3. 自然语言接口(Natural Language Interface)

最自然的接口就是自然语言接口:
以前因为计算机处理不好自然语言,所以才有了那么多编程语言、接口、协议、界面风格。而且每一次进化,都是为了“更自然”,现在自然的终极时刻到来,大模型赋予计算机以“人类灵魂”,能和我们进行友好的沟通。

为什么要大模型连接外部世界?
大模型有两大缺陷:

  1. 并非知晓一切
    • 训练数据不可能什么都有。垂直、非公开数据欠缺
    • 不知道最新信息。大模型训练周期较长,且更新一次耗资巨大,还有越训练越傻的风险。中间会有延时、空档期。GPT-3.5 ,GPT-4 发布日期分别为:2022.1 和 2023.4
  2. 没有“真逻辑”
    表现出来的逻辑、推理,是文本的统计概率,而不是真正的逻辑

所以:大模型需要连接真实世界,对接真逻辑系统。

比如计算加法:

  • 把100以内的所有加法算式都训练给大模型,它就能回答100以内的加法
  • 如果超出100的加法,就不一定能算对了
  • 大模型并不懂加法,只是记住了100以内的加法算式的统计概率
  • 它是用字面意义做加法

4. OpenAI-Actions 接外部世界

第一次尝试用Plugins连接真实世界,产品不成功,原因:

  • 不在“场景”中,不能提供端到端的服务
  • 缺少“强Agetn”调度,只能手工选择3个plugin,使用成本太高
    第二次尝试升级为Actions,内置到GPTs中,解决了落地场景问题
    Actions工作流程:
    在这里插入图片描述

4.1 开发一个Action步骤

  • 创建一个应用的API接口
  • 以OpenAPI YAML或JSON格式记录API
  • 在ChatGPT UI中将schema传给GPT
    示例:
openapi: 3.0.1
info:title: TODO Actiondescription: An action that allows the user to create and manage a TODO list using a GPT.version: 'v1'
servers:- url: https://example.com
paths:/todos:get:operationId: getTodossummary: Get the list of todosresponses:"200":description: OKcontent:application/json:schema:$ref: '#/components/schemas/getTodosResponse'
components:schemas:getTodosResponse:type: objectproperties:todos:type: arrayitems:type: stringdescription: The list of todos.

4.2 Function Calling扩展

OpenAI GPTs

  1. 无需编程,就能定制个性对话机器人的平台
  2. 可以放入自己的知识库,实现 RAG(后面会讲)
  3. 可以通过 actions 对接专有数据和功能
  4. 内置 DALL·E 3 文生图和 Code Interpreter 能力
  5. 只有 ChatGPT Plus 会员可以使用

字节跳动 Coze

  1. 免费使用 GPT-4 等 OpenAI 的服务
  2. 只有英文界面,但其实对中文更友好
  3. Prompt 优化功能更简单直接

Dify

  1. 开源,中国公司开发
  2. 功能最丰富
  3. 可以本地部署,支持非常多的大模型
  4. 有 GUI,也有 API

有这类无需开发的工具,为什么还要学大模型开发技术呢?

  • 它们都无法针对业务需求做极致调优
  • 它们和其它业务系统的集成不是特别方便

Function Calling 技术可以把自己开发的大模型应用和其它业务系统连接。

4.3 Function Calling 的机制

在这里插入图片描述
注意: 接口里叫 tools,是从 functions 改的

4.3 Function Calling示例

调用本地函数

# 初始化
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
import os
import json_ = load_dotenv(find_dotenv())client = OpenAI()# 定义一个函数
def get_completion(messages, model="gpt-3.5-turbo"):response = client.chat.completions.create(model=model,messages=messages,temperature=0.7,  # 模型输出的随机性,0 表示随机性最小tools=[{  # 用 JSON 描述函数。可以定义多个。由大模型决定调用谁。也可能都不调用"type": "function","function": {"name": "sum","description": "加法器,计算一组数的和","parameters": {"type": "object","properties": {"numbers": {"type": "array","items": {"type": "number"}}}}}}],)return response.choices[0].message
from math import *prompt = "1+2+3...+99+100"messages = [{"role": "system", "content": "你是一个超级计算器"},{"role": "user", "content": prompt}
]
response = get_completion(messages)# 把大模型的回复加入到对话历史中
print(response)
messages.append(response)print('=====GPT回复=====', response)# 如果返回的是函数调用结果,则打印出来
if (response.tool_calls is not None):# 是否要调用 sumtool_call = response.tool_calls[0]print("=====函数调用=====", tool_call)if (tool_call.function.name == "sum"):# 调用 sumargs = json.loads(tool_call.function.arguments)result = sum(args["numbers"])# 打印函数调用结果print("=====函数返回=====", result)# 把函数调用结果加入到对话历史中messages.append({"tool_call_id": tool_call.id,  # 用于标识函数调用的 ID"role": "tool","name": "sum","content": str(result)  # 数值 result 必须转成字符串})# 再次调用大模型print("=====最终回复=====")print(get_completion(messages).content)

在这里插入图片描述
逻辑:

  • 定义调用OpenAI gpt-3.5-turbo模型的函数,增加tools参数,tools参数为JSON数组,JSON内容:type:function和function的JSON对象,function:描述name、description、parameters等
  • 定义提示词,第一次将提示词传给大模型gpt-3.5-turbo,模型根据提示词判断是否调用函数并做出响应
  • 如果需要调用函数,返回数据将含有重要参数:tool_calls,包含 ID和function描述,function中包含:arguments(参数)、name(参数名称)、type(类型function)
  • 将上步返回的结果:ID和调用参数的结果(result),追加到历史会话中,作为新的提示词。
  • 第二次传给大模型gpt-3.5-turbo
  • 大模型gpt-3.5-turbo根据历史提示词和调用函数的结果,给出新响应
注意:
  1. Function Calling 中的函数与参数的描述也是一种 Prompt
  2. 这种 Prompt 也需要调优,否则会影响函数的调用、参数的准确性,甚至让 GPT 产生幻觉

调用多个函数

定义返回奇、偶数函数,模型本身也具有区分能力,这里为了演示多函数调用,所以定义了两个具体函数

# 定义一个函数
def get_completion(messages, model="gpt-3.5-turbo"):response = client.chat.completions.create(model=model,messages=messages,temperature=0.7,  # 模型输出的随机性,0 表示随机性最小tools=[{  # 用 JSON 描述函数。可以定义多个。由大模型决定调用谁。也可能都不调用"type": "function","function": {"name": "getEvenNumber","description": "获得所有的偶数","parameters": {"type": "object","properties": {"numbers": {"type": "array","items": {"type": "number"}}}}}}, {"type": "function","function": {"name": "getOddNumber","description": "获得所有的奇数","parameters": {"type": "object","properties": {"numbers": {"type": "array","items": {"type": "number"}}}}}}],)return response.choices[0].message
# 返回所有偶数
def getEvenNumber(nums):if 0 == len(nums):return []new_nums = []for n in nums:if n % 2 == 0:new_nums.append(n)return new_nums# 返回所有奇数
def getOddNumber(nums):if 0 == len(nums):return []new_nums = []for n in nums:if n % 2 != 0:new_nums.append(n)return new_nums            
prompt = "1,2,3,4,5,6,7,8,9,10"messages = [{"role": "system", "content": "你是一个超级数学家,返回所有偶数"},{"role": "user", "content": prompt}
]
response = get_completion(messages)# 把大模型的回复加入到对话历史中
messages.append(response)print('=====GPT回复=====')
print(response)# 如果返回的是函数调用结果,则打印出来
while response.tool_calls is not None:for tool_call in response.tool_calls:# 是否要调用 函数args = json.loads(tool_call.function.arguments)result = Nonefunction_name = ""if tool_call.function.name == "getEvenNumber":# 调用 getEvenNumber        result = getEvenNumber(args["numbers"])function_name = "getEvenNumber"# 打印函数调用结果print("=====函数返回=====", result)elif tool_call.function.name == "getOddNumber":# 调用 getOddNumberresult = getOddNumber(args["numbers"])function_name = "getOddNumber"print("=====函数返回=====", result)# 把函数调用结果加入到对话历史中messages.append({"tool_call_id": tool_call.id,  # 用于标识函数调用的 ID"role": "tool","name": function_name,"content": str(result)  # 数值 result 必须转成字符串})response = get_completion(messages)messages.append(response)  # 把大模型的回复加入到对话中print("=====最终回复=====")
print(response.content)

返回偶数结果:
在这里插入图片描述

返回奇数结果:
在这里插入图片描述

Function Calling 获取JSON

def get_completion(messages, model="gpt-3.5-turbo"):response = client.chat.completions.create(model=model,messages=messages,temperature=0,  # 模型输出的随机性,0 表示随机性最小tools=[{"type": "function","function": {"name": "splitEvenAndOdd","description": "区分奇、偶数","parameters": {"type": "object","properties": {"even": {"type": "string","description": "奇数"},"odd": {"type": "string","description": "偶数"}}}}}],)return response.choices[0].messageprompt = "1,3,2,5,4,6,7,9,8,10"
messages = [{"role": "system", "content": "你是一个数学老师"},{"role": "user", "content": prompt}
]
response = get_completion(messages)
print("====GPT回复====")
print(response)
args = json.loads(response.tool_calls[0].function.arguments)
print("====函数参数====")
print(args)

在这里插入图片描述

查询数据库

从SQLite数据库获得数据
在这里插入图片描述

def get_table_names(conn):"""返回所有表名."""table_names = []tables = conn.execute("SELECT name FROM sqlite_master WHERE type='table';")for table in tables.fetchall():table_names.append(table[0])return table_namesdef get_column_names(conn, table_name):"""返回所有列名."""column_names = []columns = conn.execute(f"PRAGMA table_info('{table_name}');").fetchall()for col in columns:column_names.append(col[1])return column_namesdef 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_dictsdatabase_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 # 构造表名和列名字符数组]
)

和之前一样,我们为函数调用定义一个函数规范,让模型API生成参数。请注意:我们要插入数据库的模型到函数规范中。让模型知道这一点很重要:

tools = [{"type": "function","function": {"name": "ask_database","description": "使用这个函数回答用户关于音乐的问题. 输入为格式化好的SQL语句.","parameters": {"type": "object","properties": {"query": {"type": "string","description": f"""通过SQL查询提取用户问题的答案。SQL语句应该使用这个数据库模式:{database_schema_string}查询结果应该以纯文本形式返回,而不是JSON格式。""",}},"required": ["query"],},}}
]

执行SQL查询

messages = []
messages.append({"role": "system", "content": "通过chinook音乐数据库生成SQL查询来回答用户问题"})
messages.append({"role": "user", "content": "谁是按曲目数量排名前五的艺术家?"})
# 传入prompt及tools
chat_response = chat_completion_request(messages, tools)
assistant_message = chat_response.choices[0].message
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:results = execute_function_call(assistant_message)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(messages)

在这里插入图片描述

messages.append({"role": "user", "content": "歌曲最多的专辑叫什么名字?"})
chat_response = chat_completion_request(messages, tools)
assistant_message = chat_response.choices[0].message
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:results = execute_function_call(assistant_message)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(messages)

在这里插入图片描述

4.5. Function Calling 注意事项

  1. gpt-3.5-turbogpt-3.5-turbo-1106 的别名
  2. gpt-4gpt-4-1106-preview 是两个不同的模型
  3. OpenAI 针对 Function Calling 做了 fine-tuning,以尽可能保证函数调用参数的正确
  4. 函数声明是消耗 token 的。要在功能覆盖、节约上下文tokens之间找到平衡点
  5. Function Calling 不仅可以调用读函数,也能调用写函数。但官方强烈建议,在写之前,一定要有人做确认

5. NLP 算法工程师视角

  1. 模型砍大面,规则修细节
  2. 一个模型搞不定的问题,拆成多个解决
  3. 评估算法的准确率(所以要先有测试集,否则别问「能不能做」)
  4. 评估 bad case 的影响面
  5. 算法的结果永远不是100%正确的,建立在这个假设基础上推敲产品的可行性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/701608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Chrome插件(二)—Hello World!

本小节将指导你从头到尾创建一个基本的Chrome插件,你可以认为是chrome插件开发的“hello world”! 以下详细描述了各个步骤: 第一步:设置开发环境 确保你拥有以下工具: 文本编辑器:如Visual Studio Cod…

Django学习记录04——靓号管理整合

1.靓号表 1.1 表结构 1.2 靓号表的构造 class PrettyNum(models.Model): 靓号表 mobile models.CharField(verbose_name"手机号", max_length11)# default 默认值# null true,blank true 允许为空price models.IntegerField(verbose_name"价…

EasyRecovery易恢复软件数据恢复方面表现优势有哪些?

EasyRecovery易恢复软件在数据恢复方面表现优异。它支持多种设备的数据恢复,如硬盘、光盘、U盘/移动硬盘、数码相机等,并且能够恢复包括文档、图片、视频、音频等各种类型的文件。无论是误删除、格式化、分区丢失还是硬件故障导致的数据丢失,…

目标跟踪之KCF详解

High-Speed Tracking with Kernelized Correlation Filters 使用内核化相关滤波器进行高速跟踪 大多数现代跟踪器的核心组件是判别分类器,其任务是区分目标和周围环境。为了应对自然图像变化,此分类器通常使用平移和缩放的样本补丁进行训练。此类样本集…

目标检测新SOTA:YOLOv9 问世,新架构让传统卷积重焕生机

在目标检测领域,YOLOv9 实现了一代更比一代强,利用新架构和方法让传统卷积在参数利用率方面胜过了深度卷积。 继 2023 年 1 月 YOLOv8 正式发布一年多以后,YOLOv9 终于来了! 我们知道,YOLO 是一种基于图像全局信息进行…

Linux信号详解

文章目录 一、Linux信号1. 信号的概念2. 信号的定义3. 系统定义的信号 二、信号产生的方式1.通过键盘产生2. 通过系统调用3. 软件条件4. 硬件异常 三、信号处理函数1. OS发送信号的实质2. 指令发送信号3. signal()4. sigaction() 四、信号屏蔽机制1. 信号处理方式2.信号集操作函…

更改QTabWidget的选项卡的位置

选项卡位置函数: QTabWidget::setTabPosition(QTabWidget::North); //默认为上面 上北下南 参数: QTabWidget::North //上面 QTabWidget::South); //下面 QTabWidget::West //左侧 QTabWidget::East)//右侧 选项卡外观函数: QTabWidget::setT…

nodejs+vue+ElementUi废品废弃资源回收系统

系统主要是以后台管理员管理为主。管理员需要先登录系统然后才可以使用本系统,管理员可以对系统用户管理、用户信息管理、回收站点管理、站点分类管理、站点分类管理、留言板管理、系统管理进行添加、查询、修改、删除,以保障废弃资源回收系统系统的正常…

Qt_纯虚函数的信号和槽

简介 在C中,纯虚函数是一个在基类中声明但没有实现的虚函数。纯虚函数的声明以 “ 0” 结尾。纯虚函数的目的是为了提供一个接口,但是不提供实现。派生类必须实现纯虚函数,否则它也会成为一个抽象类。纯虚函数可以在基类中定义,也…

python中的类与对象(1)

目录 一. 引子:模板 二. 面向过程与面向对象 (1)面向过程编程 (2)面向对象编程 三. 对象与类 (1)对象 (2)类 四. 面向对象程序设计的特点:封装&#…

【C语言】linux内核ipoib模块 - ipoib_ib_handle_rx_wc

一、中文注释 // 定义一个处理InfiniBand接收完成工作请求的函数 static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) {// 通过网络设备获取私有数据结构struct ipoib_dev_priv *priv ipoib_priv(dev);// 获取工作请求ID,并屏蔽掉接收…

探索未来:Web3如何改变我们的生活方式

在数字化的时代,技术的不断发展和创新已经成为了我们生活的常态。而在这个不断变革的过程中,区块链技术作为一种颠覆性的技术,正逐渐成为人们关注的焦点。作为区块链技术的下一代,Web3正日益崭露头角,成为了未来的发展…

橘子学es原理01之准备工作

es本身是具备很好的使用特性的,我指的是他的部署方面的,至于后期的使用和运维那还是很一眼难尽的。 我们从这一篇开始就着重于es的一些原理性的的一些探讨,当然我们也会有一些操作性的,业务性的会分为多个栏目来写。比如前面我写的…

Flutter开发进阶之Package

Flutter开发进阶之Package 通常我们在Flutter开发中需要将部分功能与整体项目隔离,一般有两种方案Plugin和Package,Application是作为主体项目,Module是作为原生项目接入Flutter模块。 当独立模块不需要与原生项目通讯只需要Plugin就可以&a…

【广度优先搜索】【网格】【割点】1263. 推箱子

作者推荐 视频算法专题 涉及知识点 广度优先搜索 网格 割点 并集查找 LeetCode:1263. 推箱子 「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。 游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或…

利用LaTex批量将eps转pdf、png转eps、eps转png、eps转svg、pdf转eps

1、eps转pdf 直接使用epstopdf命令(texlive、mitex自带)。 在cmd中进入到eps矢量图片的目录,使用下面的命令: for %f in (*.eps) do epstopdf "%f" 下面是plt保存eps代码: import matplotlib.pyplot as…

计算机网络面经-TCP的拥塞控制

写在前边 前边我们分享了网络分层协议、TCP 三次握手、TCP 四次分手。今天我们继续深入分享一下 TCP 中的拥塞控制。 对于 TCP 的拥塞控制,里边设计到很多细节,平平无奇的羊希望通过这一节能够将这部分内容串通起来,能够让你更深刻的记忆这部分内容。 思维导图 1、什么…

封装(encapsulation)

封装[encapsulation] 封装介绍封装好处封装的实现步骤(三步)入门案例封装与构造器 封装介绍 封装就是把抽象的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],…

vue项目的前端工程化思路webpack(持续更新中)

写在前面:现在的前端网页功能丰富,特别是SPA(single page web application 单页应用)技术流行后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决Scss,Less……新增样式的扩展写法的编译工…

DC与DCT DCG的区别

先进工艺不再wire load model进行静态时序分析,否则综合结果与后端物理电路差距很大,因此DC综合工具也进行了多次迭代,DC工具有两种模式,包括wire load mode和Topographical Mode,也就是对应的DC Expert和DC Ultra。 …