6月13日OpenAI在Chat Completions API中添加了新的函數(shù)調(diào)用(Function Calling)能力,幫助開發(fā)者通過API方式實現(xiàn)類似于ChatGPT插件的數(shù)據(jù)交互能力。
本文在作者上一篇文章《私有框架代碼生成實踐》的基礎(chǔ)上,依舊使用自然語言低代碼搭建場景作為案例,將嵌入向量搜索(Embedding)獲取私有知識庫的方式,替換為函數(shù)調(diào)用方式,以我們更熟悉的結(jié)構(gòu)化數(shù)據(jù)結(jié)構(gòu)、關(guān)系型數(shù)據(jù)庫的方式進(jìn)行知識庫管理。同時函數(shù)調(diào)用能力的靈活性和可擴(kuò)展性,也可以幫助用戶使用自然語言搭建更加復(fù)雜的頁面內(nèi)容、進(jìn)行更豐富的交互操作。
一、 什么是函數(shù)調(diào)用
函數(shù)調(diào)用(Function Calling)是OpenAI在6月13日發(fā)布的新能力。根據(jù)官方博客描述,函數(shù)調(diào)用能力可以讓模型輸出一個請求調(diào)用函數(shù)的消息,其中包含所需調(diào)用的函數(shù)信息、以及調(diào)用函數(shù)時所攜帶的參數(shù)信息。這是一種將GPT能力與外部工具/API連接起來的新方式。
支持函數(shù)調(diào)用的新模型,可以根據(jù)用戶的輸入自行判斷何時需要調(diào)用哪些函數(shù),并且可以根據(jù)目標(biāo)函數(shù)的描述生成符合要求的請求參數(shù)。
開發(fā)人員可以使用函數(shù)調(diào)用能力,通過GPT實現(xiàn):
- 在進(jìn)行自然語言交流時,通過調(diào)用外部工具回答問題(類似于ChatGPT插件);
- 將自然語言轉(zhuǎn)換為調(diào)用API時使用的參數(shù),或者查詢數(shù)據(jù)庫時使用的條件;
- 從文本中提取結(jié)構(gòu)化數(shù)據(jù)。等
二、 如何使用函數(shù)調(diào)用
函數(shù)調(diào)用能力可以通過聊天API(Chat Completion)使用。為了實現(xiàn)函數(shù)調(diào)用能力,OpenAI對聊天API進(jìn)行了修改,增加了新的請求參數(shù)、響應(yīng)類型以及消息角色,應(yīng)用開發(fā)者需要:
- 在請求參數(shù)中向聊天API傳遞信息,描述應(yīng)用所提供的可調(diào)用函數(shù)的信息。
- 解析聊天API響應(yīng)的消息類型,若模型決定需要調(diào)用函數(shù),則根據(jù)模型返回的函數(shù)信息和函數(shù)傳參調(diào)用函數(shù),并獲得返回結(jié)果。
- 將函數(shù)返回的結(jié)果添加到消息列表中,并再次調(diào)用聊天API。
1. 添加請求參數(shù), 描述所支持的函數(shù)信息
聊天API中新增了兩個請求體參數(shù):
functions
當(dāng)前應(yīng)用可調(diào)用的函數(shù)的列表。函數(shù)信息中包含了函數(shù)的名稱、自然語言描述、以及函數(shù)所支持傳入的參數(shù)信息。
functions
參數(shù)的格式如下:
openai.createChatCompletion({
model: "gpt-3.5-turbo-0613",
messages: [
// ...
],
functions: [
{
name: 'function_name',
description: '該函數(shù)所具備能力的自然語言描述',
parameters: {
type: 'object',
properties: {
argument_name: {
type: 'string',
description: '該參數(shù)的自然語言描述'
},
// ...
},
required: ['argument_name']
}
},
// ...
]
})
functions
參數(shù)支持以數(shù)組形式錄入多組函數(shù)信息,其中:
-
name
:函數(shù)名稱。后續(xù)模型會在需要調(diào)用函數(shù)時返回此名稱。 -
description
:函數(shù)功能描述。模型通過該描述理解函數(shù)能力,并判斷是否需要調(diào)用該函數(shù)。 -
parameters.properties
:函數(shù)所需的參數(shù)。以對象的形式描述函數(shù)所需的參數(shù),其中對象的key即為參數(shù)名。-
type
:參數(shù)類型。支持JSON Schema協(xié)議。 -
description
:參數(shù)描述。
-
-
required
:必填參數(shù)的參數(shù)名列表。
function_call
控制模型應(yīng)該如何響應(yīng)函數(shù)調(diào)換。支持幾種輸入:
-
"none"
:模型不調(diào)用函數(shù),直接返回內(nèi)容。沒有提供可調(diào)用函數(shù)時的默認(rèn)值。 -
"auto"
:模型根據(jù)用戶輸入自行決定是否調(diào)用函數(shù)以及調(diào)用哪個函數(shù)。提供可調(diào)用函數(shù)時的默認(rèn)值。 -
{"name": "function_name"}
:強(qiáng)制模型調(diào)用指定的函數(shù)。
2. 識別響應(yīng)參數(shù), 描述需要調(diào)用的函數(shù)信息
聊天API在響應(yīng)內(nèi)容的可選項(choices
)中提供了兩個響應(yīng)參數(shù):
finish_reason
響應(yīng)內(nèi)容結(jié)束的原因。
可能的原因包括:
-
stop
:已返回完整消息。 -
length
:已達(dá)到令牌限制或由max_tokens
參數(shù)設(shè)置的上限。 -
function_call
:模型決定需要調(diào)用一個函數(shù)。 -
content_filter
:內(nèi)容觸發(fā)了攔截策略,忽略返回內(nèi)容。 -
null
:API響應(yīng)仍在執(zhí)行。
其中,若返回function_call
則表示模型需要調(diào)用函數(shù)。此時message
參數(shù)會額外返回函數(shù)信息以及函數(shù)參數(shù)信息。
message.function_call
若響應(yīng)內(nèi)容結(jié)束的原因是模型需要調(diào)用函數(shù),則message
參數(shù)中會增加一個用于描述函數(shù)信息的function_call
參數(shù),其格式如下:
-
name
:函數(shù)名稱。 -
arguments
:函數(shù)參數(shù)信息。JSON字符串格式。
3. 添加對話角色, 向消息列表中添加函數(shù)返回值
在函數(shù)執(zhí)行完成后,可以將函數(shù)的返回內(nèi)容追加到消息列表中,并攜帶完整的消息列表再次請求聊天API,以獲得GPT的后續(xù)響應(yīng)。
在消息列表中,角色的可選值除了原有的系統(tǒng)(system
)、用戶(user
)、助理(assistant
)外,新增了函數(shù)(function
)類型,用來標(biāo)識該消息時函數(shù)調(diào)用的返回內(nèi)容。
注意:向消息列表中追加函數(shù)調(diào)用響應(yīng)消息前,還需要首先將上一步模型返回的消息追加到消息列表中,以保證消息列表中的上下文完整。
完整使用代碼
const { Configuration, OpenAIApi } = require("openai");
const openai = new OpenAIApi(new Configuration({ /** OpenAI 配置 */ }));
/** 系統(tǒng)角色信息 **/
const systemPrompt: string = "系統(tǒng)角色prompt";
/** 支持函數(shù)信息 **/
const functionsPrompt: unknow[] = [
{
name: 'function_name',
description: '函數(shù)功能的自然語言描述',
parameters: {
type: 'object',
properties: {
argument_name: {
type: 'string',
description: '該參數(shù)的自然語言描述'
},
// ...
}
}
},
// ...
];
/** 支持函數(shù)邏輯 **/
const functionsCalls: { [name: string]: Function } = {
function_name: (args: { argument_name: string }) => {
const { argument_name } = args;
// ...
return '函數(shù)調(diào)用結(jié)果'
},
// ...
}
/** 開始聊天 **/
const chat = async (userPrompt: string) => {
const messages: unknow[] = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
];
let maxCall = 6;
while (maxCall--) {
const responseData = await openai.createChatCompletion({
model: "gpt-3.5-turbo-0613",
messages,
functions,
function_call: maxCall === 0 ? 'none' : 'auto'
}).then((response) => response.data.choices[0]);
const message = responseData.message
messages.push(message)
const finishReason = responseData.finish_reason
if (finishReason === 'function_call') {
const functionName = message.function_call.name
const functionCall = functionCalls[functionName]
const functionArguments = JSON.parse(message.function_call.arguments)
const functionResponse = await functionCall(functionArguments)
messages.push({
role: 'function',
name: functionName,
content: functionResponse
})
} else {
return message.content
}
}
}
三、 低代碼自然語言搭建案例
在作者的上一篇文章中,使用嵌入向量搜索提供的“檢索-提問解決方案”進(jìn)行低代碼私有協(xié)議的訪問。在本文中,將使用函數(shù)調(diào)用方式進(jìn)行替代。
同時,基于函數(shù)調(diào)用的能力,也探索了一些更加復(fù)雜的頁面搭建能力和低代碼平臺功能。
1. 私有協(xié)議訪問
基于我們的低代碼平臺私有協(xié)議,在進(jìn)行CMS類型頁面的搭建時,我們將協(xié)議的知識劃分為幾個層級,并分別提供函數(shù)供GPT按需調(diào)用,以實現(xiàn)私有協(xié)議的訪問。
系統(tǒng)描述信息
const systemPropmpt = `使用CCMS協(xié)議編寫頁面的配置信息。
CCMS協(xié)議所支持的頁面類型包括:
- *form*:表單頁
- *table*:表格頁
- *detail*:詳情頁`;
函數(shù)信息描述
const functionsPrompt = [
{
name: 'get_elements',
description: '獲取CCMS協(xié)議在指定頁面類型下,所支持的元素類型。',
parameters: {
type: 'object',
properties: {
page: {
type: 'array',
description: '頁面類型',
items: { type: 'string' }
}
}
},
required: ['page']
},
{
name: 'get_features',
description: '獲取CCMS協(xié)議在指定元素類型下,所支持的配置化特性。',
parameters: {
type: 'object',
properties: {
element: {
type: 'array',
description: '元素類型',
items: { type: 'string' }
}
}
},
required: ['element']
},
{
name: 'get_descriptions',
description: '獲取CCMS協(xié)議下,指定頁面類型、元素類型以及配置化特性的詳細(xì)信息。',
parameters: {
type: 'object',
properties: {
page: {
type: 'array',
description: '頁面類型',
items: { type: 'string' }
},
element: {
type: 'array',
description: '元素類型',
items: { type: 'string' }
},
feature: {
type: 'array',
description: '配置化特性',
items: { type: 'string' }
}
}
}
}
]
備注:盡管GPT模型支持函數(shù)的循環(huán)調(diào)用,但出于減少API調(diào)用頻次和節(jié)省Token消耗的目的,我們建議在查詢私有協(xié)議信息的函數(shù)中,使用關(guān)鍵詞數(shù)組的形式進(jìn)行批量查詢。
函數(shù)內(nèi)容
const functionsCalls = {
get_elements: (args: { page: string[] }) => {
const { page } = args;
// 請自行實現(xiàn)信息查詢,下列返回內(nèi)容僅為示例。
return page.map((pageType) => {
switch (pageType) {
case 'form':
return `# **form**表單頁所支持的元素類型包括:
- *form_text*:文本輸入框
- *form_number*: 數(shù)值輸入框`;
default:
return `# **${pageType}**沒有支持的元素。`
}
}).join("\n\n");
},
get_features: (args: { element: string[] }) => {
const { element } = args
// 請自行實現(xiàn)信息查詢,下列返回內(nèi)容僅為示例。
return element.map((elementKey) => {
const [ pageType, elementType ] = elementKey.split('_');
switch (pageType) {
case 'form':
switch (elementType) {
case 'text':
return `# **form_text**(文本輸入框)所支持的配置化特性包括:
- *form_text_maxLength*: 文本最大長度限制
- *form_text_minLength*: 文本最小長度限制
- *form_text_regExp*: 文本正則表達(dá)式校驗`
default:
return `# **${elementKey}**沒有支持的配置化特性。`
}
default:
return `# **${elementKey}**沒有支持的配置化特性。`
}
}).join("\n\n");
},
get_descriptions: (args: { page: string[], element: string[], feature: string[] }) => {
const {
page = [],
element = [],
feature = []
} = args
// 請自行實現(xiàn)信息查詢,下列返回內(nèi)容僅為示例。
return [
...page.map((pageType) => `# **${pageType}**的詳細(xì)描述如下:...`),
...element.map((elementType) => `# **${elementType}**的詳細(xì)描述如下:...`),
...feature.map((featureType) => `# **${featureType}**的詳細(xì)描述如下:...`)
].join("\n\n")
}
}
調(diào)用示例
一次完整調(diào)用的消息列表:
為了便于閱讀,已經(jīng)調(diào)整了消息列表中消息內(nèi)容的縮進(jìn)排版,并且將表示函數(shù)調(diào)用參數(shù)的JSON字符串解析為對象形式。
[
// 第一次請求聊天API
{ role: 'system',
content: `使用CCMS協(xié)議編寫頁面的配置信息。
CCMS協(xié)議所支持的頁面類型包括:
- *form*: 表單頁
- *table*: 表格頁
- *detail*: 詳情頁` },
{ role: 'user',
content: '創(chuàng)建一個課程報名頁面' },
{ role: 'assistant',
content: null,
function_call: { name: 'get_elements',
arguments: { page: ["form"] } } },
// 第二次請求聊天API
{ role: 'function',
name: 'get_elements',
content: `# **form**表單頁所支持的元素類型包括:
- *form_text*:文本輸入框
- *form_number*: 數(shù)值輸入框` },
{ role: 'assistant',
content: null,
function_call: { name: 'get_features',
arguments: { element: ["form_text", "form_number"] } } },
// 第三次請求聊天API
{ role: 'function',
name: 'get_features',
content: `# **form_text**(文本輸入框)所支持的配置化特性包括:
- *form_text_maxLength*: 文本最大長度限制
- *form_text_minLength*: 文本最小長度限制
- *form_text_regExp*: 文本正則表達(dá)式校驗
# **form_number**沒有支持的配置化特性。` },
{ role: 'assistant',
content: null,
function_call: { name: 'get_descriptions',
arguments: { page: ["form"],
element: ["form_text", "form_number"],
feature: ["form_text_maxLength", "form_text_minLength", "form_text_regExp"] } } },
// 第四次請求聊天API
{ role: 'function',
name: 'get_descriptions',
content: `# **form**的詳細(xì)描述如下:...
# **form_text**的詳細(xì)描述如下:...
# **form_number**的詳細(xì)描述如下:...
# **form_text_maxLength**的詳細(xì)描述如下:...
# **form_text_minLength**的詳細(xì)描述如下:...
# **form_text_regExp**的詳細(xì)描述如下:...` },
{ role: 'assistant',
content: '課程報名頁面的配置信息如下:\n\n...' }
]
2. 頁面搭建能力擴(kuò)展: 頁面上下文跳轉(zhuǎn)場景
在進(jìn)行低代碼頁面搭建時,有時會需要在頁面配置中加入一些上下文信息。
例如需要在頁面中添加一個按鈕,用戶點(diǎn)擊按鈕時跳轉(zhuǎn)至另一個頁面。此時我們可以通過一個函數(shù),允許模型獲取相關(guān)的頁面列表。
關(guān)于按鈕、跳轉(zhuǎn)操作等協(xié)議內(nèi)容可以通過上一章節(jié)中的方法獲取:
## button 按鈕。 支持的配置項包括: - *label*:按鈕標(biāo)簽 - *action*:操作類型,支持: - *none*:無操作 - *redirect*:頁面重定向 - *redirectTo*:頁面標(biāo)識
函數(shù)信息描述
const functionsPrompt = [
// ...
{
name: 'get_page_id',
description: '查詢頁面標(biāo)識列表。其中包含頁面標(biāo)識(`id`)、頁面名稱(`name`)',
parameters: {
type: 'object',
properties: {
page: {
type: 'string',
description: '頁面'
}
}
}
}
]
函數(shù)內(nèi)容
const functionsCalls = {
// ...
get_page_id: (args: {}) => {
// 請自行實現(xiàn)信息查詢,下列返回內(nèi)容僅為示例。
return JSON.stringify([
{
id: 'page_list',
name: '列表頁'
},
{
id: 'page_create',
name: '新增頁',
description: '用于新增內(nèi)容'
},
{
id: 'page_preview',
name: '預(yù)覽頁'
}
])
}
}
調(diào)用示例
一次完整調(diào)用的消息列表:
為了便于閱讀,已經(jīng)調(diào)整了消息列表中消息內(nèi)容的縮進(jìn)排版,并且將GPT返回的配置信息和表示函數(shù)調(diào)用參數(shù)的JSON字符串解析為對象形式。
[
// 已省略系統(tǒng)角色信息以及私有協(xié)議訪問信息。
// ...
{ role: 'user',
content: '添加一個預(yù)覽按鈕,點(diǎn)擊后跳轉(zhuǎn)至預(yù)覽頁。'
},
// ...
{ role: 'assistant',
content: { type: "button",
label: "預(yù)覽",
action: "redirect",
redirectTo: "preview" },
function_call: { name: 'get_page_id',
arguments: { page: "preview" } } },
{ role: 'function',
name: 'get_page_id',
content: [ { id: "page_list", name: "列表頁" },
{ id: "page_create", name: "新增頁" },
{ id: "page_preview", name: "預(yù)覽頁"} ] },
{ role: 'assistant',
content: { type: "button",
label: "預(yù)覽",
action: "redirect",
redirectTo: "page_preview" }
]
3. 低代碼平臺能力擴(kuò)展: 搭建窗口可視區(qū)域調(diào)整
在進(jìn)行自然語言低代碼搭建時,我們希望讓搭建窗口的可視區(qū)域自動滾動到發(fā)生變化的區(qū)域,此時可以通過系統(tǒng)角色要求在進(jìn)行頁面配置變動時調(diào)用頁面滾動方法,自動滾動至發(fā)生配置變化的元素位置。
系統(tǒng)描述信息
在系統(tǒng)描述信息中添加相關(guān)描述:
const systemPropmpt = `//...
每次對頁面內(nèi)容進(jìn)行調(diào)整時,需要滾動頁面至目標(biāo)元素位置。
CCMS頁面配置信息為一個數(shù)組,每個頁面元素為數(shù)組中的一項,如:
```json
[
{
"id": "input",
"type": "text",
"label": "文本輸入框"
}
]
```
// ...
`;
函數(shù)信息描述
const functionsPrompt = [
// ...
{
name: 'scroll_to',
description: '滾動頁面至指定元素位置',
parameters: {
type: 'object',
properties: {
element_id: {
type: 'string',
description: '指定元素ID'
}
}
}
}
]
函數(shù)內(nèi)容
const functionsCalls = {
// ...
scroll_id: (args: { element_id: string }) => {
const { element_id } = args
// 自行實現(xiàn)頁面滾動邏輯
return '滾動完成'
}
}
四、 總結(jié)
OpenAI提供的函數(shù)調(diào)用功能為使用GPT能力的應(yīng)用提供了更豐富的可能性。應(yīng)用開發(fā)者可以通過函數(shù)調(diào)用功能,讓用戶通過自然語言交互,獲取實時數(shù)據(jù)、結(jié)構(gòu)化數(shù)據(jù),同時也可以與應(yīng)用進(jìn)行各類交互。本文中描述的幾個案例場景僅為拋磚引玉,歡迎大家多多討論,嘗試更多應(yīng)用場景。
作者:京東零售 牛曉光文章來源:http://www.zghlxwxcb.cn/news/detail-526565.html
來源:京東云開發(fā)者社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-526565.html
到了這里,關(guān)于【OpenAI】ChatGPT函數(shù)調(diào)用(Function Calling)實踐 | 京東云技術(shù)團(tuán)隊的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!