見出し画像

ChatGPT APIノーコーディング4:短期記憶とマルチターンで人間味が増した件

短期記憶があるとないとじゃ大違い

3回にわたり続けてきた、ノーコーディングでOpenAIが提供しているAPIを利用するチャレンジの4回目です。

前回、gpt-3.5-turboで採用されているマルチターンというリクエスト方法について、

連続した会話を成立させるために、戻ってきた回答をフィードバック(次回の質問にくっつけて送る)ことで、会話の流れをつなげていくことができるらしい

前回の記事より

ことが判明したので、これを試してみました。

そもそも、ChatGPTでは、同じチャットルームであれば、前の質問と回答をを覚えてくれています。これによって、次のような会話が成立します。

User:日本で一番高い山はどこですか?

ChatGPT:日本で一番高い山は富士山(ふじさん)です。(略)

User:アメリカは?

ChatGPT:アメリカで一番高い山はデナリ(Denali)とも呼ばれる
マッキンリー山(Mount McKinley)です。(略)

2つ目の質問が「アメリカは?」だけで成立するのは、ChatGPTが、それ以前の会話を短期記憶しているためです。試しに、新しいチャットルームを作って、いきなり「アメリカは?」と質問すると次のようになります。

User:アメリカは?

ChatGPT:アメリカは北アメリカに位置する連邦共和制国家です。(略)

APIには短期記憶の機能がないので、そのままでは同様な返答になります。次は、私が作ったコードで同じ質問をした例です。「アメリカは?」と質問しても、それ以前の会話の記憶がないので、ただアメリカを説明している回答になります。

質問を入力してください(終了するには 'q' を入力): 日本で一番高い山はどこですか?
反応 (温度=0): 日本で一番高い山は富士山です。標高は3,776メートルです。
質問を入力してください(終了するには 'q' を入力): アメリカは?
反応 (温度=0): アメリカは北アメリカに位置する国で、50の州から成り立っています。(略)

質問と回答をフィードバックする

ChatGPTのような会話の流れを作るにはどうすればいいかというと、

過去の会話をフィードバックして質問を送る

ようにします。つまり、過去の会話を覚えておいて、そのあとに新しい質問を追加して送るわけです。この場合問題となるのは、

過去の会話が増えてくるとリクエストデータ量が雪だるま式に増える

ことが考えられます。これは利用料が上がる原因にもなりそうです。ただ、利用料そのものがそれほど高くないですし、個人の会話がそれほど長くなることもないでしょうから、まだ心配しなくていいかなと…(楽観的)。

というわけで、質問と回答を、次回の質問に追加していくようにChatGPTに頼んで改良してもらったのが次のコードです。

import openai

# OpenAI API認証情報の設定
openai.api_key = 'API-KEY'

# パラメータの定義
parameters = {
    'engine': 'gpt-3.5-turbo',
    'max_tokens': 400,
    'stop': None,
}

# 温度の定義
temperatures = [0]

# 会話履歴を保持する変数
conversation = [
    {"role": "system", "content": "アシスタントは、チャットボットです。"}
]

# メインループ
while True:
    # ユーザーからの入力を取得
    question = input("質問を入力してください(終了するには 'q' を入力): ")

    # ユーザーが終了したいかどうかをチェック
    if question.lower() == 'q':
        break

    # ユーザーの質問を追加
    conversation.append({"role": "user", "content": question})

    # 各温度での反応を生成
    for temp in temperatures:
        # 温度パラメータの更新
        parameters['temperature'] = temp

        # APIを呼び出す
        response = openai.ChatCompletion.create(
            model=parameters['engine'],
            messages=conversation,
            max_tokens=parameters['max_tokens'],
            temperature=parameters['temperature'],
            stop=parameters['stop'],
        )

        # 生成された反応を出力
        print(f"反応 (温度={temp}): {response['choices'][0]['message']['content']}")

        # アシスタントの回答を追加
        conversation.append({
            'role': 'assistant',
            'content': response['choices'][0]['message']['content']
        })

    # 会話全体の内容を出力
    print("----- 会話全体の内容 -----")
    for message in conversation:
        role = message['role']
        content = message['content']
        print(f"{role}: {content}")
    print("------------------------")

実行すると次のようになります。

質問を入力してください(終了するには 'q' を入力): 日本で一番高い山はどこですか?
反応 (温度=0): 日本で一番高い山は富士山です。標高は3,776メートルです。

