はじめに
LangChainを使ってGPT関連の開発していると、Jupyter中でGPTと会話しながら調整したいことがある。
そこで、Jupyter中でipywidgetsを使ってインタラクティブにchainを使ってGPTと会話できるようにした。
本記事の完成品
準備 環境の設定, apiキー, chainの設定
使用した環境のrequirements.txt
langchain==0.0.343
openai==0.28.1
jupyterlab==4.0.10
JupyterLabでipywidgetを動かすために、以下を実行して再起動した。
jupyter labextension install @jupyter-widgets/jupyterlab-manager
まずapiキーを環境変数に入れておく
import os
#APIキーをセット
os.environ["OPENAI_API_KEY"] = #############
GPTとの会話で使いたいchainを作っておく。記法はLangChain Expression Language (LCEL)を使用した。(関連記事: LangChainのLCELで | (パイプ文字)を使って処理できる理由)
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain.memory import ConversationBufferMemory
from langchain.chat_models import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from operator import itemgetter
# memoryを作成。これによって、会話の履歴を保存し、gptに毎回履歴を渡せるようになる。
memory = ConversationBufferMemory(return_messages=True)
# promptを作成
template = """Answer the question in Japanese:
Question: {question}
"""
prompt = ChatPromptTemplate.from_messages([
MessagesPlaceholder(variable_name="chat_history"),
HumanMessagePromptTemplate.from_template(template)
])
# modelを作成
model = ChatOpenAI(model_name="gpt-3.5-turbo-16k",verbose=True)
# parserを作成
output_parser = StrOutputParser()
# chainへの入力に、chat_histryという変数名で、memoryが持っている会話履歴が加わるようにする。
setup = RunnablePassthrough.assign(
chat_history = RunnableLambda(memory.load_memory_variables)| itemgetter("history")
)
chain = setup | prompt | model | output_parser
ipyywidgetsで会話
from IPython.display import display, HTML, Markdown
import ipywidgets as widgets
# テキストボックスとボタンの作成
text_box = widgets.Text(placeholder='テキストを入力してください')
submit_button = widgets.Button(description='実行')
# 出力用のウィジェット
output = widgets.Output()
display(output)
# 実行ボタンを押したときの関数
def run_function(_):
# gptの返事を待っている間は、実行ボタンを選択不可にする。
submit_button.description = "実行中"
submit_button.disabled = True
# 入力された値を取得、取得後はクリア
text = text_box.value
text_box.value = ""
with output:
# 入力されたテキストをアウトプットウィンドウに出力
input_section_format = """<div>
<p>入力> {text}</p>
</div>"""
input_section = HTML(input_section_format.format(text=text))
display(input_section)
# gptのchainの実行
# 入力されたテキストを渡し、chainを実行
input = {"question":text}
gpt_output = chain.invoke(input)
# 入力とgptからの出力をmemoryに保存しておく。
memory.save_context({"input":template.format(**input)},{"output": gpt_output})
# gptの出力内容をアウトプットウィンドウに出力
# 出力内容を折り畳めるように、detailsタグを使用する。
gpt_section = Markdown(f"""<div>
<details><summary>GPT</summary><pre>{gpt_output}</pre></details>
</div>""")
display(gpt_section)
# 実行ボタンの選択不可を解除。
submit_button.description = "実行"
submit_button.disabled = False
submit_button.on_click(run_function)
# テキストボックスと実行ボタンを表示
display(text_box, submit_button)
完成。chainの部分を色々変えて試行錯誤しながら使えそう。