这两天看的比较多的一个新闻就是 OpenAI 又更新了自己的 API。 除了各种大减价,增加 Token 数量之外,还新推出了一个叫做 Function calling 的能力。那么 Function calling 到底是什么东西,可能很多新闻类型的内容也没讲太明白,我和大家聊一下。
其实这个能力和我之前跟大家聊的 ChatGPT 插件功能有些类似。 如果没看过的朋友,我也简单和大家描述一下, ChatGPT 插件是这样一个流程,你的服务端给它提供一个描述文件,就是告诉 ChatGPT 怎么调用你的接口,以及这些接口都能做什么。 那么当用户在使用 ChatGPT 的时候,如果 ChatGPT 认为用户提的某些问题,你的插件能够更好的解决,那么 ChatGPT 就会直接去调用你插件的接口。
当然,如果我这个描述你还是不能很好的理解,可以看看我之前的文章:说说 ChatGPT Plugin, 看看你能否先知先觉
Function calling 其实就是把这个过程 API 化了。 这个东西出现的还真是快,其实我在前些天用 ChatGPT 插件的时候就一只在想这个问题,插件最强大的地方在于任何类型的应用,无论它本身是否有 AI 能力,都能用通过插件这个方式把大语言模型的能力用到自己的产品上面。
但是插件也有一个局限性,就是用户的使用场景受限,必须在 ChatGPT 界面中才行。我那会儿就在想要是这个能力能脱离 ChatGPT 本身的界面,那就更强大了。结果 OpenAI 还是厉害,我想到的这些问题,人家早就想明白了,而且很快的把它变成现实了。
https://platform.openai.com/docs/guides/gpt/function-calling
Function calling:
const { google } = require('googleapis')
const chatUseOpenAi = async (req, res) => {
let {
model = 'gpt-3.5-turbo-16k-0613',
messages = [
{
role: 'user',
content: '你好',
},
],
apiKey = 'sk-xxx',
params = {},
} = req.body
if (apiKey === 'xxx') {
let baseURL = 'http://xxx'
const searchGoogleGptFunction = {
name: 'search_google_when_gpt_cannot_answer',
description:
'当 gpt 遇到无法回答的或者需要搜索引擎协助回答时从 google 搜索',
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: '搜索句,支持中文或者英文',
},
},
},
}
let getCurrentWeather = {
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'],
},
}
let isUseGoogleSearch = true
params = {
...params,
functions: [searchGoogleGptFunction],
function_call: isUseGoogleSearch ? 'auto' : 'none', //fun?.function_call, none
}
let result = await axios.post(`${baseURL}/api/light/chat/openAi`, {
model,
messages,
apiKey,
params,
})
const { errorData, completion } = result.data.data
let tempSearchResult = ''
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 arguments =
completion.choices[0]?.message?.function_call?.arguments
console.log('arguments', arguments)
arguments = arguments ? JSON.parse(arguments) : {}
let baseURL = 'http://xxx'
let pageNum = 1
searchCount = searchCount + 1
let message = arguments.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: 'xxx',
}
)
clearTimeout(timer)
const { searchResult } = result.data.data
delete searchResult.queries
tempSearchResult = searchResult
if (searchResult && Array.isArray(searchResult.items)) {
let googleResultList = searchResult.items.map((item) => {
return {
title: item.title,
snippet: item.snippet,
}
})
const googleResultForGPT = `这是我的提问:${message}\n这是我在google搜索“${message}”的结果:\n${JSON.stringify(
googleResultList
)}\n请结合搜索结果回答`
let messagesTemp = [
...messages,
{
role: 'function',
name: completion.choices[0]?.message?.function_call?.name,
content: googleResultForGPT,
},
]
let resultForGPT = await axios.post(
`${baseURL}/api/light/chat/openAi`,
{
model,
messages: messagesTemp,
apiKey,
params,
}
)
const { errorData, completion: completionForGTP } =
resultForGPT.data.data
res.send({
code: 200,
data: {
errorData,
completionForGTP,
params,
tempSearchResult,
},
message: '成功',
})
return
}
} catch (err) {
console.log('错误1', err.stack)
customSendEmail({
subject: 'google搜索失败',
html: `chatgpt自动调用<br/>${err.stack}`,
})
}
} catch (error) {
console.log('arguments, 解析错误')
customSendEmail({
subject: 'arguments, 解析错误',
html: `arguments, 解析错误<br/>${err.stack}`,
})
}
}
}
res.send({
code: 200,
data: {
errorData,
completion,
params,
tempSearchResult,
},
message: '成功',
})
} else {
res.send({
code: 400,
message: '失败:参数apiKey',
})
}
}
google搜索:
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: 'xxx',
key: 'xxx,
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://juejin.cn/post/7249909247039143997
http://swiftcafe.io/post/openai-api
http://chat.xutongbao.top