1
/
5

Function callingを試してみた

こんにちは

エンジニアの上本です。

6月13日にOpenAIの大きなアプデートが発表されました。

その中で目玉機能として紹介されていた「Function callng」を遅ればせながら試してみたので、その概要と所管をお伝えしたいと思います。

Function callingとは

Function callingを簡単に説明すると、外部関数の呼び出しを検知して、教えてくれる仕組みのことです。

スケジュールを管理するボットを例に考えて見ましょう。「明日のスケジュールは?」と聞いてもGPTはスケジュールの情報を持っていません。

その情報を取得するにはスケジュールを管理しているサービスの予定を取得する関数(API)を呼び出す必要があるのですが、それを教えてくれるのがFunction callingです。

また、APIの定義に則ってパラメータを調整してくれます。例えば、スケジュールを取得するAPIは日付を年月日で指定する必要があるとします。しかしAPIに「明日」と指定することはできません。この部分をOpenAIがよしなに変換してくれます。

めちゃくちゃ有り難いですね!

自社サービスを想定して試してみる

概要がわかったところで、実際に自社で提供しているスマートホーム化ツール「Home Hub」を想定し、自然言語の指示からAPI操作を行う処理を試してみます。(※Home HubのAPIは公開していないためモックで表現)

インストール

現在公式で公開しているライブラリは「Python」「Node.js」「Azure OpenAI libraries」ということなので、今回は「Node.js」を使用します。

npm install openai dotenv


npm install openai dotenv

イニシャライズ

OpenAI APIの認証情報を指定します。

# index.ts

import {Configuration, OpenAIApi} from 'openai'
import * as dotenv from "dotenv"

dotenv.config()

const configuration = new Configuration({
organization: process.env.OPENAI_ORGANIZATION_ID,
apiKey: process.env.OPENAI_API_KEY,
})

const openai = new OpenAIApi(configuration)


# index.ts

import {Configuration, OpenAIApi} from 'openai'
import * as dotenv from "dotenv"

dotenv.config()

const configuration = new Configuration({
organization: process.env.OPENAI_ORGANIZATION_ID,
apiKey: process.env.OPENAI_API_KEY,
})

const openai = new OpenAIApi(configuration)

モックを用意

実際のAPIを呼び出すための関数を用意します。今回は、「照明の操作」「鍵の操作」を行うためのAPIを呼び出す関数を用意しました。それぞれ、部屋と操作内容を指定する想定です。

const lightAction = ({room, action}: { room: string, action: string }): Promise<{ room: string, action: string }> => {
// 照明操作のAPIを呼び出す
return new Promise((resolve) => resolve({room, action}))
}

const lockAction = ({room, action}: { room: string, action: string }): Promise<{ room: string, action: string }> => {
// スマートロック操作のAPIを呼び出す
return new Promise((resolve) => resolve({room, action}))
}

const functions = {lightAction, lockAction}


const lightAction = ({room, action}: { room: string, action: string }): Promise<{ room: string, action: string }> => {
// 照明操作のAPIを呼び出す
return new Promise((resolve) => resolve({room, action}))
}

const lockAction = ({room, action}: { room: string, action: string }): Promise<{ room: string, action: string }> => {
// スマートロック操作のAPIを呼び出す
return new Promise((resolve) => resolve({room, action}))
}

const functions = {lightAction, lockAction}

APIの定義を指定

「name」に先程作成したモックを呼び出す関数。「description」にその関数の説明。「parameters」に関数の引数の情報を指定します。

const functionDefinitions = [{
name: 'lightAction',
description: '指定した部屋の照明を操作する',
parameters: {
type: 'object',
properties: {
room: {
type: 'string',
description: '部屋',
},
action: {
type: 'string',
enum: [
'ON',
'OFF',
],
description: '操作',
},
},
required: ['room', 'action']
},
}, {
name: 'lockAction',
description: '指定した部屋の鍵を操作する',
parameters: {
type: 'object',
properties: {
room: {
type: 'string',
description: '部屋',
},
action: {
type: 'string',
enum: [
'LOCK',
'UNLOCK',
],
description: '操作',
},
},
required: ['room', 'action']
},
}];


