TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

ChatGPT APIのFunction callingを試す

Chat Completions APIに新しく追加された機能である「Function calling」を試してみた。
Function calling and other API updates

Function calling

Bingチャットを使っていると、質問に応じて必要なときに検索を行う処理を行っている。同じように状況に応じてアクションをとる処理を実装しようとすると、プロンプトエンジニアリングを頑張る必要がある。
今回追加された「Function calling」は、このような用途をプロンプトエンジニアリングなしで実現することができる。

APIの呼び出し時に渡すfunctionsパラメータに、どのような状況で関数を実行するかの説明を書いておけば、質問文がその状況に該当する場合に、finish_reasonがfunction_callになって、関数引数の値とともに返してくれる。

その値をもとにアクションを行って、さらに生成を続けることができる。

要約に使えそう

他のユースケースとしては、例えば文書に対する質問を行うチャットボットの場合、プロンプトに「要約してください」が与えられた場合に、質問に対する回答ではなく、要約の関数を定義しておけば、文書全体の要約処理を行うことができる。
要約の時だけ、トークン数が4倍になった16kのモデルを使うとかもできそうである。

他のユースケース

他にも、OpenAIの記事ではデータベース クエリに変換する処理や、テキストから構造化データを抽出する用途が紹介されている。

OpenAI Cookbook

OpenAI CookbookにFunction callingのノートブックが追加されたので試してみた。
openai-cookbook/examples/How_to_call_functions_with_chat_models.ipynb at main · openai/openai-cookbook · GitHub

天気を検索

AIPのパラメータに渡す関数定義を以下のように行う。
関数定義のdescriptionに記述している「Get the current weather」に該当する質問の場合にこの関数が返されるようになる。

functions = [
    {
        "name": "get_current_weather",
        "description": "Get the current weather",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA",
                },
                "format": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "The temperature unit to use. Infer this from the users location.",
                },
            },
            "required": ["location", "format"],
        },
    }
]


ユーザの質問が、「what is the weather like today」の場合、関数の引数locationが特定できないため、ChatGPTからは場所を聞く質問が返される。

conversation.add_message("user", "what is the weather like today")
{'role': 'assistant', 'content': 'Where are you currently located?'}

ユーザが場所を回答すると、関数を返す条件が整ったので、関数が返される。

conversation.add_message("user", "I'm in Glasgow, Scotland")
{'index': 0,
 'message': {'role': 'assistant',
  'content': None,
  'function_call': {'name': 'get_current_weather',
   'arguments': '{\n  "location": "Glasgow, Scotland",\n  "format": "celsius"\n}'}},
 'finish_reason': 'function_call'}

返された関数のパラメータを元に天気を検索する外部APIを呼び出すことができる。

SQLクエリを生成

functionsにSQLクエリを実行する関数を定義する。