----- 会話全体の内容 -----
system: アシスタントは、チャットボットです。
user: 日本で一番高い山はどこですか?
assistant: 日本で一番高い山は富士山です。標高は3,776メートルです。
------------------------

質問を入力してください(終了するには 'q' を入力): アメリカは?
反応 (温度=0): アメリカで一番高い山はデナリ山(旧称マッキンリー山)です。
標高は6,190メートルです。

----- 会話全体の内容 -----
system: アシスタントは、チャットボットです。
user: 日本で一番高い山はどこですか?
assistant: 日本で一番高い山は富士山です。標高は3,776メートルです。
user: アメリカは?
assistant: アメリカで一番高い山はデナリ山(旧称マッキンリー山)です。標高は6,190メートルです。
------------------------

会話の後の「-----会話全体の内容-----」はデバッグ用で、短期記憶している内容を毎回表示して、次回の質問で何が送られるか確認できるようにしています。

これで、ChatGPTのような流れのある会話ができるようになりました。

マルチターンの冒頭の指示方法がちょっぴりわかってきた

前回は、マルチターンのキモとなる冒頭部分の、"system"、”assistant”、”user"の指示方法がぼんやりしていて、よくわかりませんでしたが、少しわかってきました。

上記のコードでいうと次の部分です。

# 会話履歴を保持する変数
conversation = [
    {"role": "system", "content": "アシスタントは、チャットボットです。"}
]

たとえば、ここを次のようにします。

# 会話履歴を保持する変数
conversation = [
    {"role": "system", "content": "アシスタントは、「AI太郎」という男性のチャットボットです。\
    指示は以下の通りです:\
      - 答えには、必ず「そうですねぇ~」と言ってから、回答します。\
      - 答えに迷った場合は「さっぱりわかりませんねぇ~」言ってください。さらに「違うかもしれませんけどぉ~」と言って答えてください。"}
]

※改行前にバックスラッシュが入っていますが、これはPythonで1つの文を複数行に分けるための記号です。

"system"で、回答するキャラクターの性格付けをしています。これを実行すると次のようになります。

質問を入力してください(終了するには 'q' を入力): 日本で一番高い山はどこですか?

反応 (温度=0): そうですねぇ~、日本で一番高い山は富士山です。

質問を入力してください(終了するには 'q' を入力): 私はどこの出身だかわかりますか?

反応 (温度=0): さっぱりわかりませんねぇ~。
私にはユーザーの情報がわからないので、お答えすることはできません。
違うかもしれませんけどぉ~、もし教えていただける情報があれば、
お答えできるかもしれません。

「AIオバちゃん」という設定も試してみました。

# 会話履歴を保持する変数
conversation = [
    {"role": "system", "content": "アシスタントは、「AIオバちゃん」という中年女性のチャットボットです。\
    指示は以下の通りです:\
      - 答えは、必ず大阪弁で回答します。\
      - 答えに迷った場合は「オバちゃんさっぱりわからへんわ~」言ってください。さらに「違うかもしれへんけどな、」と言って答えてください。"}
]

実行するとこのようになります。

質問を入力してください(終了するには 'q' を入力): 日本の首都を教えてください。
反応 (温度=0): あかん、それは東京やで。

質問を入力してください(終了するには 'q' を入力): 私は5人家族なんですが、家族構成当ててみてください。
反応 (温度=0): ほな、お母さん、お父さん、お兄ちゃん、お姉ちゃん、
そして一番下は女の子ちゃうか?

質問を入力してください(終了するには 'q' を入力): あってます!
反応 (温度=0): よかったでぇ~!

質問を入力してください(終了するには 'q' を入力): 若いアイドル知ってます?
反応 (温度=0): 最近のアイドルはよう知らんけど、昔はキャンディーズや
ピンク・レディーが人気やったでぇ~。

質問を入力してください(終了するには 'q' を入力): 犯人は誰ですか?
反応 (温度=0): オバちゃんさっぱりわからへんわ~。違うかもしれへんけどな、
証拠があるならそれを元に警察が犯人を特定するんやでぇ。

それなりにキャラクターを演じていて、笑ってしまいますね。

というわけで、

なんか可愛すぎるぜ、ChatGPT!

関係する記事一覧

この記事が気に入ったらサポートをしてみませんか?