OpenAI 发布几个重磅更新
1、 开放 16k 上下文的 GPT-3.5-Turbo 模型(gpt-3.5-turbo-16k),是目前的4倍
2、 新的 GPT-4 和 3.5 Turbo 模型
3、Chat Completions API 中的新增加函数调用功能 (实时获取网络数据成为可能)
4、embeddings模型的成本降低75%
5、gpt-3.5-turbo的输入token成本降低了25% (开发者的福音)
其中最令人兴奋的功能应该当属函数调用功能,我们都知道ChatGPT训练的数据是基于2021年之前的,你要问一些实时性相关的问题就没法回答你了,而函数调用让实时获取网络数据成为可能,比如查询天气预报、查股票、推荐个近期的电影之类的。
哪些模型支持函数调用?
gpt-3.5-turbo-0613
和 gpt-4-0613
这两个模型都支持函数调用。
函数调用的流程是什么?
1、用户发起提问时,调用一次带有函数描述的completions接口,gpt会判断是否支持调用函数,如果可以就从用户的提问信息中提取出函数所需要的参数。
2、开发者拿到gpt提取出来的参数后自行调用函数并返回结果
3、将函数的返回结果再次发给GPT做总结归纳为自然语言
需要注意的地方:
举个真实例子
这里我以实时获取天气预报为例子演示函数调用的流程,天气预报接口我用的第三方高德API,免费,每天几千次的调用额度。申请注册流程这里省略,自行研究。
这个函数就是用来查询天气情况的,参数 city_name
是城市的名字,因为高德API只支持通过城市代码查天气,所以我这里做了一次根据城市名找到对应编码的查询
接口返回的结果中包含有温度(temperature)、风度(windpower)、风向(winddirection)、湿度(humidity)、天气(weather)等字段信息。
天气函数准备好后,用户开始提问:“深圳天气如何?“, 第一次调用`ChatCompletion`接口。
这里我们指定了一个functions
参数,该参数描述了函数的名字以及参数类型,比如我们这里定义了city_name
的参数,gpt 就会从用户问题中提取出city_name。
gpt 给我们返回的message中有function_call
字段,而且 arguments 里面提取了city_name这个字段的值。
第二步:从返回结果中提取参数后调用函数, 这个过程不是交给gpt处理,而是由开发者自己调用该函数,gpt做的事情是把函数需要的参数提取出来。
注意,这里要将函数调用返回的结果做一些json转换
第三交步:把返回结果给gpt做总结归纳
注意messages列表中最后一条消息中role
角色是 function, 最后得到的结果second_response
中的content内容为:
const functionCalling = async ({
isUseGoogleSearch,
params,
messages,
historyMessage,
model,
}) => {
const searchGoogleGptFunction = {
name: 'search_google_when_gpt_cannot_answer',
description:
'当 gpt 遇到无法回答的或者需要搜索引擎协助回答时从 google 搜索',
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: '搜索句,支持中文或者英文',
},
},
},
}
const getCurrentWeather = {
name: 'get_current_weather',
description: '获取指定地区的当前天气情况',
parameters: {
type: 'object',
properties: {
city: {
type: 'string',
description: '城市,例如:深圳',
},
},
required: ['city'],
},
}
params = {
...params,
functions: [searchGoogleGptFunction, getCurrentWeather],
function_call: isUseGoogleSearch ? 'auto' : 'none', //fun?.function_call, none
}
let completionRes = await axios.post(`${baseURL}/api/light/chat/openAi`, {
model,
messages,
apiKey,
params,
})
const { completion } = completionRes.data.data
if (
completion &&
Array.isArray(completion.choices) &&
completion.choices.length > 0
) {
if (
completion.choices[0].finish_reason === 'function_call' &&
completion.choices[0]?.message?.function_call?.name ===
'search_google_when_gpt_cannot_answer'
) {
try {
let myArguments = completion.choices[0]?.message?.function_call?.arguments
console.log('myArguments', myArguments)
myArguments = myArguments ? JSON.parse(myArguments) : {}
let pageNum = 1
searchCount = searchCount + 1
let message = myArguments.query
console.log('google搜索次数', searchCount)
console.log('google搜索关键词', message, Date())
let timer = setTimeout(() => {
customSendEmail({
subject: 'google搜索超时',
html: `google搜索超时,${message},${pageNum}`,
})
}, 1000 * 60)
try {
let result = await axios.post(
`${baseURL}/api/light/chat/googleSearchOnAzure`,
{
message,
pageNum: 1,
apiKey,
}
)
clearTimeout(timer)
const { searchResult } = result.data.data
delete searchResult.queries
if (searchResult && Array.isArray(searchResult.items)) {
let googleResultList = searchResult.items.map((item) => {
return {
title: item.title,
snippet: item.snippet,
}
})
const googleResultForGPT = `这是我的提问:${historyMessage}\n这是我在google搜索“${message}”的结果:\n${JSON.stringify(
googleResultList
)}\n请结合搜索结果回答`
console.log(googleResultForGPT)
let messagesTemp = [
...messages,
{
role: 'function',
name: completion.choices[0]?.message?.function_call?.name,
content: googleResultForGPT,
},
]
completionRes = await axios.post(
`${baseURL}/api/light/chat/openAi`,
{
model,
messages: messagesTemp,
apiKey,
params,
}
)
return completionRes
}
} catch (err) {
console.log('错误1', err)
if (global.isLocal === false) {
customSendEmail({
subject: 'chatgpt错误【2】',
html: `chatgpt错误【2】
${err.stack}`,
})
}
}
} catch (err) {
console.log('chatgpt错误【1】', err)
if (global.isLocal === false) {
customSendEmail({
subject: 'chatgpt错误【1】',
html: `chatgpt错误【1】
${err.stack}`,
})
}
}
} else if (
completion.choices[0].finish_reason === 'function_call' &&
completion.choices[0]?.message?.function_call?.name ===
'get_current_weather'
) {
try {
let myArguments = completion.choices[0]?.message?.function_call?.arguments
console.log('myArguments,get_current_weather', myArguments)
myArguments = myArguments ? JSON.parse(myArguments) : {}
let city = myArguments.city
let resultCity = cityList.find(item => item.name.includes(city))
let cityCode = '110000'
if (resultCity && resultCity.adcode) {
cityCode = resultCity.adcode
}
console.log('城市', city, cityCode)
let result = await axios.get(
`https://restapi.amap.com/v3/weather/weatherInfo?key=${weatherApiKey}&city=${cityCode}`
)
const searchResult = result.data
if (searchResult && Array.isArray(searchResult.lives)) {
const searchResultForGPT = `这是我的提问:${historyMessage}\n这是我查询到的结果:\n${JSON.stringify(
searchResult.lives
)}\n请结合搜索结果回答`
console.log(searchResultForGPT)
let messagesTemp = [
...messages,
{
role: 'function',
name: completion.choices[0]?.message?.function_call?.name,
content: searchResultForGPT,
},
]
completionRes = await axios.post(`${baseURL}/api/light/chat/openAi`, {
model,
messages: messagesTemp,
apiKey,
params,
})
return completionRes
}
} catch (err) {
console.log('chatgpt错误【3】', err)
if (global.isLocal === false) {
customSendEmail({
subject: 'chatgpt错误【3】',
html: `chatgpt错误【3】
${err.stack}`,
})
}
}
}
}
}
const { google } = require('googleapis')
const chatGoogleSearchOnAzure = async (req, res) => {
let { message = '', pageNum = 1, apiKey = 'sk-xxx' } = req.body
if (apiKey === 'xxx') {
let start = (pageNum - 1) * 10
const customSearch = google.customsearch('v1')
const customSearchRes = await customSearch.cse.list({
cx: googleCx,
key: googleKey,
q: message,
start,
num: 10,
hl: 'zh-CN',
safe: 'off',
imgColorType: 'color',
})
const searchResult = customSearchRes.data
res.send({
code: 200,
data: {
searchResult: searchResult,
},
message: '成功',
})
} else {
res.send({
code: 400,
message: '失败:参数apiKey',
})
}
}
参考链接:
https://wejson.cn/excel2json/
https://lbs.amap.com/api/webservice/guide/api/weatherinfo/
https://m.moji.com/weather/china/beijing/beijing
https://zhuanlan.zhihu.com/p/637425118
http://chat.xutongbao.top/