News

お知らせ

2023年8月1日 投稿:stak編集部

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

イニシャライズ

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)

モックを用意

実際の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}

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']
    },
}];

実行してみる

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

(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}'
  }
}

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

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

実行結果

{
  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)
}

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

実行結果を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)

実行結果

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

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

所管

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

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

stakの最新情報を受け取ろう

stakはブログやSNSを通じて、製品やイベント情報など随時配信しています。
メールアドレスだけで簡単に登録できます。