1. はじめに
こんにちは、スキマスイッチ大好き後藤です。
アプリの改善や新しい機能の提案を行う際、各画面の使用状況を把握することは重要です。
なぜなら具体的な利用データに基づいて効果的な改善策を考えることができるからです。
私が開発している音楽アプリでは、ユーザが特定の画面を開くたびに、その画面固有のID(以下、screenId)をGoogle Analyticsに送信しています。
例えば、歌詞画面が開かれると、lyricというscreenIdをGoogle Analyticsに送信します。
一般的に、Google Analyticsに蓄積したデータはBigQueryを使って解析され、ユーザの行動分析などを通じてサービスの改善に役立てられます。
特に、screenIdのデータを集計することで、各画面の使用率を求めることができます。
しかし、画面使用率を求めるためには一定レベルのSQLの知識が必要であったり、手軽に求めることができないという問題がありました。
そこで、この問題を解決するためのアプローチとしてOpenAI社が提供しているFunction callingを使用しました。
以下が今回作成しようと思ったものの処理の流れです。
1. ユーザが「1ヶ月間の〇〇画面の利用状況を知りたい」と入力する
2. Function callingがこの入力を解析し、予め定義したSQLを実行する関数の引数を生成する
3. 引数に基づいて関数を実行し、抽出したデータを表示する
本記事では、この中で特に2の部分に焦点を当てて説明します。
2. Function callingとは
Function callingは、ユーザの自然言語の入力から、使用する関数を選択し、引数を適切に作成するものです。
これにより、ユーザの意図を自動的に理解し、プログラムの適切な機能を実行できます。
具体的な例を1つ紹介します。例えば、以下のような関数が事前に定義されているとします。
- send_email(宛先, 内容)
- register_schedule(日程, 場所)
- update_profile(名前, 画像)
ユーザが「今日の18:00にジムに行くと登録して」と入力した際、Function callingはこれを解析します。
そして、register_schedule(日程, 場所)という関数が最も適切であると判断します。
その後、日程にその日が2023年の8月8日なら「2023/08/08 18:00」、場所に「ジム」が引数として作成されます。
3. Function callingの実装
本セクションではFunction callingで使用したプロンプトや関数の定義を紹介します。
使用したGPTのバージョンはgpt-4-0613です。
以下のプロンプトを用いて、ユーザの入力をもとに適切なscreenIdや期間(以下、span)を生成しました。
screenIdとspanは定義したSQLを実行するために使用され、その期間の画面使用率を算出します。
#命令書 ユーザの入力から適切なscreenIdとspanを生成します。次の制約条件に従い、対応する答えを出力してください。 #制約条件 ・存在しないScreenIdが生成された場合は、再入力を求めること。 ・複数の画面が入力された場合、具体的な画面名を再確認すること。 ・spanの上限値は180とすること。 |
具体的な関数の定義例として、ある画面に関連するscreenIdとspanを生成する関数を以下に示します。
propertiesには、screen_idとspanを設定しています。
spanは、1週間なら7、1ヶ月なら30と変換できるようにpropertiesのdescriptionを定義しました。
{ "name": "make_〇〇_screen_id", // 関数名 "description": "特典画面に関する入力された日本語から意味が最も近しい次のscreenIdの定義を選択する。screenIdの定義: 〇〇_list, 〇〇_detail, 〇〇_image_viewer", // 関数自体の説明 "parameters": { // 関数の引数を定義する。今回はscreenIdとspanを設定する "type": "object", "properties": { "screen_id": { "type": "string", "description": "screenIdは日本語ではなく英語で定義する。", // 引数の説明 }, "span": { "type": "string", "description": "期間を定義する。単位は1日単位とする。X月からのような意味の場合、現在の日付との差分の日数を設定する。例えば、2023/07/27で5月からとされた場合、7/27と5/1の差分の日数を設定する。 ただし最大は180日とし、180日を超える場合は180と定義すること。" // 引数の説明 } }, "required": ["screen_id"], }, } |
上記のような関数定義をアプリ内の画面の種類ごと(ライブラリ画面や検索画面など)に複数用意しました。
1つにまとめるのではなく、複数用意することで引数の精度を向上させることができました。
4. 実行結果
Function callingの導入により、ユーザの入力からscreenIdやspanを精度高く取得することができるようになりました。
以下に、入力と取得した引数の例を紹介します。
– 直近1週間のホーム画面 →
screenId: home, span: 7
– ここ二ヶ月のプレイリスト詳細画面 →
screenId: detail_playlist, span: 60
– 3週間分の検索画面 →
screenId: search, span: 21
具体的な画面使用率の数値については割愛しますが、上述の取得結果を基にSQLクエリを実行することで、それぞれの画面の使用率を算出することができました。
さらに、Function callingは例外処理にも優れており、ユーザからの不明確な入力や存在しない画面名(課金画面)に対しても適切なフィードバックを提供することができます。具体例は以下の通りです。
- プレイヤー画面とビデオ画面 → あなたが「プレイヤー画面」と「ビデオ画面」のどちらを指しているかはっきりしないので、もっと具体的に説明していただけますか。
- 課金画面 → 申し訳ありませんが、現在用意されているScreenIdには「課金画面」に該当するものが存在しません。他にお求めの画面名はありますか?
5. うまくいかなかったこと
実装していく中でうまく行かないことが3点ありました。
1つ目は、GPT-3.5-turbo-0613の問題点です。
gpt-3.5-turbo-0613を利用した際に、screenIdの値が自動的に日本語に変換される問題がありました。
プロンプトを修正し、「screenIdは英語で生成すること」という条件を追加しましたが、効果はありませんでした。
この問題については、screenIdの制約条件をより詳細に設定する必要があると考えています。
2つ目は、関数定義のdescriptionの文字数制約です。
関数定義の際のdescriptionには文字数制限があるようで、約1000文字を超えるとエラーが発生します。
この制限に対応するため、関数を分割するなどの対策を行いました。
3つ目は、期間の引数のspanの制約が正確に機能しておらず、指定よりも長い期間が出力されることです。
「最大は180日とし、180日を超える場合は180にすること。」と定義していますが、「ここ一年」と入力すると365と出力されてしまいました。
この問題は、「spanが180以上の場合、spanを180に修正する」というバリデーションをコードに追加することで、予期せぬ値が設定されるのを防ぎました。
6. まとめと感想
Function callingの導入により、画面名と期間を引数に持つ関数を定義するだけで、適切な引数を自動生成することが可能となりました。
また、制約条件の指定によって例外処理も実装することができました。
制約が完全には機能していない点もありましたが、これは関数定義の工夫やハンドリングによって十分対処可能でした。
自然言語から処理が行えるこの機能は非常に便利であり、今後もFunction callingを用いてさまざまな自動化が可能なものを探していきたいと思います。
また、現在の実装はいつでも誰でも実行できる状態ではないため、SlackBotのようなツールを組み合わせて、ユーザが直接入力を行い、リアルタイムで画面使用率を確認できる状態を目標にしています。
本記事の内容がFunction callingを活用する上での参考になれば幸いです。