実装例③ 文章を適切なカテゴリに自動分類する
以下はこちらで用意した架空の映画のレビューです。
- 心を揺さぶるストーリーで、演出が素晴らしい。演技も印象的。
- プロットが予測可能で、キャラクターに深みがない。
- 面白いアイディアだが、特別目立つわけではない。
- 独創的な脚本と美しいサウンドトラック。全体的に感動的。
- 特殊効果に頼りすぎで、物語が弱い。演技も平凡。
- 一般的なタイムトラベル物。楽しめるが、心に残らない。
- 映像が魅力的で、感情移入できるキャラクター。楽しい体験。
- 演技はまずまずだが、物語は平均的。特に印象に残らない。
- 概ね満足しているが、結末は残念だった。
これらの短文をネガティブ/ポジティブ/ニュートラルの3つのカテゴリに自動的に分類するプログラムを考えてみましょう。
プロンプトを作成する
前述のようにFunction CallingやJSONモードで分類を行うことも可能ですが、ここではあえてそのどちらも使わず、プロンプトエンジニアリングで分類を実行してみます。
prompt_template = """以下の入力文の感情を分析し、最も相応しいと思うカテゴリを一つ選んで分類してください。 # 入力文 {input} # カテゴリ [0]: Neutral [1]: Positive [2]: Negative # 出力形式 選択肢番号 # 判定結果 ["""
分類するカテゴリに番号を振って提示し、入力文の内容を踏まえて分類先として相応しいものをどれか一つを選択するよう指示しています。
こちらのプロンプトでは、最後が「#判定結果」と「[」で終わっている所がポイントです。GPTを始めとするLLMの基本的な機能は「文章の続きを予測する」というものであるため、このように中途半端な部分でプロンプトを中断すると、ChatGPTはその続きを予測しようとします。「カテゴリ」の項目で選択肢の番号を「[1]」のように記述していることを踏まえて、プロンプトの末尾が開始カッコで終わっていれば、その次に来る文字は高い確率で「番号」である事が予測できます。つまり、ここから生成される文言は「1]」や「2]」といった内容となるため、出力形式をJSONに固定しなくても簡単に選択肢番号を抽出することができます。
APIを実行する
このプロンプトを以下のようなコードで送信します。
text = """心を揺さぶるストーリーで、演出が素晴らしい。演技も印象的。""" prompt = prompt_template.format(input=text) client = OpenAI() response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{'role': 'system', 'content': prompt}], temperature=1, n=5, stop=["]"] )
ここで重要なパラメーターは以下になります。
n
こちらは、「生成結果数」を表すパラメーターです。今回「5」を指定しているので、5回分の結果を同時に取得します。テキストの感情を読み解くといったタスクでは、判断が難しいテキストが入力された場合に結果がバラつくことが懸念されますが、このように、複数回分の結果を取得して多数決を取るという手法を用いることで、判定結果の一貫性を向上させる効果あることが知られています。
結果を複数取得する場合、全ての結果が出力トークン数としてカウントされますが、今回は数字が1つ出力されるだけですので、出力数を増やしてもコストやパフォーマンスへの影響はわずかです。詳しくはドキュメントのnの解説をご覧ください。
stop
指定した文字列がトークンとして現れた時点で生成を強制終了することができます。文字列は最大4つまで指定できます。今回は閉じカッコが現れた時点で終了するようにしてあり、プロンプト末尾の開始カッコとの間にある番号だけを生成するように仕向けています。もしくは、今回の選択肢番号は全て1桁なので、「stop」の代わりに「max_tokens」というパラメーターに「1」を指定して、必ず1トークンで生成を強制終了するという方法でも同じ結果が得られるでしょう。詳しくはドキュメントのstopの解説をご覧ください。
実行結果を確認する
for i, choice in enumerate(response.choices): print("判定%d:" %(i+1), choice.message.content)
「n」パラメーターで複数結果を生成するよう指示した場合は、response.choicesの配列にそれぞれの結果が格納されています。ここまでのコードを実行して、結果を確認してみましょう。
入力テキスト:心を揺さぶるストーリーで、演出が素晴らしい。演技も印象的。
判定1: 1 判定2: 1 判定3: 1 判定4: 1 判定5: 1
こちらの入力文は明らかにポジティブな意見のため、満場一致で「1:ポジティブ」と判定されています。
入力テキスト:概ね満足しているが、結末は残念だった。
判定1: 2 判定2: 1 判定3: 2 判定4: 1 判定5: 1
このように少し判断が難しい入力文では、「1:ポジティブ」と「2:ネガディブ」で意見が割れていますが、多数決を取れば「1:ポジティブ」と判定された事になります。手元で10回ほど実行してみましたが、全てポジティブが多数となりました。このように、一回の判定ではブレが出るような問題でも、多数決をさせることで安定化を図ることができます。
以上のプログラムを使用して、最初の映画レビューを全てカテゴライズすると、以下のような結果となりました。
ポジティブ
- 心を揺さぶるストーリーで、演出が素晴らしい。演技も印象的。
- 独創的な脚本と美しいサウンドトラック。全体的に感動的。
- 映像が魅力的で、感情移入できるキャラクター。楽しい体験。
- 概ね満足しているが、結末は残念だった。
ネガティブ
- プロットが予測可能で、キャラクターに深みがない。
- 特殊効果に頼りすぎで、物語が弱い。演技も平凡。
- 演技はまずまずだが、物語は平均的。特に印象に残らない。
ニュートラル
- 面白いアイディアだが、特別目立つわけではない。
- 一般的なタイムトラベル物。楽しめるが、心に残らない。
少々判断が難しいものも含まれていますが、概ね正しく分類できていそうです。恐らく人間が手動で分類しても似たような結果となるでしょう。
このような分類を行えば、商品レビューや動画のコメントなどを効率的に分析したり、ユーザーからの問い合わせを内容に応じて自動的に担当者へ転送したりといったことが可能になります。テキスト分類は、ここで紹介したプロンプティング以外にも様々な手法が考えられますので、ぜひ目的に合うやり方を模索してみてください。
まとめ
今回の記事では、ChatGPTをチャットBot以外の利用目的で組み込むノウハウについて解説しました。このように会話という縛りを無くすことで、ChatGPT APIの活用の幅は格段に広がります。本記事の内容がChatGPTの活用に悩んでいる皆様の一助になれば幸いです。ご紹介した例はChatGPTで実現できることのほんの一部に過ぎませんので、ぜひご自身の環境に合わせて様々な使い方を試してみてください。
次回の記事では、ChatGPTからより良い回答を得るための様々なプロンプトエンジニアリングについて解説する予定です。