6月13日OpenAI在Chat Completions API中添加了新的函式呼叫(Function Calling)能力,幫助開發者通過API方式實作類似于ChatGPT插件的資料互動能力,
本文在作者上一篇文章《私有框架代碼生成實踐》的基礎上,依舊使用自然語言低代碼搭建場景作為案例,將嵌入向量搜索(Embedding)獲取私有知識庫的方式,替換為函式呼叫方式,以我們更熟悉的結構化資料結構、關系型資料庫的方式進行知識庫管理,同時函式呼叫能力的靈活性和可擴展性,也可以幫助用戶使用自然語言搭建更加復雜的頁面內容、進行更豐富的互動操作,
一、 什么是函式呼叫
函式呼叫(Function Calling)是OpenAI在6月13日發布的新能力,根據官方博客描述,函式呼叫能力可以讓模型輸出一個請求呼叫函式的訊息,其中包含所需呼叫的函式資訊、以及呼叫函式時所攜帶的引數資訊,這是一種將GPT能力與外部工具/API連接起來的新方式,
支持函式呼叫的新模型,可以根據用戶的輸入自行判斷何時需要呼叫哪些函式,并且可以根據目標函式的描述生成符合要求的請求引數,
開發人員可以使用函式呼叫能力,通過GPT實作:
- 在進行自然語言交流時,通過呼叫外部工具回答問題(類似于ChatGPT插件);
- 將自然語言轉換為呼叫API時使用的引數,或者查詢資料庫時使用的條件;
- 從文本中提取結構化資料,等
二、 如何使用函式呼叫
函式呼叫能力可以通過聊天API(Chat Completion)使用,為了實作函式呼叫能力,OpenAI對聊天API進行了修改,增加了新的請求引數、回應型別以及訊息角色,應用開發者需要:
- 在請求引數中向聊天API傳遞資訊,描述應用所提供的可呼叫函式的資訊,
- 決議聊天API回應的訊息型別,若模型決定需要呼叫函式,則根據模型回傳的函式資訊和函式傳參呼叫函式,并獲得回傳結果,
- 將函式回傳的結果添加到訊息串列中,并再次呼叫聊天API,
1. 添加請求引數, 描述所支持的函式資訊
聊天API中新增了兩個請求體引數:
functions
當前應用可呼叫的函式的串列,函式資訊中包含了函式的名稱、自然語言描述、以及函式所支持傳入的引數資訊,
functions引數的格式如下:
openai.createChatCompletion({
model: "gpt-3.5-turbo-0613",
messages: [
// ...
],
functions: [
{
name: 'function_name',
description: '該函式所具備能力的自然語言描述',
parameters: {
type: 'object',
properties: {
argument_name: {
type: 'string',
description: '該引數的自然語言描述'
},
// ...
},
required: ['argument_name']
}
},
// ...
]
})
functions引數支持以陣列形式錄入多組函式資訊,其中:
-
name:函式名稱,后續模型會在需要呼叫函式時回傳此名稱, -
description:函式功能描述,模型通過該描述理解函式能力,并判斷是否需要呼叫該函式, -
parameters.properties:函式所需的引數,以物件的形式描述函式所需的引數,其中物件的key即為引數名,type:引數型別,支持JSON Schema協議,description:引數描述,
-
required:必填引數的引數名串列,
function_call
控制模型應該如何回應函式調換,支持幾種輸入:
"none":模型不呼叫函式,直接回傳內容,沒有提供可呼叫函式時的默認值,"auto":模型根據用戶輸入自行決定是否呼叫函式以及呼叫哪個函式,提供可呼叫函式時的默認值,{"name": "function_name"}:強制模型呼叫指定的函式,
2. 識別回應引數, 描述需要呼叫的函式資訊
聊天API在回應內容的可選項(choices)中提供了兩個回應引數:
finish_reason
回應內容結束的原因,
可能的原因包括:
stop:已回傳完整訊息,length:已達到令牌限制或由max_tokens引數設定的上限,function_call:模型決定需要呼叫一個函式,content_filter:內容觸發了攔截策略,忽略回傳內容,null:API回應仍在執行,
其中,若回傳function_call則表示模型需要呼叫函式,此時message引數會額外回傳函式資訊以及函式引數資訊,
message.function_call
若回應內容結束的原因是模型需要呼叫函式,則message引數中會增加一個用于描述函式資訊的function_call引數,其格式如下:
name:函式名稱,arguments:函式引數資訊,JSON字串格式,
3. 添加對話角色, 向訊息串列中添加函式回傳值
在函式執行完成后,可以將函式的回傳內容追加到訊息串列中,并攜帶完整的訊息串列再次請求聊天API,以獲得GPT的后續回應,
在訊息串列中,角色的可選值除了原有的系統(system)、用戶(user)、助理(assistant)外,新增了函式(function)型別,用來標識該訊息時函式呼叫的回傳內容,
注意:向訊息串列中追加函式呼叫回應訊息前,還需要首先將上一步模型回傳的訊息追加到訊息串列中,以保證訊息串列中的背景關系完整,
完整使用代碼
const { Configuration, OpenAIApi } = require("openai");
const openai = new OpenAIApi(new Configuration({ /** OpenAI 配置 */ }));
/** 系統角色資訊 **/
const systemPrompt: string = "系統角色prompt";
/** 支持函式資訊 **/
const functionsPrompt: unknow[] = [
{
name: 'function_name',
description: '函式功能的自然語言描述',
parameters: {
type: 'object',
properties: {
argument_name: {
type: 'string',
description: '該引數的自然語言描述'
},
// ...
}
}
},
// ...
];
/** 支持函式邏輯 **/
const functionsCalls: { [name: string]: Function } = {
function_name: (args: { argument_name: string }) => {
const { argument_name } = args;
// ...
return '函式呼叫結果'
},
// ...
}
/** 開始聊天 **/
const chat = async (userPrompt: string) => {
const messages: unknow[] = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
];
let maxCall = 6;
while (maxCall--) {
const responseData = https://www.cnblogs.com/Jcloud/p/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
}
}
}
三、 低代碼自然語言搭建案例
在作者的上一篇文章中,使用嵌入向量搜索提供的“檢索-提問解決方案”進行低代碼私有協議的訪問,在本文中,將使用函式呼叫方式進行替代,
同時,基于函式呼叫的能力,也探索了一些更加復雜的頁面搭建能力和低代碼平臺功能,
1. 私有協議訪問
基于我們的低代碼平臺私有協議,在進行CMS型別頁面的搭建時,我們將協議的知識劃分為幾個層級,并分別提供函式供GPT按需呼叫,以實作私有協議的訪問,
系統描述資訊
const systemPropmpt = `使用CCMS協議撰寫頁面的配置資訊,
CCMS協議所支持的頁面型別包括:
- *form*:表單頁
- *table*:表格頁
- *detail*:詳情頁`;
函式資訊描述
const functionsPrompt = [
{
name: 'get_elements',
description: '獲取CCMS協議在指定頁面型別下,所支持的元素型別,',
parameters: {
type: 'object',
properties: {
page: {
type: 'array',
description: '頁面型別',
items: { type: 'string' }
}
}
},
required: ['page']
},
{
name: 'get_features',
description: '獲取CCMS協議在指定元素型別下,所支持的配置化特性,',
parameters: {
type: 'object',
properties: {
element: {
type: 'array',
description: '元素型別',
items: { type: 'string' }
}
}
},
required: ['element']
},
{
name: 'get_descriptions',
description: '獲取CCMS協議下,指定頁面型別、元素型別以及配置化特性的詳細資訊,',
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模型支持函式的回圈呼叫,但出于減少API呼叫頻次和節省Token消耗的目的,我們建議在查詢私有協議資訊的函式中,使用關鍵詞陣列的形式進行批量查詢,
函式內容
const functionsCalls = {
get_elements: (args: { page: string[] }) => {
const { page } = args;
// 請自行實作資訊查詢,下列回傳內容僅為示例,
return page.map((pageType) => {
switch (pageType) {
case 'form':
return `# **form**表單頁所支持的元素型別包括:
- *form_text*:文本輸入框
- *form_number*: 數值輸入框`;
default:
return `# **${pageType}**沒有支持的元素,`
}
}).join("\n\n");
},
get_features: (args: { element: string[] }) => {
const { element } = args
// 請自行實作資訊查詢,下列回傳內容僅為示例,
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*: 文本正則運算式校驗`
default:
return `# **${elementKey}**沒有支持的配置化特性,`
}
default:
return `# **${elementKey}**沒有支持的配置化特性,`
}
}).join("\n\n");
},
get_descriptions: (args: { page: string[], element: string[], feature: string[] }) => {
const {
page = [],
element = [],
feature = []
} = args
// 請自行實作資訊查詢,下列回傳內容僅為示例,
return [
...page.map((pageType) => `# **${pageType}**的詳細描述如下:...`),
...element.map((elementType) => `# **${elementType}**的詳細描述如下:...`),
...feature.map((featureType) => `# **${featureType}**的詳細描述如下:...`)
].join("\n\n")
}
}
呼叫示例
一次完整呼叫的訊息串列:
為了便于閱讀,已經調整了訊息串列中訊息內容的縮進排版,并且將表示函式呼叫引數的JSON字串決議為物件形式,
[
// 第一次請求聊天API
{ role: 'system',
content: `使用CCMS協議撰寫頁面的配置資訊,
CCMS協議所支持的頁面型別包括:
- *form*: 表單頁
- *table*: 表格頁
- *detail*: 詳情頁` },
{ role: 'user',
content: '創建一個課程報名頁面' },
{ role: 'assistant',
content: null,
function_call: { name: 'get_elements',
arguments: { page: ["form"] } } },
// 第二次請求聊天API
{ role: 'function',
name: 'get_elements',
content: `# **form**表單頁所支持的元素型別包括:
- *form_text*:文本輸入框
- *form_number*: 數值輸入框` },
{ 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*: 文本正則運算式校驗
# **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**的詳細描述如下:...
# **form_text**的詳細描述如下:...
# **form_number**的詳細描述如下:...
# **form_text_maxLength**的詳細描述如下:...
# **form_text_minLength**的詳細描述如下:...
# **form_text_regExp**的詳細描述如下:...` },
{ role: 'assistant',
content: '課程報名頁面的配置資訊如下:\n\n...' }
]
2. 頁面搭建能力擴展: 頁面背景關系跳轉場景
在進行低代碼頁面搭建時,有時會需要在頁面配置中加入一些背景關系資訊,
例如需要在頁面中添加一個按鈕,用戶點擊按鈕時跳轉至另一個頁面,此時我們可以通過一個函式,允許模型獲取相關的頁面串列,
關于按鈕、跳轉操作等協議內容可以通過上一章節中的方法獲取:
## button 按鈕, 支持的配置項包括: - *label*:按鈕標簽 - *action*:操作型別,支持: - *none*:無操作 - *redirect*:頁面重定向 - *redirectTo*:頁面標識
函式資訊描述
const functionsPrompt = [
// ...
{
name: 'get_page_id',
description: '查詢頁面標識串列,其中包含頁面標識(`id`)、頁面名稱(`name`)',
parameters: {
type: 'object',
properties: {
page: {
type: 'string',
description: '頁面'
}
}
}
}
]
函式內容
const functionsCalls = {
// ...
get_page_id: (args: {}) => {
// 請自行實作資訊查詢,下列回傳內容僅為示例,
return JSON.stringify([
{
id: 'page_list',
name: '串列頁'
},
{
id: 'page_create',
name: '新增頁',
description: '用于新增內容'
},
{
id: 'page_preview',
name: '預覽頁'
}
])
}
}
呼叫示例
一次完整呼叫的訊息串列:
為了便于閱讀,已經調整了訊息串列中訊息內容的縮進排版,并且將GPT回傳的配置資訊和表示函式呼叫引數的JSON字串決議為物件形式,
[
// 已省略系統角色資訊以及私有協議訪問資訊,
// ...
{ role: 'user',
content: '添加一個預覽按鈕,點擊后跳轉至預覽頁,'
},
// ...
{ role: 'assistant',
content: { type: "button",
label: "預覽",
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: "預覽頁"} ] },
{ role: 'assistant',
content: { type: "button",
label: "預覽",
action: "redirect",
redirectTo: "page_preview" }
]
3. 低代碼平臺能力擴展: 搭建視窗可視區域調整
在進行自然語言低代碼搭建時,我們希望讓搭建視窗的可視區域自動滾動到發生變化的區域,此時可以通過系統角色要求在進行頁面配置變動時呼叫頁面滾動方法,自動滾動至發生配置變化的元素位置,
系統描述資訊
在系統描述資訊中添加相關描述:
const systemPropmpt = `//...
每次對頁面內容進行調整時,需要滾動頁面至目標元素位置,
CCMS頁面配置資訊為一個陣列,每個頁面元素為陣列中的一項,如:
```json
[
{
"id": "input",
"type": "text",
"label": "文本輸入框"
}
]
```
// ...
`;
函式資訊描述
const functionsPrompt = [
// ...
{
name: 'scroll_to',
description: '滾動頁面至指定元素位置',
parameters: {
type: 'object',
properties: {
element_id: {
type: 'string',
description: '指定元素ID'
}
}
}
}
]
函式內容
const functionsCalls = {
// ...
scroll_id: (args: { element_id: string }) => {
const { element_id } = args
// 自行實作頁面滾動邏輯
return '滾動完成'
}
}
四、 總結
OpenAI提供的函式呼叫功能為使用GPT能力的應用提供了更豐富的可能性,應用開發者可以通過函式呼叫功能,讓用戶通過自然語言互動,獲取實時資料、結構化資料,同時也可以與應用進行各類互動,本文中描述的幾個案例場景僅為拋磚引玉,歡迎大家多多討論,嘗試更多應用場景,
作者:京東零售 牛曉光
來源:京東云開發者社區
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/556709.html
標籤:其他
上一篇:天翼云邊緣安全加速平臺亮相2023亞太內容分發大會暨CDN峰會
下一篇:返回列表
