TENTIALのテックブログ

株式会社TENTIALのエンジニアチームが開発や組織のよもやまを謳っていきます

GPT-3.5-turboを利用してアンケートのラベリング機能を実装しました

はじめに

TENTIALのテックチームに所属しています薮野(@yb3)です。

ここ数週間GPT周りのテクノロジーの進歩が凄まじく、TENTIALでもこの技術を利用した業務改善や新たなアプリケーションの実装を、テックチームに限らずマーケティングやセールスでもこの技術を活用した取り組みが検討されています。

購入後アンケートの分析は、顧客の意見やニーズを把握するために重要なプロセスですが、今までは自動化に伴う高い開発コストや精度の問題から実装を見送り、手動のラベリングを行なっていました。

まずGPTで実現できることを確認する意味で、今まで工数の問題で行うことができなかった購入後アンケートにおける購入理由のテキストを、GPTに読み込ませ、あらかじめ指定したラベルのうちから適切なラベルをアンケートに付与する機能を実装しました。

GPT-3.5-turboのAPIについて

概要

GPT-3.5-turboは、OpenAIが開発したGPT-3シリーズの最新の大規模言語モデルの一つです。GPT-3シリーズは、広範なトピックやタスクに対応する自然言語処理(NLP)モデルで、GPT-3.5-turboはその中でも高い性能とコスト効率を兼ね備えています。 GPT-3.5-turboは、学習データが2021年9月までのものであるため、それ以降の情報やイベントについては知らないことに注意が必要です。

APIの利用方法

GPT-3.5-turboのAPIは、OpenAIの公式のライブラリを利用してアクセスできます。Pythonを使用した場合の基本的な利用方法は以下の通りです。

まず、OpenAI Pythonライブラリをインストールします。

pip install openai

次に、APIキーを設定します。環境変数を利用するか、直接コード内に記述することができます。

import openai

openai.api_key = "your-api-key"

APIを呼び出すには、以下のようにopenai.ChatCompletion.create()関数を使用します。

messages = [
    {
        "role": "system",
        "content": """
        ここにgpt-3.5-turboに事前に指示するテキストを入力します。今回の実装ではここに用意したラベルや、そのラベルが適用される条件を指定します。
        ```
        """
    },
    {
        "role": "user",
        "content": "ユーザーアンケートの内容です",
    },
]

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=messages,
)

アンケートのラベリング機能の実装

まず、購入理由をカテゴリ分けするためのラベルを定義します。ここではラベルとそのラベルになる条件を指定した以下の7つのラベルを用意しました

購入理由-プレゼント: 贈答用として購入する場合
購入理由-効果・機能: 商品の機能や効果が重要な購入理由として挙げられた場合
購入理由-リピート: 過去に購入したことがある商品を再度購入する場合
購入理由-使用感: 商品の使用感が重要な購入理由として挙げられた場合
その他: 該当するラベルが存在しない場合やエラーの場合

このラベルを使用し、role: systemのメッセージとして入力を与えて実際にラベリングを実行してみます。

request_texts = [
    "パートナーにプレゼントしたくて購入しました。一緒に自分のも。",
    "リピートです。履き心地が良くてお気に入り!",
    "疲れが取れ、良い睡眠と言う事で購入しました。",
]

for request_text in request_texts:
    messages = [
        {
            "role": "system",
            "content": """
            あなたは株式会社TENTIALのECサイトで購入後におこなっているアンケートで回答してもらった購入理由に対してラベルを付与する役割があります。
            
            ```
            アンケートの内容【お客様のアンケートの内容】
            ```

            という形式で文字列を提供するので

            ```
            【お客様のアンケートの内容】
            ```

            にあたる文字列を読み、ラベルを適切な数だけ考えてください

            ラベルの選択肢は
            * ラベル名:ラベルを付与する条件
            の形式で提供するのでこの中から選択してください

            ```
            購入理由-プレゼント: 贈答用として購入する場合
            購入理由-効果・機能: 商品の機能や効果が重要な購入理由として挙げられた場合
            購入理由-リピート: 過去に購入したことがある商品を再度購入する場合
            購入理由-使用感: 商品の使用感が重要な購入理由として挙げられた場合
            ```

            返答は以下の形式で必ず行います。これ以外の形式は一切認めません。
            ```
            ラベル: [ラベル名,ラベル名,ラベル名]
            ```
            """,
        },
        {
            "role": "user",
            "content": """アンケートの内容【{}】""".format(request_text),
        },
    ]
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages,
    )
    answer = response["choices"][0]["message"]["content"]
    print(answer)
ラベル: [購入理由-プレゼント]
ラベル: [購入理由-リピート, 購入理由-使用感]
ラベル: [購入理由-効果・機能]

おおむね大丈夫そうです。弊社ではデータウェアハウスにBigQueryを使用しているので、判定したデータでBigQueryを更新して分析を行えるようにしました。

上手くアプリケーションとして組み込むための工夫

期待したフォーマットの返答をしてくれないことがたまにある

返答は以下の形式で必ず行います。これ以外の形式は一切認めません。

このプロンプトで返答するフォーマットを指定しているものの、たまに全然違うフォーマットで返答してくることがあります。 これに関しては返答からラベルを抽出する方法を工夫することで対応しています。

label_array = [
    ["購入理由-効果・機能", "商品の機能や効果が重要な購入理由として挙げられた場合"],
    ["購入理由-使用感", "商品の使用感が重要な購入理由として挙げられた場合"],
    ["購入理由-リピート", "過去に購入したことがある商品を再度購入する場合"],
    ["購入理由-プレゼント", "贈答用として購入する場合"],
]

def get_labels():
    labels = []
    for label in label_array:
        labels.append(label[0])

    return labels


# 正規表現で一致するものを抽出する
def search_labels(answer):
    labels = get_labels()

    matches = []
    for label in labels:
        pattern = re.compile(label)
        if pattern.search(answer):
            matches.append(label)

    return matches

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=messages,
)
answer = response["choices"][0]["message"]["content"]

result = search_labels(answer)

ただこれでも100%漏れなく抽出できるわけではないので、そもそもこのラベリング自体が100%ではないんだなという認識で運用しています。

読ませるテキストによってはラベリングを行わないことがある

  ```
  アンケートの内容【お客様のアンケートの内容】
  ```

  という形式で文字列を提供するので

  ```
  【お客様のアンケートの内容】
  ```

  にあたる文字列を読み

このプロンプトは最初はなくお客様のアンケートの内容をそのまま入力として渡し、返答させていました。 ですが、入力フォーマットを指定しない場合に例えば「早く発送してください」のような命令形の入力があると、ラベリングを行わずに命令文に対する返答を行うことが度々ありました。 これに対してプロンプトで入力フォーマットを指定するとかなり改善されました。

GPT-3.5-turboをラベリングシステムに使用してみた感想

これだけのコード量と実装時間(1日程度)でラベリングシステムの実装が完了するのはかなり魅力的だなと感じました。今回のラベリングシステムと同様に工数や実装時間と照らし合わせるとコストパフォーマンスの観点で実装を見送っていたような開発はOpenAIのGPT系のAPIを使用することにより解決でき、AI/MLのMVPをクイックに開発するような使い方ではとても有用に感じました。

一方で万能ではなく、想定した挙動をしないことも多々あると感じたので、そもそも100%の動作を期待していない場面で使ったり、実装側で工夫するなど人間側の歩み寄りが大事だなと感じました。

CTO(@Hey_icchiman)ともテックチーム以外も巻き込んで社内全体で使っていき、オペレーションスピードをあげることで、身体を充電するツールをより早く、質高くお客様に届けられるようにしたいです。

www.wantedly.com