LangChain的函数,工具和代理(一):OpenAI的函数调用

news2024/11/18 9:26:47

一、什么是函数调用功能

几个月前OpenAI官方发布了其API的函数调用功能(Function calling), 在 API 调用中,您可以描述函数,并让模型智能地选择输出包含调用一个或多个函数的参数的 JSON 对象。API函数“ChatCompletion” 虽然不会实际调用该函数;但是模型会生成这些基于函数参数的JSON对象,您可以使用它来调用代码中的实际函数。

也就是说当用户和ChatGPT对话的过程中需要调用某些外部的函数或者API时,我们可以让ChatGPT生成调用外部函数所需的参数,然后我们再使用这些参数再去实际的调用外部函数,目前OpenAl 对 gpt-3.5-turbo-0613 和 gpt-4-0613 模型进行了微调,使它们具备了以下函数调用功能:

1. 接受额外的参数,用户可以通过这些参数传入函数的描述。
2. 如果相关,则返回要使用的函数的名称,以及带有适当输入参数的 JSON 对象。

二,如何实现OpenAI的函数调用功能

在实现OpenAI的函数调用功能之前,我们先定义一个外部函数,当用户和ChatGPT对话时,ChatGPT会自动判断是否需要调用外部函数,当需要调用外部函数时ChatGPT会返回调用函数的json对象给用户:

import json

# 查询天气的模拟函数示例
# 在生产中,这可能是您的后端 API 或外部 API
def get_current_weather(location, unit="fahrenheit"):
    """Get the current weather in a given location"""
    weather_info = {
        "location": location, #城市
        "temperature": "72", # 温度
        "unit": unit, #温度单位
        "forecast": ["sunny", "windy"], #天气情况
    }
    return json.dumps(weather_info)

这里我们定义一个外部函数get_current_weather,他用来查询特定城市的天气情况,并返回一个jons对象作为查询结果。接下来我们需要定义一个该函数的描述对象,该描述对象后面会作为参数传递给ChatGPT:

#函数描述对象
functions = [
    {
        "name": "get_current_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA",
                },
                "unit": {
                    "type": "string", 
                    "enum": ["celsius", "fahrenheit"]},
            },
            "required": ["location"],
        },
    }
]

下面我们来说明一下函数描述对象的主要成员:

  • name: 外部函数名称如get_current_weather
  • description:外部函数功能的描述
  • parameters:外部函数的参数集
  • parameters-type:外部函数的参数集的类型
  • properties:外部函数的具体参数集
  • location:具体的外部函数的参数
  • location-type:外部函数的参数的类型
  • location-description:外部函数的参数的描述
  • unit:具体的外部函数的参数
  • unit-type:外部函数的参数的类型
  • enum:外部函数的参数的枚举值
  • required:必填的参数

这里我们生成了一个外部函数的描述对象,该描述对象会告诉ChatGPT该外部函数的作用,以及我们需要在恰当的时候来调用该函数,至于什么时候才是“恰当的时候”这需要由ChatGPT根据用户对话的上下文来判断。接下来我们向ChatGPT询问一个关于天气的问题:

import openai
openai.api_key = "XXXXXXXXX"

messages = [
    {
        "role": "user",
        "content": "上海的天气怎么样?"
    }
]

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions
)

print(response)

这里我们向ChatGPT提出了关于天气的问题:“上海的天气怎么样?”, 从ChatGPT的返回结果中我们看到"function_call",这告诉我们接下来我们该调用外部函数了,同时ChatGPT还返回了调用外部函数的参数location和unit,以及所需调用的外部函数名:get_current_weather,有意思的是这里返回的unit为“celsius”即摄氏度而非美国使用的"fahrenheit(华氏度)", 这似乎说明ChatGPT知道中国使用摄氏度作为温度的单位,下面我们询问一下美国城市的天气:

messages = [
    {
        "role": "user",
        "content": "What's the weather like in Boston?" #波士顿 的天气怎么样?
    }
]

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions
)

print(response)

这里我们用英语询问了美国城市波士顿的天气情况,从ChatGPT的返回结果中我们看到arguments中只包含了location,而没有包含unit, 而在我们的外部函数get_current_weather中unit为非必填参数,它有一个默认值为:unit="fahrenheit",因此在实际调用外部函数时我们只需将chatgpt返回结果中的arguments中取出对应的参数然后传递给外部函数即可,接下来我们从ChatGPT的返回结果中获取参数来实际调用外部函数get_current_weather:

args = json.loads(response_message["function_call"]["arguments"])
result=get_current_weather(args)
print(result)

 接下来我们来测试一下ChatGPT能否准确识别何时该调用外部函数,下面我们会对ChatGPT发送一个简单的问候语:hi,  当Chatgpt收到该问候语时不应该触发函数调用功能:

messages = [
    {
        "role": "user",
        "content": "hi!",
    }
]

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions,
)

print(response)

从上面的chatgpt的返回结果中我们看到不存在先前的“function_call"内容即没有生成外部函数的调用参数,这说明此时我们不需要调用外部函数。

