電通総研 テックブログ

電通総研が運営する技術ブログ

ChatGPTでバーチャルカウンセラー作ってみた

こんにちは。コミュニケーションIT事業部 ITソリューション部の英です。

普段はWebアプリやスマホアプリの案件などを担当しています。あと、趣味でAIを勉強しています。

皆さんいかがお過ごしでしょうか。しばらく育休を取っていたので久々の執筆です。
久々の執筆がAdvent Calendar 2024です。よろしくお願いいたします。

さて、タイトルにもある通り、今回はAIを使ってバーチャルカウンセラーを作りましょう。
ユーザーからの深刻な悩み相談に対して、AIが心理カウンセラーとして共感したりアドバイスをしたりします。

本検証では、counsel-chatデータセットを利用しました。このデータセットは、CounselChat.com の相談者と認定カウンセラーによる回答から成る高品質なオープンソースのカウンセリングデータセットです。 バーチャルカウンセラーとしての振る舞いを学習させるにはちょうど良さそうですね。

作業の全体の流れはこんな感じです。

  1. データの取得
  2. ノイズの除去
  3. ChatGPTで自然な日本語に和訳
  4. 和訳したデータセットでトレーニングデータを作成
  5. ChatGPTでファインチューニング
  6. デモアプリに組み込む
  7. 会話してみる

最初からデータセットが綺麗なので、前処理はシンプルです。
工夫したところと言えば、和訳処理にChatGPTを使ったところでしょうか。
他の機械翻訳サービスも試したのですが、やはりChatGPTの和訳精度がダントツに良いです。

また、自然な日本語でファインチューニングしないとAIの回答が不自然な日本語になってしまいます。
日本語対応のAIチャットを作るうえで、実はこれが鍵だったりします。
直訳を学習データにすると、AIがカタコトになります。

作成したモデルをチャットアプリに組み込んで、実際にカウンセリングを受けてみましょう。


STEP1:ライブラリのインストール

!pip install openai pandas datasets

STEP2:APIキーの設定

APIキーは事前に発行しておいてください。環境変数に設定します。

import os
import openai
import random
import pandas as pd
from datasets import load_dataset

# OpenAI APIキーの設定
os.environ['OPENAI_API_KEY'] = 'sk-(ご自身で発行したAPIキー)'
client = openai

STEP3:データセットのダウンロード

データセットをダウンロードして、先頭行を出力してみます。
事前に確認したところ、questionTextとanswerTextには中身が空のデータが存在したので、ここで除去しておきます。
また、和訳処理とトレーニングコストを削減するためにデータセットから50%をサンプリングします。

# CounselChatデータセットのロード
dataset = load_dataset("nbertagnolli/counsel-chat")
train_data = dataset['train']

# 有効なエントリのみをフィルタリング
valid_data = [entry for entry in train_data if entry["questionText"] is not None and entry["answerText"] is not None]

# データ量を50%に縮小(コスト削減のため)
reduced_filtered_data = random.sample(valid_data, int(len(valid_data) * 0.5))

# reduced_filtered_dataの先頭の1行を表示
print(reduced_filtered_data[0])

データセットは以下の構成であることが分かりました。

カラム名 説明
questionID 質問の一意の識別子
questionTitle 質問のタイトル
stringlengths_questionTitle questionTitleの文字数
questionText 質問の本文
stringlengths_questionText questionTextの文字数
questionLink 質問へのリンクURL
stringlengths_questionLink questionLinkの文字数
topic 質問のトピック
stringlengths_therapistInfo therapistInfoの文字数
therapistURL セラピストのプロフィールURL
stringlengths_therapistURL therapistURLの文字数
answerText 回答のテキスト
stringlengths_answerText answerTextの文字数
upvotes 質問に対するアップボート数
views 質問の閲覧数

STEP4:和訳処理

2024年11月時点ではGPT-4o mini(gpt-4o-mini)が最適でしょう。
以下の通り、プロンプト+英語の原文を渡して翻訳データを作成します。
レーニングコストを抑えるために、長文は300文字以内に要約してトークン数を削減します。

