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!