三、设置OPAI API的默认参数

openai的API函数ChatCompletion.create中存在一个function_call的参数,该参数的默认值为“auto”即让模型自己来选择是否需要调用外部函数:

messages = [
    {
        "role": "user",
        "content": "hi!",
    }
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions,
    function_call="auto",
)
print(response)

上面我们在openai.ChatCompletion.create的方法中加入了function_call="auto",意思是让模型根据上下文来确定是否调用外部函数,我们看到当我们向ChatGPT打招呼时,如输入“hi”时 ,chatgpt的返回结果中没有“function_call”的内容。这说明ChatGPT知道此时不应该调用外部函数。

messages = [
    {
        "role": "user",
        "content": "hi!",
    }
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions,
    function_call="none",#禁止调用外部函数
)
print(response)

上面当我们将function_cal设置为"none"时(即禁止chatGPT调用外部函数),chatGPT的返回结果中也不会出现“function_call”的内容。

messages = [
    {
        "role": "user",
        "content": "What's the weather in Boston?",
    }
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions,
    function_call="none", #禁止调用外部函数
)
print(response)

在上面的代码中我们向ChatGPT询问了波士顿的天气,但是我们设置了function_call="none",也就是说虽然我们询问了波士顿的天气情况,但我们却禁止chatgpt调用外部函数,从chatgpt的返回结果中我们看到仍然没有“function_cal”的相关内容。

下面我们设置chatgpt强制调用外部函数,看看会发生上面情况:

messages = [
    {
        "role": "user",
        "content": "hi!",
    }
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions,
    function_call={"name": "get_current_weather"},#强制调用外部函数
)
print(response)

在上面的代码中我们在 ChatCompletion.create中设置了function_call={"name": "get_current_weather"}意思是让chatgpt强制生成调用get_current_weather函数的参数,但是我们向chatgpt发送的用户消息却是:hi!, 这时会让chatgpt产生困惑,因为用户消息中没有有关询问天气的内容,但是却要强制chatgpt去生成外部函数的调用参数,所以在chatgpt的返回结果中function_call中的arguments中给出了一个随机的location:San Francisco,CA。

下面我们向chatgpt询问波士顿的天气,并且让chatgpt强制调用get_current_weather,看看会发生什么情况:

messages = [
    {
        "role": "user",
        "content": "What's the weather like in Boston!",
    }
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    functions=functions,
    function_call={"name": "get_current_weather"}, #强制调用外部函数
)
print(response)

从上面的chatgpt的返回结果中我们看到了“function_call”中的内容。这说明只要我们设置了chatgpt强制指定了外部调用函数时,它总会生成相应的函数参数。

四、外部函数的调用结果的应用

上面我们让chatgpt来判断是否应该调用外部函数,并且让chatgpt返回了调用外部函数的参数,接下来我们要做的是用chatgpt提供的参数去实际调用外部函数,并将外部函数的返回结果再喂给chatgpt,这样做的目的是让chatgpt来汇总所有的信息并产生最终对用户友好的返回信息。

#整合chatgpt的返回结果
messages.append(response["choices"][0]["message"])
#从chatgpt的返回结果中获取外部函数的调用参数
args = json.loads(response["choices"][0]["message"]['function_call']['arguments'])
#调用外部函数
observation = get_current_weather(args)

messages.append(
        {
            "role": "function",
            "name": "get_current_weather",
            "content": observation, #外部函数的返回结果
        }
)

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-0613",
    messages=messages,
)
print(response)

 这里我们看到ChatGPT最终返回了一个非常友好的回复,该回复是在外部函数调用结果的基础上经过整理后得到的。

关于token统计

我们知道chatgpt的API是通过token来收费的,这里我们在使用chatgpt的函数调用功能时我们创建了一个函数描述对象functions,因此functions也会作为上下文的一部分被统计token数,下面我们去掉ChatCompletion.create中的functions和function_call这两个参数看看最后chatgpt返回的总的token数是多少:

messages = [
    {
        "role": "user",
        "content": "What's the weather like in Boston!",
    }
]
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-1106",
    messages=messages
)
print(response)

从上面的返回结果中我们看到当我们去掉了ChatCompletion.create中的functions和function_call这两个参数时,总token数为48,而先前的总token数为99,这说明外部函数描述对象functions被统计了token数。

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

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

相关文章

redis之数据类型

(一)关系型数据库和非关系型数据库的区别 1、关系型数据库是一个机构化的数据库,列和行 (1)列:声明对象 (2)行:记录对象的属性 (3)表与表之间…

Python (十三) 输出

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一波电子书籍资料,包含《Effective Java中文版 第2版》《深入JAVA虚拟机》,《重构改善既有代码设计》,《MySQL高性能-第3版》&…

使用pytorch利用神经网络原理进行图片的训练(持续学习中....)

