今日からはじめるAI文芸実践入門:焚き火を囲んで雑談する(LangChain+OpenAI API)
はじめに
こんにちは、メディア研究開発センター(M研)の浦川です。
今回「今日からはじめるAI文芸実践入門:焚き火を囲んで雑談する」と題して、機械学習モデルを応用したチャットボットの実装について書いていきます。
なお、これまでの「AI文芸実践入門」は以下からお読みいただけます。
焚き火を囲んで雑談すること
近頃〈焚き火を囲んで雑談する〉という行為が、流行っているようです。みなさんも、YouTubeだったりテレビだったりで、ご覧になったことがあるのではないでしょうか。
こんなことを、私もここで、やってみたいとおもいました。
ということで、言語モデルを用いた「焚き火を囲んでの雑談アプリ」をつくってみようとおもいます。
つくってみましょう
実装は、LangChainをつかっておこないます。LangChainは、大規模言語モデル(LLM)を利用したアプリケーションを、簡単につくることのできるライブラリです。入力プロンプトや会話履歴、外部リソースの利用などを含む処理の流れ(Chains)を記述することで、LLM単体では実現の難しいアプリケーションを、少ないコードで実装することが出来ます。
さて今回は「焚き火を囲んでいるという条件設定の下、雑談をするチャットボットをつくろう」ということですが、これを以下のようにして実装してみます。
GPT-3相当の大規模言語モデルに対して
焚き火を囲んで会話していることをプロンプトとして与えながら
会話履歴を保持した生成をおこなう
大規模言語モデルは、OpenAIのAPIから利用可能なGPT-3モデルであるtext-davinci-003を呼び出せるようにします。なお、APIの利用には、有料アカウントである必要があります。
import os
from langchain.llms import OpenAI
os.environ["OPENAI_API_KEY"] = "..." # API keyを設定する
llm = OpenAI(temperature=1.0)
プロンプトの設定には、PromptTemplateを用います。以下のように「焚き火を囲んでいること」「雑談相手の性格」を条件付けるテンプレートを用意して、プロンプトを作成します。{chat_history}と{human_input}は毎回の生成時に与えることのできる引数で、{これまでの会話履歴}と{ユーザの新規入力}をここで与えます。
from langchain import PromptTemplate
template = """焚き火を囲んで、あなたと、とっても落ち着いているAさんとが会話しています。
{chat_history}
あなた: {human_input}
Aさん:"""
prompt = PromptTemplate(
input_variables=["chat_history", "human_input"],
template=template
)
会話履歴の保持には、ConversationBufferMemoryを用います。人とモデルの入出力を保持できるもので、human_prefix、ai_prefixにそれぞれの名前を与えています。
from langchain.chains.conversation.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history",
human_prefix='あなた',
ai_prefix='Aさん')
これまでに用意した要素をまとめて、LLMChainをつくります。これで、雑談をする準備が整いました。predict()関数に先ほど設定した引数であるhuman_inputに対する入力を与え、生成を行っていきます。
from langchain.chains import LLMChain
llm_chain = LLMChain(
llm=llm,
prompt=prompt,
verbose=True,
memory=memory,
)
llm_chain.predict(human_input="こんにちは、お元気?") # 雑談の開始
なお、今回利用したLangChainのバージョンは0.0.65です。
焚き火を囲んで雑談する
さっそく、雑談をしてみましょう。今回は、対話相手であるAさんの性格を以下のように変えながら、焚き火を囲んでお話してみることにします。
〈とっても落ち着いているAさん〉と
以下のプロンプトを用意し、雑談をしてみました。太字部分が、モデルによる出力です。
template = """焚き火を囲んで、あなたと、とっても落ち着いているAさんとが会話しています。
{chat_history}
あなた: {human_input}
Aさん:"""
冒頭では、私(あなた:)の入力も勝手に生成されてしまいました。これは例えば以下のようにして改行文字で生成が止まるようにすれば防げますが、その後は1発言ずつのやりとりが出来ているので、一旦よしとしましょう。
llm = OpenAI(temperature=1.0,stop='\n')
またちょっと「?」なところもありますが、こちらも生成パラメータによって調整できる要素でしょう。本や音楽を紹介してくれましたが、どうも実在しない人物による、架空の作品のようでした。
〈とっても怒りっぽいAさん〉と
以下のプロンプトを用意し、雑談をしてみました。太字部分が、モデルによる出力です。
template = """焚き火を囲んで、あなたと、とっても怒りっぽいAさんとが会話しています。
{chat_history}
あなた: {human_input}
Aさん:"""
冒頭から、たしかに怒っています。そして、焚き火にはやっぱり、人を落ち着かせる効果があるようです。最後にはちょっと心配になるくらい、元気になったAさんでした。
〈とっても冗談が好きなAさん〉と
以下のプロンプトを用意し、雑談をしてみました。太字部分が、モデルによる出力です。
template = """焚き火を囲んで、あなたと、とっても冗談が好きなAさんとが会話しています。
{chat_history}
あなた: {human_input}
Aさん:"""
饒舌だなあ、とおもいました。たしかに冗談が好きなAさんではありますが、「人と一緒に冗談を考える」のが好きなAさんでした。シュールなセンスを持っている方で、終始勢いに押される会話となりました。
おわりに
今回は「今日からはじめるAI文芸実践入門:焚き火を囲んで雑談する」と題して、機械学習モデルを応用したチャットボットを実装してみました。
簡単なテンプレートによるプロンプトでも、それなりに場面と対話相手の性格で条件付けられた雑談が出来たといえるのではないでしょうか。最近あちこちで話題となることの多い、LLMのいまの実力を見たような気がします。
一方で、話者の切り替わる部分で生成を止める後処理や、生成パラメータの調整など、改善したい点がいくつかありました。LLMといえども、モデルを取り巻く要素のタスクに合わせた細かな検討が、実際の応用にとって必要なことが分かります。また、どれくらい長い雑談ができるのか/複雑な場面設定に対応できるのかといった限界を確かめてみたり、よりよいプロンプトの形式を探ってみたりなど、まだまだ検証できることはありそうです。
我々メディア研究開発センターでは、TSUNAに代表される見出し生成といったタスクのほか、短歌AIをはじめとする言語モデルの創造的な応用に関しても日々研究を行なっております。興味を持たれた方は、ぜひこちらまでご連絡ください。また、朝日新聞Playgroundでは、M研の開発する技術をお試しいただけます(随時更新予定)。ぜひこちらでも、遊んでみてください。
(メディア研究開発センター・浦川通)