OpenAI(ChatGPT)のFunction callingを使ってkintone連携させてみた

6月13日にあったOpenAI APIの大型アップデートでFunction callingが追加されました。これは超簡単に言うと「ChatGPTに語りかけたらChatGPTがその内容を見て、予め設定してある関数を実行してその結果をいい感じにぬるっと返信する」といったことが簡単にできるようになります。

このFunction callingを利用すると自然言語で問いかけた内容を元にkintoneからデータを取得したりkintoneへデータを登録・更新するということが今まで以上に簡単に実装ができるようになります。

そして、この自然言語の処理部分をまるっとOpenAIにまかせてしまえるというのが開発効率をあげることや良質なアウトプットにめちゃくちゃ効果的です。

今回、実際にGoogle Colabを使って試してみましたのでご紹介したいと思います。

弊社では初回開発無料の定額39万円でkintoneアプリを開発する定額型開発サービス「システム39」を提供しております。kintoneの導入やアプリ開発でお困りの方は、お気軽にご相談ください。
*Webでの打ち合わせも可能です。

   kintoneのアプリ開発はこちら <相談無料>    

OpenAI(ChatGPT)にkintoneの顧客情報を調べてもらう

今回は、Function callingの動きを理解してもらうのが主な目的となりますのでkintoneとの連携は「ChatGPTに企業の情報を調べてほしい依頼があったらkintoneの顧客マスタからデータを取得して返す」というシナリオで進めていきます。

この連携を実現するためにはOpenAIのAPIを最低でも2回実行する必要があり、以下のような流れで実行します

  • 質問内容を受けてOpenAI APIを実行(1回目)し、質問内容を解析して回答に必要な関数を選び、引数を作成する
  • 選ばれた関数を作成された引数を元に実行
  • 質問と関数の実行結果を渡してOpenAI APIを実行(2回目)

具体的なイメージが掴めるよう実際にコードを書いていきましょう。

まずはopenaiのライブラリをインストールします。

!pip install openai

処理に必要なimportとOpenAIのAPI Key、実行するモデルを定義します。
Function callingを使うには0613というモデルを指定する必要があります。ここではgpt-3.5を例にするので「gpt-3.5-turbo-0613」としていますが、gpt-4を利用する場合は「gpt-4-0613」を指定してください。

import openai
import json
import requests

openai.api_key = "sk-xxxxxxxx"
model_name = "gpt-3.5-turbo-0613"

OpenAIのAPIを実行する前にkintoneから顧客情報を取得する関数を書きます。

# kintoneの顧客マスタから顧客情報を取得する関数
def get_kintone_data(companyname):
    url = f"https://xxxx.cybozu.com/k/v1/records.json"
    headers = {
        "Host": "xxxxx.cybozu.com:443",
        "X-Cybozu-API-Token": "xxxxxxxxxx",
        "Content-Type": "application/json"
    }
    params = {
        "app": "39",
        "query": f'会社名 like "{companyname}"',
        "fields": ["会社名","担当者名","TEL","住所"]
    }

    response = requests.get(url, headers=headers, data=json.dumps(params))

    if response.status_code != 200:
        raise Exception(f"Error: {response.status_code}")

    return json.dumps(response.json()["records"])

顧客アプリは以下のような感じで会社名を検索キーに会社名、担当者名、TEL、住所を取得します。

取得した結果はJSONデータのまま返します。

次に1回目のOpenAIのAPIを実行します。

# ChatGPTに投げる質問
question = "林田という会社の会社情報を教えてください"

# functionsの定義
functions=[
    {
        "name": "get_kintone_data",
        "description": "kintoneから会社名をキーワードに企業情報のデータを取得して返します",
        "parameters": {
            "type": "object",
            "properties": {
                "companyname": {
                    "type": "string",
                    "description": "会社名",
                }
            },
            "required": ["companyname"],
        },
    }
]

# 1回目の実行
response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
    ],
    functions=functions,
    function_call="auto",
)

message = response["choices"][0]["message"]
arguments = json.loads(message["function_call"]["arguments"])

function_name = message["function_call"]["name"]

openai.ChatCompletion.createに作成した関数情報を渡し、function_callはautoにします。
autoにすることで渡した関数情報(functions)と質問内容を解析して、実行に適した関数が何かを選んで返してくれます。(ここではget_kintone_dataを返してくれます)
質問に対してどんな関数を実行すればよいかをOpenAIが勝手にいい感じにしかもかなりの高精度で決めてくれるというのが凄いです。

以下のブログでもあるように具体的にOpenAIが何をどうやって適した関数を選択しているかは細かく窺い知ることができなさそうですが、APIが認識しやすいよう関数名(name)はわかりやすく、説明(description)は具体的に書いたほうが良いとは思います。

OpenAI APIのFunction callingで関数が呼ばれる条件を確認してみた

ちなみにfunction_callには明示的に実行したい関数を指定できるのと”none”を指定することで関数を呼び出さないようにすることもできるようです。

functions変数の中のparametersでkintoneから顧客情報を取得する関数の実行に必要な引数の定義を行っています。ここでは「”companyname”というプロパティに会社名を入れてね」と定義しています。

そして、1回目のAPIを実行すると質問内容から関数を実行するために必要な会社名を引数として作成してmessageプロパティの[“function_call”][“arguments”]にセットしてくれます。

これで質問から関数実行に必要な引数(会社名)を取得できますのでkintoneから顧客情報を取得する関数を実行し、その実行結果を元に2回目のOpen AIのAPIを実行します。

#1回目の実行結果を引数に渡してkintoneから顧客データを取得する関数を実行
function_response = get_kintone_data(arguments.get("companyname")) 

# 関数の実行結果を渡して2回目の実行
sec_response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
        message,
        {
            "role": "function",
            "name": function_name,
            "content": function_response,
        },
    ],
)

print(sec_response.choices[0]["message"]["content"].strip())

get_kintone_dataを実行することで会社名からヒットした顧客情報をJSON形式で取得できますので、質問内容、1回目の実行結果、関数の実行結果を渡すことで質問内容を元にkintoneの顧客情報を検索していい感じに結果を返すということが実装できます。

コードをまとめるとこんな感じです。

import openai
import json
import requests

openai.api_key = "sk-xxxxxxxx"
model_name = "gpt-3.5-turbo-0613"

# kintoneの顧客マスタから顧客情報を取得する関数
def get_kintone_data(companyname):
    url = f"https://xxxx.cybozu.com/k/v1/records.json"
    headers = {
        "Host": "xxxx.cybozu.com:443",
        "X-Cybozu-API-Token": "xxxxxxxxxx",
        "Content-Type": "application/json"
    }
    params = {
        "app": "39",
        "query": f'会社名 like "{companyname}"',
        "fields": ["会社名","担当者名","TEL","住所"]
    }

    response = requests.get(url, headers=headers, data=json.dumps(params))

    if response.status_code != 200:
        raise Exception(f"Error: {response.status_code}")

    return json.dumps(response.json()["records"])

# ChatGPTに投げる質問
question = "林田という会社の会社情報を教えてください"

# functionsの定義
functions=[
    {
        "name": "get_kintone_data",
        "description": "kintoneから会社名をキーワードに企業情報のデータを取得して返します",
        "parameters": {
            "type": "object",
            "properties": {
                "companyname": {
                    "type": "string",
                    "description": "会社名",
                }
            },
            "required": ["companyname"],
        },
    }
]

# 1回目の実行
response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
    ],
    functions=functions,
    function_call="auto",
)

message = response["choices"][0]["message"]
arguments = json.loads(message["function_call"]["arguments"])

function_name = message["function_call"]["name"]

#1回目の実行結果を引数に渡してkintoneから顧客データを取得する関数を実行
function_response = get_kintone_data(arguments.get("companyname")) 

# 関数の実行結果を渡して2回目の実行
sec_response = openai.ChatCompletion.create(
    model=model_name,
    messages=[
        {"role": "user", "content": question},
        message,
        {
            "role": "function",
            "name": function_name,
            "content": function_response,
        },
    ],
)

print(sec_response.choices[0]["message"]["content"].strip())

質問を「林田という会社の会社情報を教えてください」としています。
サンプルアプリでは林田という名前の会社は「林田商会」と「林田物産」の2つがありますのでこの質問を投げたところ以下のような結果が返ってきました。

————————————————————————————————

林田という会社の会社情報は以下の通りです:

1. 会社名:林田商会
2. 住所:基本情報欄には「岐阜県恵那市××××」と記載されています。
3. 代表者名:森 懇(もり こうぎ)
4. 電話番号:090-××××-××××(企業ごとに異なる番号が複数記載されています)

もう一つの情報の例:
1. 会社名:林田物産
2. 住所:基本情報欄には「大阪府大阪市北区梅田××××」と記載されています。
3. 代表者名:金子 真吏(かねこ しんじ)
4. 電話番号:090-××××-××××(企業ごとに異なる番号が複数記載されています)

ご質問の「林田」という会社の詳細な情報を教えていただけると、さらに具体的な情報を提供することができます。

————————————————————————————————

ちなみに質問を「板橋電子という会社の会社情報を教えてください」に変えてみると以下の様な回答となりました。

————————————————————————————————

板橋電子株式会社の会社情報は以下の通りです:
– 住所: 神奈川県小田原市××××
– 電話番号: 090-××××-××××
– 代表者名: 末永 亃里
– 会社名: 板橋電子株式会社 以上です。

————————————————————————————————

代表者名など一部怪しい結果があったりアウトプットするフォーマットにばらつきがありますが、ここはプロンプトを調整することで精度は上げられるのではないかと思います。

OpenAI(ChatGPT)とkintone連携の可能性が拡がった

今回はわかりやすさ重視でシンプルな連携にしていますが、質問内容で実行する関数を変えたり、関数を実行した結果、別の関数を呼ぶなど複雑な処理も実装はもちろんできますし、自然言語処理をほぼほぼOpenAIに任せることでkintone連携の実装難易度がかなり下がった印象です。

この連携をうまく活用することで

  • LINE WORKSなどのチャットツールからChatGPTを使ってExpediaで出張の飛行機やホテルを予約し、その結果をkintoneの出張申請アプリに登録する
  • 商談前に商談先企業の担当者情報をChatGPTに調べてもらうとkintoneやHubSpotなどから担当者情報を検索し、わかりやすいフォーマットでまとめて返す

といったことが実現できそうです。

いかがでしたでしょうか?
ブログネタに困ることはないくらいOpenAIのアップデートスピードが早いのですが、また何かみなさんのお役に立てる連携ネタがありましたら書いていきたいと思います。

弊社では初回開発無料の定額39万円でkintoneアプリを開発する定額型開発サービス「システム39」を提供しております。kintoneの導入やアプリ開発でお困りの方は、お気軽にご相談ください。
*Webでの打ち合わせも可能です。

   kintoneのアプリ開発はこちら <相談無料>    

関連記事

同じカテゴリーの記事