functions = [
    {
        "name": "ask_database",
        "description": "Use this function to answer user questions about music. Input should be a fully formed SQL query.",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": f"""
                            SQL query extracting info to answer the user's question.
                            SQL should be written using this database schema:
                            {database_schema_string}
                            The query should be returned in plain text, not in JSON.
                            """,
                }
            },
            "required": ["query"],
        },
    }
]

埋め込み変数になっている{database_schema_string}の部分には、テーブルスキーマを挿入する。
ChatGPTがテーブルスキーマを知っておくことが重要ということである。


システムプロンプトを以下のように入力する。

agent_system_message = """You are ChinookGPT, a helpful assistant who gets answers to user questions from the Chinook Music Database.
Provide as many details as possible to your users
Begin!"""

(あなたは ChinookGPT です。Chinook 音楽データベースからユーザーの質問に回答する便利なアシスタントです。
できるだけ多くの詳細をユーザーに提供します)

ユーザメッセージを以下のように入力する。

sql_conversation.add_message(
    "user", "Hi, who are the top 5 artists by number of tracks"
)

(こんにちは、トラック数のトップ 5 アーティストは誰ですか)


以下のようなクエリの関数が返却される。

{'query': 'SELECT artists.Name, COUNT(tracks.TrackId) AS num_tracks FROM artists JOIN albums ON artists.ArtistId = albums.ArtistId JOIN tracks ON albums.AlbumId = tracks.AlbumId GROUP BY artists.Name ORDER BY num_tracks DESC LIMIT 5;'}

これを元に、データベースにクエリを実行することで、データベースに基づいた回答ができる。

ただし、直接生成されたクエリを実行するとSQLインジェクションなどのセキュリティ上の問題が起きるため、SQLのパラメータのみ生成して、SQL文は別で作りこむ方がよい。

複数の関数を定義して連携する

複数の関数を定義して、連携させることができる。
例では、arXivからキーワードに該当する論文一覧を取得する関数と、取得した論文から関連が高い論文を要約する関数を定義して、先に一覧取得していない場合は、要約を行わないようにしている。

# Initiate our get_articles and read_article_and_summarize functions
arxiv_functions = [
    {
        "name": "get_articles",
        "description": """Use this function to get academic papers from arXiv to answer user questions.""",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": f"""
                            User query in JSON. Responses should be summarized and should include the article URL reference
                            """,
                }
            },
            "required": ["query"],
        },
    },
    {
        "name": "read_article_and_summarize",
        "description": """Use this function to read whole papers and provide a summary for users.
        You should NEVER call this function before get_articles has been called in the conversation.""",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": f"""
                            Description of the article in plain text based on the user's query
                            """,
                }
            },
            "required": ["query"],
        },
    }
]

(1つ目の関数の説明:ユーザーの質問に答えるために arXiv から学術論文を取得するには、この関数を使用します。
 2つ目の関数の説明:論文全体を読み、ユーザーに概要を提供するには、この機能を使用します。
         会話内で get_articles が呼び出される前に、この関数を決して呼び出さないでください。)
※ノートブックにはバグがあり、functionsが配列になっていなかったので修正している。


システムプロンプトに以下の内容を入力する。

paper_system_message = """You are arXivGPT, a helpful assistant pulls academic papers to answer user questions.
You summarize the papers clearly so the customer can decide which to read to answer their question.
You always provide the article_url and title so the user can understand the name of the paper and click through to access it.
Begin!"""
paper_conversa

(あなたは arXivGPT です。学術論文を引き出してユーザーの質問に答える役に立つアシスタントです。
顧客が質問に答えるためにどれを読めばよいかを判断できるように、論文を明確に要約します。
ユーザーが論文の名前を理解し、クリックして論文にアクセスできるように、必ずarticle_url と title を指定します。
始めよう!)

ユーザメッセージに以下の内容を入力する。

paper_conversation.add_message("user", "Hi, how does PPO reinforcement learning work?")

(こんにちは、PPO 強化学習はどのように機能しますか?)

get_articlesが返るので、記事の一覧を取得し、メッセージ履歴にroleをfunctionとしたメッセージを追加し、その際contentに取得した記事の内容を設定する。

messages.append(
    {
        "role": "function",
        "name": full_message["message"]["function_call"]["name"],
        "content": str(results),
    }

そして、会話を続けると以下のようにRead moreが論文のリンクになった論文一覧が生成される。

Here are some papers that explain how Proximal Policy Optimization (PPO) reinforcement learning works:

"Proximal Policy Optimization and its Dynamic Version for Sequence Generation" - This paper proposes using PPO for sequence generation tasks and introduces a dynamic approach for PPO. It demonstrates the efficacy of PPO in conditional sequence generation tasks. Read more

"CIM-PPO: Proximal Policy Optimization with Liu-Correntropy Induced Metric" - This article analyzes the asymmetry effect of KL divergence on PPO's objective function and introduces a new algorithm called CIM-PPO that incorporates the theory of correntropy. It compares the effectiveness of CIM-PPO with KL-PPO and Clip-PPO. Read more

"A2C is a special case of PPO" - This paper challenges the common understanding that A2C and PPO are separate algorithms and shows that A2C is actually a special case of PPO. It provides theoretical justifications and empirical experiments to support this claim. Read more

"Proximal Policy Optimization via Enhanced Exploration Efficiency" - This paper addresses the exploration ability of PPO and proposes an exploration enhancement mechanism based on uncertainty estimation. It introduces the proximal policy optimization algorithm with intrinsic exploration module (IEM-PPO) and evaluates its performance on multiple tasks. Read more

"Neural PPO-Clip Attains Global Optimality: A Hinge Loss Perspective" - This paper provides the first global convergence rate analysis of PPO-Clip under neural function approximation. It presents a reinterpretation of PPO-Clip using hinge loss and introduces a two-step policy improvement scheme for convergence analysis. Experimental results validate the approach on various RL benchmark tasks. Read more

Feel free to click on the links to access the papers for more details.


続けて、ユーザメッセージに同じ質問を入力する。

paper_conversation.add_message("user", "Hi, how does PPO reinforcement learning work?")

(こんにちは、PPO 強化学習はどのように機能しますか?)

今度は、read_article_and_summarizeが返るので、取得済みの記事一覧から返されたread_article_and_summarizeのパラメータのqueryに近いタイトルの記事を探して要約を実行する。
以下のように要約結果が得られる。

Core Argument:

The paper discusses the use of proximal policy optimization (PPO) in sequence generation tasks, specifically in the context of chit-chat chatbots.
The authors argue that PPO is a more efficient reinforcement learning algorithm compared to policy gradient, which is commonly used in these tasks.
They propose a dynamic approach for PPO (PPO-dynamic) and demonstrate its efficacy in synthetic experiments and chit-chat chatbot tasks.
Evidence:

PPO-dynamic achieves a high precision score in a synthetic counting task, comparable to other algorithms like REINFORCE and MIXER.
In the chit-chat chatbot task, PPO-dynamic achieves a slightly higher BLEU-2 score than REINFORCE and PPO.
The learning curves of PPO and PPO-dynamic are more stable than policy gradient, and PPO-dynamic converges faster.
Conclusions:

PPO is a better optimization method for sequence learning compared to policy gradient.
PPO-dynamic further improves the optimization process by dynamically adjusting the hyperparameters.
PPO can be used as a new optimization method for GAN-based sequence learning for better performance.

まとめ

Chat Completions APIに新しく追加された「Function calling」を試した。
Function callingにより、Bingチャットのようにユーザの質問文に応じて必要な場合に検索を呼び出すような処理をプロンプトエンジニアリングなしで実行できるようになる。

Bingチャットや、ChatGPT Plusのプラグインは、内部では前からこの機能を使って実装されていたのかもしれない。
APIでも同じような処理が実装できるようになったのでアプリケーションの応用範囲も広がりそうである。