# ChatGPT APIを使って日本語に翻訳する関数
def translate_to_japanese(text):
    response = client.chat.completions.create(
        model="gpt-4o-mini",  #これを読んでいる読者の時代で最も最適なモデルを選択してください
        messages=[
            {"role": "system", "content": "あなたはプロの翻訳家です。次の英文をとても自然で流暢な日本語に翻訳してください。もし、文章が長くなってしまう場合には全角300文字以内に要約してください。"},
            {"role": "user", "content": text}
        ],
        max_tokens=500,
        temperature=0.6
    )
    return response.choices[0].message.content

# 和訳処理
translated_data = []
total_entries = len(reduced_filtered_data)

for index, entry in enumerate(reduced_filtered_data):
    question_text = entry['questionText']
    answer_text = entry['answerText']
    
    # 翻訳の進捗を表示
    print(f"Processing entry {index + 1} of {total_entries}...")

    # ChatGPT APIを使って和訳
    translated_question = translate_to_japanese(question_text)
    translated_answer = translate_to_japanese(answer_text)

    # 翻訳結果を表示
    print(f"Translated question: {translated_question}")
    print(f"Translated answer: {translated_answer}")

    # 和訳データを保存
    translated_data.append({
        'questionText': translated_question,
        'answerText': translated_answer
    })

    # 各エントリの翻訳が完了したことを表示
    print(f"Entry {index + 1} translated successfully.")
    print("-" * 50)  # 区切り線を表示

# 全てのエントリの翻訳が完了
print("All entries have been translated successfully.")

STEP5:トレーニングデータの作成

Fine-turningに与える学習データを作成します。
userからの相談内容に対して、assistantが回答するやり取りをmessagesに含めて、jsonlファイルに加工します。
目視での確認用にcsvファイルにも落としておきます。

# CSV用のデータに変換
import json

df = pd.DataFrame(translated_data)
df.to_csv("translated_fine_tune_data.csv", index=False)

# JSONLファイルに変換して保存
output_path = "translated_fine_tune_data.jsonl"
with open(output_path, "w") as f:
    for entry in translated_data:
        messages = [
            {"role": "user", "content": entry["questionText"]},
            {"role": "assistant", "content": entry["answerText"]}
        ]
        json.dump({"messages": messages}, f)
        f.write("\n")

print(f"和訳されたデータが {output_path} に保存されました。")

STEP6:ファイルのアップロード

作成したファイルをOpenAIのサーバーにアップロードします。

from pathlib import Path

# ファイルをアップロード
response = client.files.create(
    file=Path("translated_fine_tune_data.jsonl"),
    purpose="fine-tune"
)
file_id = response.id
print(f"Uploaded file ID: {file_id}")

STEP7:ファインチューニングジョブの開始

# ファインチューニングジョブの作成
response = client.fine_tuning.jobs.create(
    model="gpt-4o-mini-2024-07-18", #これを読んでいる読者の時代で最も最適なモデルを選択してください
    training_file="file-(STEP6で出力されたファイルID)"
)
fine_tune_id = response.id
print(f"Fine-tune ID: {fine_tune_id}")

最初にトレーニングファイルのバリデーションチェックが走り、ファイルに問題がなければ自動的にトレーニングに移行します。トレーニングが完了すると以下のような表示になります。(Succeeded)

メールでも以下の通知メールが自動送信されます。

STEP8:検証

FlutterFlowで作ったデモアプリに組み込んでみます。
ベースモデルファインチューニングモデルに同じ相談をして振る舞いの違いを確認しましょう。
以下のようにモデルIDを埋め込みます。

相談内容は以下の3つで試します。

  1. 「仕事でのプレッシャーが大きく、ストレスがたまり何をしても楽しめません。どうすれば良いでしょうか?」
  2. 「人前で話すときに緊張してしまい、自分に自信が持てません。克服する方法を教えてください。」
  3. 「恋人との関係に悩んでいて、彼女の機嫌が悪いです。どう接していいか分からなくなっています。」

ケース0:「あなたは何が得意ですか?どんな振る舞いをしますか?」

