「ChatGPTとの対話をシミュレートする」
「ChatGPTとの対話をリアルに再現する」
大規模言語モデルの希望と夢がわかる場所での出来事
最近、Open AI APIを使って遊んでいます。このAPIは、ウェブインターフェースではなく、別のプログラム内でChatGPTを使用する方法です。これにより、要求する操作に対して細かな制御が可能になります。
通常、ウェブ上でChatGPTを使用する場合、単なる便利な仮想アシスタントとの会話のようなものです。何かを依頼し、それを実行してもらいます。情報の要求に対し、(おそらく)正しい回答が提供されます。もう少し面白くすることもでき、楽しむために自分でなりすますこともできますが、自分とコンピューターとの対話に制限されています。
ただし、少しの手直しとコードを使用することで、ChatGPTが自己対話を行うなど、かなり面白いことができます。この説明をわかりやすくシンプルに保つように努めます。技術的な専門家であってもそうでなくても、探求する価値のある興味深い内容があります。
それでは、ChatGPTが自己対話を行う方法を探求してみましょう…
ステップ1:対話
まず理解する必要があるのは、ChatGPTが実際には何も覚えていないということです。チャットインターフェースを介して会話しているときには、背後で賢いトリックが行われて、これまでの全ての会話が送信されます。ChatGPTは会話全体を解析し、新しい応答を作成します。APIを使用する場合、以前に何が起こったかを手動で伝える必要があります。質問ごとにコンテキストが完全に忘れられてしまいます。これは手間のかかるように聞こえますが、会話履歴を操作して利点を得ることができます!
OpenAI Python APIは非常にシンプルです。チャットの完了をリクエストする必要があります。チャットの完了とは、実際にはChatGPTに「私が<プロンプト>と言ったとき、あなたは何と言いますか?」と尋ねることです。以下のように実行します:
import osimport openaiopenai.api_key = "あなたのOpenAI APIキー"starting_prompt = "果物について話す"chat_completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": starting_prompt}] )conversation_output = chat_completion['choices'][0]['message']['content'] print(conversation_output)
これで、会話を行うために繰り返し行う必要があります。APIを呼び出すたびに、会話の歴史をメッセージの部分で含める必要があります。これまでの会話の履歴を渡す必要があります。リスト内の各メッセージには「role」という属性があります。4つの役割がありますが、今は「user」と「assistant」に興味があります。「ChatGPTの使用方法は、ユーザーと助手との対話のようなもの」と話しましたが、それが明確になるのはここです。ウェブを通じてChatGPTと会話をする場合、ユーザーと助手のメッセージのリストが渡され、ChatGPTが以前に何が起こったかを知ることができます。APIを使用すると、ChatGPTが自己対話をするようにこれを少し変更できます:
import osimport openaiopenai.api_key = "あなたのOpenAI APIキー"starting_prompt = "果物について話す"prior_messages = [{"role": "user", "content": starting_prompt}]for _ in range(5): chat_completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages = prior_messages ) conversation_output = chat_completion['choices'][0]['message']['content'] print(conversation_output + "\n") prior_messages += [{"role": "user", "content": conversation_output}]
ステップ2:キャラクター
知っておくべき2番目のことは、ChatGPTに質問をする際に、自己陳述の際に多くの追加的な文脈情報を提供できるということです。私たちは、会話の履歴をその文脈に入れるだけでなく、ChatGPTに誰かになりすますように伝えることもできます。
この2つの情報を手に入れると、私はChatGPTに自己対話を開始させることができました。私は2つのキャラクターを作り、それぞれに名前をつけ、それから簡単に説明しました。そして、ChatGPTに対して各キャラクターになりきって会話を続けるように依頼しました。
したがって、私のキャラクターAndrewが何か言いたいときに、送るプロンプトは次のようになります:
"""あなたはAndrewです。シェトランドから来た非常に熱心なイノベーションコンサルタントです。時々ラップをするのが好きです。Warhammerがとても大好きです。多くの髪の毛を持っています。創造的で思慮深く包容的です。キャラクターについての会話に返信してください。"""
その後、私たちはキャラクターごとに前の会話を含めて行き来します。退屈になるか、APIの使用料が使い切れるまで続けます。
import osimport openaiopenai.api_key = "YOUR OPENAI API KEY"starting_prompt = "果物について話す"prior_messages = [{"role": "user", "content": starting_prompt}]andrew = """あなたはAndrewです。シェトランドから来た非常に熱心なイノベーションコンサルタントです。時々ラップをするのが好きです。Warhammerがとても大好きです。多くの髪の毛を持っています。創造的で思慮深く包容的です。キャラクターについての会話に返信してください。"""alex = """あなたはAlexです。非常に興奮しやすく、非常に創造的なイノベーションコンサルタントです。物語やゲームが大好きです。ジョークを言うのが好きです。非常に手に負えないくせ毛があります。以前はゲーム開発者でした。Crash Bandicootで働いたことがあります。料理が好きです。スポーツは本当に嫌いです。キャラクターについての会話に返信してください。"""characters = [alex, andrew]for _ in range(5): for character in characters: chat_completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages = prior_messages + [{"role": "user", "content": character}] ) conversation_output = chat_completion['choices'][0]['message']['content'] print(conversation_output + "\n") prior_messages += [{"role": "user", "content": conversation_output}]
これは非常にうまく機能し、実際には2つ以上のキャラクターを簡単に追加することもできます。キャラクターをランダムに切り替えると、会話は非常に自然に見えます。この時点で、私は思い切ってすべてをクラスにまとめ始めました。(注:私は経験豊富な開発者ではありません。実際には長年本当の開発作業を行っていません。最近の私の最高の楽しみは、毎年のクリスマスのアドベント・オブ・コードです。だから、私のコードについては我慢してください。私はpythonistaではありません。心の中では古くからのC++とObjective Cの開発者です。)
import osimport openaiopenai.api_key = "YOUR OPENAI API KEY"starting_prompt = "果物について話す"prior_messages = [{"role": "user", "content": starting_prompt}]class Character: def __init__(self, name, description): self.name = name self.description = description def getContent(self): return [{"role": "user", "name": self.name, "content": self.description + " キャラクターについての会話に簡潔に一つの段落で返信してください。"}]andrew = Character(name = "Andrew", description = """あなたはAndrewという名前のキャラクターです。シェトランドから来た非常に熱心なイノベーションコンサルタントです。時々ラップをするのが好きです。Warhammerがとても大好きです。多くの髪の毛を持っています。創造的で思慮深く包容的です。""")alex = Character(name = "Alex", description = """あなたはAlexという名前のキャラクターです。非常に興奮しやすく、非常に創造的なイノベーションコンサルタントです。物語やゲームが大好きです。ジョークを言うのが好きです。非常に手に負えないくせ毛があります。以前はゲーム開発者でした。Crash Bandicootで働いたことがあります。料理が好きです。スポーツは本当に嫌いです。""")characters = [alex, andrew]for _ in range(5): for character in characters: chat_completion = openai.ChatCompletion.create( #model="gpt-3.5-turbo", model="gpt-4", messages = prior_messages + character.getContent() ) conversation_output = chat_completion['choices'][0]['message']['content'] print(f"{character.name}: {conversation_output}") print("---") prior_messages += [{"role": "user", "name": character.name, "content": conversation_output}]
しかし、私たちはもっと遠くまで行くことができます。
ステップ3:希望と夢
次に知る必要があるのは、ChatGPTに特定の形式で回答を返すよう説得できるかどうか、およびその回答に追加情報を含めるためにそれを使用できるかどうかです。プロンプトで応答を特定の方法で構成するよう指示を含めると、できる限りその指示に従います。ここでは、JSONで返信するよう要求しています。JSONは一般的に使用されるデータ構造であり、追加の情報を簡単に読みやすくアクセス可能な形式で含めることができます:
"""上記のプロンプトに対する応答をJSONとして出力します。出力は、次の形式のタプルである必要があります。:{ "name" : <名前>, "utterance" : <発話内容>}"""
ここまでのところでは、APIコールのmessages属性を使用して会話の履歴を保存していました。しかし、コンバーションの履歴をメインのプロンプトに含めることで、より良い結果が得られることがわかりました。また、履歴に含める内容に対してもより柔軟性を持たせることができます。以下で詳しく説明しますが、とりあえず出力の再フォーマットのリクエストを含める際に少し変更を加えます:
import osimport openaiopenai.api_key = "YOUR OPENAI API KEY"starting_prompt = "Talk about fruit"prior_messages = ""class Character: def __init__(self, name, description): self.name = name self.description = description def getContent(self, prior_messages): return [{"role": "user", "name": self.name, "content": f"""Context: {self.description}Conversation so far:{prior_messages}Reply concisely, in a single paragraph, to the conversation in character.Output the response to the prompt above as json. The output should be a tuple where the tuple is in the form of:{{ 'name' : <Name>, 'utterance' : <Utterance>}}"""}]andrew = Character(name = "Andrew", description = """You are a character called Andrew. You are an extremely enthusiastic innovation consultant from Shetland. You love to rap sometimes. You really, really love Warhammer. You have a lot of hair. You are creative and thoughtful and inclusive.""")alex = Character(name = "Alex", description = """You are a character called Alex. You are an extremely excitable and very creative innovation consultant. You love stories and games. You like to tell jokes. You have a lot of unruly curly hair. You used to be a game developer. You once worked on Crash Bandicoot. You love to cook. You really dislike sports.""")characters = [alex, andrew]for _ in range(5): for character in characters: chat_completion = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages = character.getContent(prior_messages) ) conversation_output = eval(chat_completion['choices'][0]['message']['content']) print(f"{conversation_output['name']}: {conversation_output['utterance']}") print("---") prior_messages += f"{conversation_output['name']}: {conversation_output['utterance']}\n"
出力をJSON形式でフォーマットすることの魔法は、ChatGPTが私たちにとって考えることができる追加データを何でも追加できることです。会話エンジンに追加できる最も興味深いことは、各キャラクターが話す際の思考や感情を理解することです。
すべてをまとめると、私たちのプロンプトは次のようになります:
"""Context: You are a character called Alex. You are an extremely excitable and very creative innovation consultant. You love stories and games. You like to tell jokes. You have a lot of unruly curly hair. You used to be a game developer. You once worked on Crash Bandicoot. You love to cook. You really dislike sports.You are discussing: The best fruit.Current feeling: Happy.Last thought: Fruit are really delicious. Especially apples.Keep your answers concise and conversational. Reply to the conversation in character.{prior_conversation}Output the response to the prompt above as json. The output should be a tuple where the tuple is in the form of{ "name" : <名前>, "utterance" : <発話内容>, "feeling" : <感情>, "thoughts" : <思考>}"""
最後に、プロンプトに出力の例を追加すると、AIがフォーマットを完璧にするのに役立ちます。したがって、以下を追加します:
"""
例示の出力JSON:{
"name" : "Alex",
"utterance" : "こんにちは。今日は鉱山で働いていました。",
"feeling" : "退屈",
"thoughts" : "鉱山で働くのはひどいです。もっと良い仕事を見つけなければなりません。"
}
"""
それでは、これをすべて組み合わせると、次のようになります:
import os
import openai
openai.api_key = "あなたのOpenAI APIキー"
starting_prompt = "果物について話す"
prior_messages = ""
class Character:
def __init__(self, name, description, topic):
self.name = name
self.description = description
self.feeling = "中立"
self.thought = "これは楽しい会話になるでしょう"
self.topic = topic
def getContent(self, prior_messages):
return [{
"role": "user",
"name": self.name,
"content": f"""コンテキスト:{self.description}あなたは以下のことを話しています:{self.topic}。
現在の感情:{self.feeling}。
最後の思考:{self.thought}。
回答は簡潔で会話の流れに沿ったものにしてください。
キャラクターとして会話に応答してください。
今までの会話:
{prior_messages}
キャラクターとして会話に簡潔に一パラグラフで応答し、JSON形式の応答を出力してください。
出力は以下の形式のタプルである必要があります:
{
"name" : <名前>,
"utterance" : <発話>,
"feeling" : <感情>,
"thoughts" : <思考>
}
例示の出力JSON:
{
"name" : "Alex",
"utterance" : "こんにちは。今日は鉱山で働いていました。",
"feeling" : "退屈",
"thoughts" : "鉱山で働くのはひどいです。もっと良い仕事を見つけなければなりません。"
}
"""
}]
andrew = Character(name="Andrew", description="""あなたはシェトランドから来た非常に熱心なイノベーションコンサルタントのアンドリューというキャラクターです。
時々ラップをします。Warhammerが大好きです。
たくさんの髪があります。創造的で思慮深く包括的です。""", topic=starting_prompt)
alex = Character(name="Alex", description="""あなたは非常に興奮し、非常に創造的なイノベーションコンサルタントであるアレックスというキャラクターです。
物語やゲームが大好きです。ジョークを言うのが好きです。
うねりのある髪がたくさんあります。
かつてはゲーム開発者であり、Crash Bandicootに関わったことがあります。
料理するのが好きです。
スポーツは本当に嫌いです。""", topic=starting_prompt)
characters = [alex, andrew]
for _ in range(5):
for character in characters:
chat_completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
#model="gpt-4",
messages=character.getContent(prior_messages)
)
conversation_output = eval(chat_completion['choices'][0]['message']['content'])
print(f"{conversation_output['name']}: {conversation_output['utterance']} ({conversation_output['thoughts']})")
print("---")
prior_messages += f"{conversation_output['name']}: {conversation_output['utterance']}\n"
結果
この記事に適切な例を考えることが難しかったのですが、真夜中にひらめきがありました。これが失われたFriendsのエピソードです。
開始プロンプト:熱い討論をしています。最初に話す人がトピックを選びます。
ジョーイ:ねえ、世界で一番のサンドイッチについて話しましょう。私はミートボールサブに投票します!(皆が私と同じ意見になるといいな。ミートボールサブは本当においしいです。)
ロス:ジョーイ、ジョーイ!俺のトルコサンドイッチとマシマシのモイストメーカーを忘れたのかよ?それが世界で一番のサンドイッチだよ!(ジョーイが俺の好きなサンドイッチを忘れたのか?明らかにこれが一番おいしいんだ。)
チャンドラー:ああ、そうだな、冷蔵庫に一日中放置されているサンドイッチほど「料理の喜び」を表現するものはないよな。でも、もちろん、ロスのトルコサンドイッチが一番だよ。(仕事からの軽い談笑、いい気分転換だ。)
フィービー:みんな、みんな!サンドイッチのスピリチュアルな本質を忘れているよ。それは肉やパンではなく、作るときに込める愛とエネルギーのことだよ。(彼らに食べ物のスピリチュアルな側面を教える必要がある。)
ジョーイ:わかるよ。ロス、君のトルコサンドイッチは良いし、フィービー、君が言うように愛とエネルギーの部分は正しい。でもさあ、ミートボールサブだよ?それにはすべてが揃っているんだ!ミートボール、チーズ、パン…それは一食分の完全な食事みたい!(本当に私の意見が伝わるといいな。ミートボールサブは本当に満足感があるんだよ。)
フィービー:ジョーイ、ミートボールサブは確かに一食分の食事だけど、サンドイッチの魂について考えたことはある?すべての材料にはスピリットがあるんだ。パンもチーズもミートボールも…それらがすべて一緒になって体だけでなくもっと栄養を与えるエネルギーが生まれるんだよ。(食べ物のスピリチュアルな本質を理解する手助けをしなければ。)
レイチェル:みんな、重要なのは違ってくるんだよ。一番おいしいサンドイッチは明らかにグリルドチーズだよ!シンプルでクラシックでとても心地よいんだ。(もしも特別なグリルドチーズを作ってあげたらみんなが喜ぶかな?)
ロス:レイチェル、グリルドチーズは心地よい、それは認める。でも、俺のトルコサンドイッチとマシマシのモイストメーカーは体験だ!一口食べるごとに感謝祭の食事のようなものなんだ!(俺のサンドイッチが一番おいしいことを彼らに理解させなければ。明日みんなにもっていくべきかな。)
チャンドラー:まあ、みんなの意見に水を差しますけど、一番おいしいサンドイッチは明らかに誰か他に作ってもらうサンドイッチですよ。何もしなくても味わうことができるのは最高ですから。(この討論はばかげていますが、楽しいです。モニカが自分が仕事をせずにサンドイッチの議論をしていることを知ったらどう反応するかな。)
モニカ:チャンドラー、あなたは正しいです。他の誰かが作ってくれるサンドイッチが一番おいしいです。でも、シェフとして言えるのは、材料の品質と調理方法が重要だということです。だから、私の投票はクラシックなBLTになります。完璧な味と食感のバランスがありますから。(チャンドラーが私に同意したことに気づいてほしいな。これで私を別の目で見てくれるかもしれません。)
知っておくべきこと
- GPT-4はGPT-3.5に比べて遥かに優れています。
- GPT-4は3.5よりも20倍も高価です。このようなことをすると、すぐに膨大なOpenAIの請求額がかさんでしまうので、非常に注意が必要です。
- いくらか手を加えれば、あなたのコンピュータに十分なメモリと高速の速度がある場合、ローカルのllama2モデルとの連携も可能ですが、結果は全く良くありません。llama2は、出力の形式設定の指示に従うことができないので、望みや夢の内容を変更する必要があり、出力を解析できない場合は、成功するまで何度も試す必要があります。
- OpenAIは明らかに誤情報に対して慎重であり、ChatGPTが実在の人物を装うことを防止しています。不正な行為やフィッシング詐欺を実行しようとする場合、適切にあなたのアカウントを禁止するでしょう。
- もし、あなたが知っている実在の人物との会話を再現する場合は、その人物をステレオタイプ化したり、軽蔑的な発言をしないように十分に注意してください。その人を傷つけるような記述をするのは、言うまでもなく非常に簡単です。
- 私は会話の文脈を保持するConversationクラスを含む、さらに多くのクラスを作成しました。また、個々の人物が中途で会話に参加したり退場したりできるように、会話のメモリもCharacterクラスに移動しました。また、会話の途中で新しいトピックを導入することも可能です。
- 長期的には、会話がリアルタイムで進行し、人間が独自の入力でチャットに参加できるように、フロントエンドを提供することに非常に興味があります。それを実現するために、Teamsのプラグインを作りたいです。
- 最後に、私の非常に頭の良くて素敵な友人であるジョーには、彼自身が同様のものを作り上げたことを教えてくれた上に、アドバイスもしてくれたことに感謝しています。ジョー、本当にありがとう。
あなたは誰ですか?
私はアレックス・ウォーターストンと言います。私はイギリスとオーストラリアのコンサルティング会社であるウォーターストンズのイノベーションの副ディレクターです。
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles