自分だけのクイズを作成しよう - Quipha
スポンサーリンク

【ChatGPT】Function callingを本格実装

【ChatGPT】Function callingを本格実装 ChatGPT

当サイトではアフィリエイト広告を利用しています。

スポンサーリンク

はじめに

今回は、ChatGPTの新機能であるFunction callingを試します。
自分で作成したアプリから、ChatGPTの機能が呼び出せるとアイディア次第では便利ですね!

他にも私のブログで、ChatGPTについて解説している記事がありますのでご覧ください。

ChatGPTについて

ChatGPTは、OpenAIによって開発された大規模な自然言語処理モデルです。

ChatGPTについては以下の記事もご覧ください。

また、有料プランもあります。
以下の記事も参考にしてください。

Function calling

Function callingは、ユーザーの入力に応じてChatGPTのAPIが判断し関数を呼ぶことができます。
予め定義したプロパティ値を取得することができ、それにより独自のアプリケーションと連携することができます。

詳しくは公式のドキュメントをご覧ください。

function-calling

手軽に独自アプリとChatGPTを連携させることができます。

VS Codeインストール

開発環境を構築します。

VS Codeのインストール方法は、以下の記事にまとめましたのでご覧ください。

VS Codeのオススメ設定や拡張機能などは、以下の記事にまとめました。

スポンサーリンク

Docker Desktopのインストール

Macの場合はDockerのみですが、Windowsの場合はDocker(WSL2がバックエンド)が必要です。
Dockerのインストール方法は、以下の記事をご覧ください。

Windows
Mac

ChatGPTのAPIキーの取得

ChatGPTのAPIを利用するためには、アカウントを作成し、APIキーを取得する必要があります。

アカウントの作成方法は以下の記事を参考にしてください。

APIの登録方法については以下の記事を参考にしてください。

APIキーの利用には料金がかかります。詳しくはOpenAIのサイトをご確認ください。

ログインした状態で、以下のサイトにアクセスします。

platform.openai.com

右上のメニューから、「View API keys」をクリックします。

OpenAI View API keys

「Create new secret key」をクリックし、APIキーを作成します。

OpenAI Create new secret key

APIキーが表示されます。
この画面でしかコピーできず、再度表示することができませんので注意してください。

OpenAI API Key

APIキーは絶対に他人に知られないようにしましょう。

Dockerコンテナの設定

開発環境のコンテナを作成するための定義を用意します。

この設定ファイルは、プロジェクトを作成する度に活用できます。

任意の場所にプロジェクトフォルダを用意します。

Windows例:
\\wsl.localhost\Ubuntu\home\xxx\sample-app\
Mac例:
/users/xxx/Documents/sample-app

Windowsの場合、保存場所はWSLを指定しましょう。
Cドライブなどに保存した場合、ファイルシステムの関係で読み込みが遅くなります。

上記のフォルダの中に、「.devcontainer」フォルダを作成し、このようにファイルを作成します。

/
└ .devcontainer/
  ├ devcontainer.json
  └ Dockerfile

devcontainer.jsonを作成し中身を以下のようにします。
Dockerfileで作成ということと、拡張機能のインストールを記述します。

{
	"name": "Python Sample",
	// Dockerfileでイメージ・コンテナを作成
	"dockerFile": "Dockerfile",
	// リモート先のVS Codeにインストールする拡張機能
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-python.python"
			]
		}
	},
}

Dockerfileを定義します。
Python環境のイメージを使用し、OpenAIのライブラリをインストールします。

FROM python:3 
ENV PYTHONUNBUFFERED 1
 
RUN pip install openai

PYTHONUNBUFFERED」は、Pythonの標準出力のバッファリングを無効にします。
アプリケーションの出力(ログなど)をリアルタイムで確認できるようになります。

設定はこれだけです。
リモート先の設定と、Dockerコンテナの定義を行いました。

以降の解説キャプチャはWindowsをベースにしていますが、Macでの操作も同様です。

VS Codeの起動

VS Codeを起動し、F1キーを押しコマンドパレットを開きます。
「Open Folder in Container」と入力し選択します。

VS Code Open Folder in Container

参考までに以前とメニューの表示方法が変わりました。

先程作成したフォルダを選択します。
プロジェクトにはDockerの設定も含まれているため、初回起動時にはイメージとコンテナが自動で作成されます。

VS Code Dev Container Building image

完了しました。
この時点で、Python環境のコンテナが作成され、リモートしている状態です。

VS Code Dev Container start

実装

ChatGPTのAPIを利用した実装

今回はPythonを使って実装します。
ChatGPTのAPIを利用して、Pythonで実装するやり方は以下の記事を参考にしてください。

【Python】ChatGPT APIを使って連携
PythonでChatGPTのAPIを利用して実装します。

メール送信

それでは早速、実装をしてみましょう。
試しにメールを送信する処理を考えてみます。

メール送信関数を定義し、送信したい内容をユーザが入力します。

import openai
import json

# TODO: APIキーのハードコーディングは避ける
openai.api_key = "APIキー"

# ユーザ入力
sentence = "明日の10時から打合せする件メールを送信する。佐藤さんのアドレスはxxxxxxxx.sato@gmail.comです"

# ユーザの入力した情報から、指定したプロパティを取得する
response = openai.ChatCompletion.create(

    # モデルを指定する
    model="gpt-3.5-turbo-0613",

    messages=[
        {
            "role": "user",
            "content": sentence
        },
    ],

    # 関数定義(複数の定義が可能)
    functions=[
        {
            "name": "send_email",
            "description": "メールを送信する",
            "parameters": {
                "type": "object",
                # プロパティ
                "properties": {
                    "email": {
                        "type": "string",
                        "description": "送信先メールアドレス"
                    },
                    "subject": {
                        "type": "string",
                        "description": "メール件名"
                    },
                    "content": {
                        "type": "string",
                        "description": "メール本文"
                    }
                },
                "required": ["email"]
            }
        }
    ],
    function_call="auto",
)

# 応答結果の出力
print(response["choices"][0]["message"])


# argumentsを出力する場合
#arguments = json.loads(response["choices"][0]
#                       ["message"]["function_call"]["arguments"])
#print(arguments)

ユーザ入力によって、関数を呼ぶか通常のChatGPTを呼ぶか変わります。
そのため、応答結果の「function_call」が含まれない場合がある点に注意です。

上記のように関数を定義し、取得したいプロパティを指定します。
ChatGPTがユーザの入力内容から、それぞれのプロパティ値を取得します。

応答結果は以下のようになりました。

{
  "role": "assistant",
  "content": null,
  "function_call": {
    "name": "send_email",
    "arguments": "{\n  \"email\": \"xxxxxxxx.sato@gmail.com\",\n  \"subject\": \"\u660e\u65e5\u306e\u6253\u5408\u305b\u306b\u3064\u3044\u3066\",\n  \"content\": \"\u660e\u65e5\u306e10\u6642\u304b\u3089\u6253\u5408\u305b\u3092\u884c\u3044\u307e\u3059\u3002\u4f1a\u8b70\u5ba4\u3067\u304a\u5f85\u3061\u3057\u3066\u304a\u308a\u307e\u3059\u3002\"\n}"
  }
}
{'email': 'xxxxxxxx.sato@gmail.com', 'subject': '明日の打合せについて', 'content': '明日の10時から打合せを行います。会議室でお待ちしております。'}

プロパティが取得できたら、独自アプリの処理と回答結果を生成します。

# 応答メッセージを取得する
message = response["choices"][0]["message"]

if message.get("function_call"):
    # 関数呼び出しの場合

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

    if function_name == "send_email":
        # 呼び出された関数によって制御

        # プロパティを取得
        arguments = json.loads(message["function_call"]["arguments"])

        # ユーザの入力から値を取得できる
        # TODO: ここで独自アプリの処理を行う。例えばメールを送信する
        print(arguments.get("email"))
        print(arguments.get("subject"))
        print(arguments.get("content"))

        # 関数の応答結果(必要に応じて追加する)
        function_response = json.dumps({
            "email": arguments.get("email"),
            "subject": arguments.get("subject"),
            "content": arguments.get("content"),
        })

        second_response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=[
                # ユーザ入力
                {
                    "role": "user",
                    "content": sentence
                },
                # ChatGPT応答
                message,
                {
                    # 関数、応答結果
                    "role": "function",
                    "name": function_name,
                    "content": function_response,
                },
            ],
        )

        # 回答結果を取得
        print("-------------")
        chat_results = second_response["choices"][0]["message"]["content"]
        print(chat_results)

TODOと記載しましたが、取得できたプロパティ値を基に独自の処理を行いましょう。
その回答結果をChatGPTに生成させます。

最終的な回答結果は以下のように出力されました。

明日の10時から打合せがあります。参加してください。
佐藤さんのアドレスはxxxxxxxx.sato@gmail.comです。
以上の内容でメールを送信しました。

検索クエリの取得

記事を検索するための関数を作成してみました。

import openai
import json

# TODO: APIキーのハードコーディングは避ける
openai.api_key = "APIキー"

# ユーザ入力
sentence = "Laravelのログイン機能の記事を検索したい"

# ユーザの入力した情報から、指定したプロパティを取得する
response = openai.ChatCompletion.create(

    # モデルを指定する
    model="gpt-3.5-turbo-0613",

    messages=[
        {
            "role": "user",
            "content": sentence
        },
    ],

    # 関数定義(複数の定義が可能)
    functions=[
        {
            "name": "get_articles",
            "description": "WordPressの記事を検索し一覧を取得します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "検索クエリ"
                    }
                },
                "required": ["query"],
            },
        }
    ],
    function_call="auto",
)

print(response["choices"][0]["message"])

# argumentsを出力する場合
#arguments = json.loads(response["choices"][0]
#                       ["message"]["function_call"]["arguments"])
#print(arguments)

以下のようにプロパティ値(検索クエリ)を取得できました。

{
  "role": "assistant",
  "content": null,
  "function_call": {
    "name": "get_articles",
    "arguments": "{\n  \"query\": \"Laravel \u30ed\u30b0\u30a4\u30f3\u6a5f\u80fd\"\n}"
  }
}
{'query': 'Laravel ログイン機能'}

記事一覧を返却する処理を書いてみましょう。

# 応答メッセージを取得する
message = response["choices"][0]["message"]

if message.get("function_call"):
    # 関数呼び出しの場合

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

    if function_name == "get_articles":
        # 呼び出された関数によって制御

        # プロパティを取得
        arguments = json.loads(message["function_call"]["arguments"])

        # ユーザの入力から値を取得できる
        # TODO: ここで独自アプリの処理を行う。例えば検索をする
        print(arguments.get("query"))

        # 関数の応答結果
        # 検索結果を取得した想定でデータを作成
        function_response = json.dumps({
            "query": arguments.get("query"),
            "articles": [
                {
                    "url": "https://chigusa-web.com/blog/laravel8-breeze/",
                    "title": "【Laravel8/9/10】認証機能の導入 (Breeze)"
                },
                {
                    "url": "https://chigusa-web.com/blog/laravel-sail/",
                    "title": "Laravel Sailで開発環境構築【Vite対応】"
                },
            ]
        })

        second_response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=[
                # ユーザ入力
                {
                    "role": "user",
                    "content": sentence
                },
                # ChatGPT応答
                message,
                {
                    # 関数、応答結果
                    "role": "function",
                    "name": function_name,
                    "content": function_response,
                },
            ],
        )

        # 回答結果を取得
        print("-------------")
        chat_results = second_response["choices"][0]["message"]["content"]
        print(chat_results)

以下のように回答結果を取得できました。

以下の記事は、Laravelのログイン機能についての情報を提供しています:

1. [【Laravel8/9/10】認証機能の導入 (Breeze)](https://chigusa-web.com/blog/laravel8-breeze/) - Laravel 8/9/10で利用できるBreezeパッケージを使用して、認証機能を導入する方法について解説しています。

2. [Laravel Sailで開発環境構築【Vite対応】](https://chigusa-web.com/blog/laravel-sail/) - Laravel Sailを使用して、開発環境を構築する方法について解説しています。この記事では、Viteと組み合わせて使用することも紹介されています。

これらの記事を参考にすると、Laravelのログイン機能を理解し、実装することができるでしょう。
スポンサーリンク

関数の複数定義

関数は複数定義できます。
ChatGPTがユーザの入力に応じて、関数を選択します。

import openai
import json

# TODO: APIキーのハードコーディングは避ける
openai.api_key = "APIキー"

# ユーザ入力
sentence = "明日の東京の天気は"

# ユーザの入力した情報から、指定したプロパティを取得する
response = openai.ChatCompletion.create(

    # モデルを指定する
    model="gpt-3.5-turbo-0613",

    messages=[
        {
            "role": "user",
            "content": sentence
        },
    ],

    # 関数定義(複数の定義が可能)
    functions=[
        {
            "name": "get_current_weather",
            "description": "指定された地域の天気を取得する",
            "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city and state, e.g. San Francisco, CA",
                        },
                        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                    },
                "required": ["location"],
            },
        },
        {
            "name": "send_email",
            "description": "メールを送信する",
            "parameters": {
                "type": "object",
                "properties": {
                    "email": {
                        "type": "string",
                        "description": "送信先メールアドレス"
                    },
                    "subject": {
                        "type": "string",
                        "description": "メール件名"
                    },
                    "content": {
                        "type": "string",
                        "description": "メール本文"
                    }
                },
                "required": ["email"]
            }
        },
        {
            "name": "get_articles",
            "description": "WordPressの記事を検索し一覧を取得します。",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "検索クエリ"
                    }
                },
                "required": ["query"],
            },
        }
    ],
    function_call="auto",
)

print(response["choices"][0]["message"])

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

3つの関数を定義していますが、ユーザの入力で天気を聞いたところ、きちんと関数が応答されているのが分かります。

{
  "role": "assistant",
  "content": null,
  "function_call": {
    "name": "get_current_weather",
    "arguments": "{\n  \"location\": \"Tokyo\"\n}"
  }
}

このように、関数を定義し簡単にChatGPTと連携し、その応答結果により独自の処理を行うことができます。

他サービス

他にもAIの便利なサービスがあります。

ChatPDFについては、以下の記事を参考にしてください。

AIにアプリを作ってもらえる、GPTAppです。

WebChatGPTでWebの情報を回答してもらうことができます。

さいごに

今回は、ChatGPTの新機能であるFunction callingを試してみました。

ぜひ試してみてくださいね。

他にも私のブログで、ChatGPTについて解説している記事がありますのでご覧ください。

\オススメ/

コメント