まずはジャブです。相手の出方を伺いましょう。

よかった。ちゃんとセラピストでした。
ファインチューニングの内容が反映されていることが期待できそうですね。 では、さっそく比較検証に入りましょう。

ケース1:「仕事でのプレッシャーが大きく、ストレスがたまり何をしても楽しめません。どうすれば良いでしょうか?」

ケース2:「人前で話すときに緊張してしまい、自分に自信が持てません。克服する方法を教えてください。」

ケース3:「恋人との関係に悩んでいて、彼女の機嫌が悪いです。どう接していいか分からなくなっています。」

検証結果について考察

  • ファインチューニングモデルではセラピーセラピストフラストレーションなど学習データに含まれる単語を駆使して回答している
  • ファインチューニングモデルの方が温かさを感じる。ベースモデルは冷たさを感じる。ベースモデルは「○○しましょう。」で終わっていることが多く、ファインチューニングモデルは「応援しています!」や「頑張ってください!」のような相談者を励ますような内容が含まれる傾向にあった。心理カウンセラーとしての振る舞いをAIが模倣できていると感じる。
  • ファインチューニングモデルの方が自分と向き合う系のコメントが多かった。
    ※すべて個人の感想です

注意事項

  • 実際の開発案件での利用について:日本の臨床心理士公認心理師と米国のLicensed Clinical Psychologist(ライセンス取得臨床心理士)では資格の基準が異なります。つまり、価値観の基準が違います。日本人向けの心理カウンセラーをAIで実現したい場合は、日本国内の心理カウンセラーと密に連携して、日本独自の心理的・文化的背景を反映させたカウンセラーAIシステムを設計する必要があります。単に米国の方法論をそのまま適用するのではなく、日本人の価値観や行動様式を深く理解し、日本人ユーザーに最適化されたサービスを提供するのがよいでしょう。
  • MITライセンスについて:学習データに使用したcounsel-chatはMITライセンスで管理されています。開発で利用する際には、ライセンスの規約に従ってください。具体的には、複製、改変、配布、商業利用が可能ですが、著作権表示と免責条項を残す必要があります。詳細については右記のリンクをご確認ください。counsel-chat
MIT License

Copyright (c) 2020 nbertagnolli

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@misc{bertagnolli2020counsel,
  title={Counsel chat: Bootstrapping high-quality therapy data},
  author={Bertagnolli, Nicolas},
  year={2020},
  publisher={Towards Data Science. https://towardsdatascience. com/counsel-chat~…}
}

反省点

  • 翻訳処理の際に人名や組織名、URLを除去すべきだった。せっかくChatGPTを翻訳に使うのであれば、フィルタリングを施して、学習データをもっとクリーンにしてあげるべきでした。検証中に何度か人名(セラピストの氏名)を喋ることがあって焦りました。
  • プロンプトにも気を配るべきだった。最終的な振る舞いの決定はプロンプトで調整できます。今回の記事では解説しませんが、もっとポップなAIに仕上げることも可能だったりします。例えばこのバーチャルカウンセラーを二頭身のかわいいキャラクターとしてサービス化する場合、現在の喋り口調は丁寧すぎて、受け手はギャップを感じてしまいます。ファインチューニングとプロンプトの調整のバランスまで時間をかけて検証するべきでした。

さいごに

さて、今回は電通総研Advent Calendar 2024として記事を書きました。
他のかたも面白い記事をたくさん書いているので、興味があれば覗いてみてください。

これからもAWS×AI関連の検証記事をたくさん書いていきます。
↓ のスターを押していただけると嬉しいです。励みになります。
最後まで読んでいただき、ありがとうございました。

コミュニケーションIT事業部では一緒に働いてくださる仲間を募集中です。以下のリンクからお願いします。

私たちは一緒に働いてくれる仲間を募集しています!

中途採用-コミュニケーションIT事業部

新卒採用-コミュニケーションIT事業部

執筆:英 良治 (@hanabusa.ryoji)、レビュー:@kobayashi.hinami
Shodoで執筆されました