const functionDefinitions = [{
name: 'lightAction',
description: '指定した部屋の照明を操作する',
parameters: {
type: 'object',
properties: {
room: {
type: 'string',
description: '部屋',
},
action: {
type: 'string',
enum: [
'ON',
'OFF',
],
description: '操作',
},
},
required: ['room', 'action']
},
}, {
name: 'lockAction',
description: '指定した部屋の鍵を操作する',
parameters: {
type: 'object',
properties: {
room: {
type: 'string',
description: '部屋',
},
action: {
type: 'string',
enum: [
'LOCK',
'UNLOCK',
],
description: '操作',
},
},
required: ['room', 'action']
},
}];

実行してみる

諸々定義が用意できたので試しに「リビングの電気をつけて」と指示してみます。

(async () => {
const prompt = 'リビングの電気をつけて'

const res = await openai.createChatCompletion({
model: 'gpt-4-0613',
messages: [{
role: 'user',
content: prompt
}],
function_call: 'auto',
functions: functionDefinitions
})
console.log(res.data.choices[0].message)

})()


(async () => {
const prompt = 'リビングの電気をつけて'

const res = await openai.createChatCompletion({
model: 'gpt-4-0613',
messages: [{
role: 'user',
content: prompt
}],
function_call: 'auto',
functions: functionDefinitions
})
console.log(res.data.choices[0].message)

})()

実行結果

{
role: 'assistant',
content: null,
function_call: {
name: 'lightAction',
arguments: '{\n "room": "リビング",\n "action": "ON"\n}'
}
}


{
role: 'assistant',
content: null,
function_call: {
name: 'lightAction',
arguments: '{\n "room": "リビング",\n "action": "ON"\n}'
}
}

実行するとこのように、照明を操作するAPI「lightAction」を使い、引数には「room: リビング」「action: ON」を指定すると返ってきました。

続いて、指示を「玄関の鍵を締めて」に変更してみます。

実行結果

{
role: 'assistant',
content: null,
function_call: {
name: 'lockAction',
arguments: '{\n "room": "玄関",\n "action": "LOCK"\n}'
}
}



{
role: 'assistant',
content: null,
function_call: {
name: 'lockAction',
arguments: '{\n "room": "玄関",\n "action": "LOCK"\n}'
}
}

はい、凄すぎますね!

取得したAPIを叩く

あんな簡単なAPI定義を指定するだけで、自然言語での指示を実際に利用できる形式になりました。あとは実際にAPIを叩いてあげるだけです。

createChatCompletionの実行の後に下記を追加します。

const message = res.data.choices[0].message
const functionCall = message?.function_call

if (functionCall) {
const args = JSON.parse(functionCall.arguments)
const response = await functions[functionCall.name](args)
}


const message = res.data.choices[0].message
const functionCall = message?.function_call

if (functionCall) {
const args = JSON.parse(functionCall.arguments)
const response = await functions[functionCall.name](args)
}

実行すると、すんなり操作が行えました。

実行結果をGPTに返答させる

GPTに返答させるには、実行結果を「messages」に追加します。

先程のif文の終了前に書きを追加します。

const response2 = await openai.createChatCompletion({
model: 'gpt-4-0613',
messages: [{
role: 'user',
content: prompt
}, {
role: 'function',
content: JSON.stringify(response),
name: functionCall.name
}],
function_call: 'auto',
functions: functionDefinitions
})

console.log(response2.data.choices[0].message)


const response2 = await openai.createChatCompletion({
model: 'gpt-4-0613',
messages: [{
role: 'user',
content: prompt
}, {
role: 'function',
content: JSON.stringify(response),
name: functionCall.name
}],
function_call: 'auto',
functions: functionDefinitions
})

console.log(response2.data.choices[0].message)

実行結果

{ role: 'assistant', content: '玄関の鍵を締めました。' }


{ role: 'assistant', content: '玄関の鍵を締めました。' }

よしなに、人が理解できる文章で返事をしてくれました。

所管

Function callingを試してみて、自然言語の曖昧な指示から「どのAPIを」「どんなパラメータで」叩けば良いのかという具体的な指示に、こんなに簡単に実現できるのに驚きました。

音声入力を受け付ければ、自アプリだけで簡単なスマートスピーカーを実現できたりと可能性が拡がりまくりですね。今後も色々と試して見たいと思います。

株式会社stakでは一緒に働く仲間を募集しています
1 いいね!
1 いいね!

同じタグの記事

今週のランキング

上本 潤さんにいいねを伝えよう
上本 潤さんや会社があなたに興味を持つかも