1.做这件事的目的 语言只是工具,使用python训练图片数据,最终会得到.pth的训练文件,java有使用这个文件进行图片识别的工具,顺便整合,我觉得Neo4J正确率太低了,草莓都能识别成为苹果,而且速度慢,不能持续识别视频帧 2.什么是神经网络?(其实就是数学的排列组合最终得到统计结果…

Vue项目 配置项设置

一、项目运行时浏览器自动打开 找到package.json文件 找到"sctipts"配置项 在"serve"配置项最后加上--open "scripts": {"serve": "vue-cli-service serve --open","build": "vue-cli-service build&quo…

2023年【四川省安全员A证】复审考试及四川省安全员A证考试试题

题库来源:安全生产模拟考试一点通公众号小程序 四川省安全员A证复审考试根据新四川省安全员A证考试大纲要求,安全生产模拟考试一点通将四川省安全员A证模拟考试试题进行汇编,组成一套四川省安全员A证全真模拟考试试题,学员可通过…

Nacos介绍与使用

Nacos介绍与使用 文章目录 Nacos介绍与使用一. 什么是Nacos1 Nacos功能1.1 配置中心1.2 注册中心 2.为什么要使用Nacos 二.Nacos 部署安装1. Nacos 部署方式2. Nacos 安装3. 配置数据源4. 开启控制台授权登录(可选) 三. Nacos配置中心的使用1. 创建配置信…

2023/11/21JAVAweb学习

优先级高低id > 类 > 元素 格式化ctrl alt L

LeetCode热题100——动态规划

动态规划 1. 爬楼梯2. 杨辉三角3. 打家劫舍 1. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? // 题解:每次都有两种选择,1或者2 int climbStairs(int n) {if (n …

GAMES101—Lec 05~06:光栅化

目录 概念回顾(个人理解)光栅化1.采样2.采样出现的问题:走样 反走样 概念回顾(个人理解) 屏幕:在图形学中,我们认为屏幕是一个二维数组,数组里的每一个元素为一个二维像素。 光栅化…

【C++进阶之路】第四篇:set和map

文章目录 一、关联式容器健值对二、set & multiset三、map & multimap在这里插入图片描述 四、set和map底层原理 一、关联式容器健值对 关联式容器 & 键值对 二、set & multiset set & multiset 三、map & multimap map & multimap 四、set和…

【AT模式连接ONENET】ONENET可视化平台的使用

02 ONENET可视化平台的使用 ATCWMODE1 设置模式 ATCWDHCP1,1 启动DHCP功能 ①ATCWJAP"ssid","password" ATCWJAP“123456789”,“wang020118” ②ATMQTTUSERCFG0,1,"设备名字","设备ID","你的鉴权信息""…

JAVA项目测试----用户管理系统

一)项目简介: 用户管理系统是依据于前后端分离来实现的,是基于Spring SpringBoot Spring MVC,SpringAOP,MyBatis等框架来实现的一个用户管理网站,并且已经部署到了云服务器上, 目前的用户管理系统实现了超级管理员的注册功能&…

模电 01

一.半导体基本知识 1.优点:体积小、重量轻、使用寿命长、输入功率小、功率转换效率高。 2.性能介于导体与绝缘体 3.常用半导体材料:硅(SI) 镉(Ge),化合物半导体:砷化镓(GaAs&…

【封装UI组件库系列】全局样式的定义与重置

封装UI组件库系列第二篇样式​​​​​​​ ​​​​​​🌟前言 🌟定义全局样式 生成主题色和不同亮度的颜色 ​编辑 中性色及其他变量 🌟样式重置 🌟总结 ​​​​​​​​​​​​​​🌟前言 在前端开发中&…

SpringBoot趣探究--1.logo是如何打印出来的

一.前言 从本篇开始,我将对springboot框架做一个有趣的探究,探究一下它的流程,虽然源码看不懂,不过我们可以一点一点慢慢深挖,好了,下面我们来看一下本篇的知识,这个logo是如何打印出来的&#…

2014年2月24日 Go生态洞察:FOSDEM 2014上的Go演讲精选

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

【Echart】Echart设置label太长隐藏:

文章目录 第一种:竖排显示第二种:显示部分第三种:强制显示所有标签并旋转 第一种:竖排显示 xAxis: {type: category,data: res.data.data.sz.xAxis,axisLabel:{fontSize:12,formatter: function(value) {return value.split().joi…

gitlab安装以及创建用户创建组,修改密码 邮箱配置 数据备份与恢复--保姆级教学!

GitLab是一种基于Web的Git仓库管理工具,它允许您在组织或个人级别上创建和管理Git仓库,以便在一个中心位置上执行代码管理和协作工作。GitLab提供了强大的功能,如代码审查、问题跟踪、CI/CD、容器注册表、Wiki和持续集成等。 以下是GitLab的…

gitlab安装配置及应用

安装 ##安装依赖 yum install -y curl policycoreutils-python openssh-server perl#上传包 rz gitlab-jh-16.5.2-jh.0.el7.x86_64.rpm 安装 yum install gitlab-jh-16.0.3-jh.0.el7.x86_64.rpm 初始化并启动 # 以下两种方法都可以配置访问地址,第一种需要在yum安…