こんにちは、CCCMKホールディングス TECH LABの三浦です。
先日久しぶりに飛行機に乗りました。当たり前のことなのですが、飛行機を使うと数100キロ離れていてもあっという間に移動することが出来ます。朝起きた場所と、夜眠る場所が数100キロも離れてるなんてなんだか不思議だな、と思いました。
最近以前から試してみたいな、と思いつつ、なかなか試すことが出来ていなかったChainlitというPythonのライブラリをついに試すことが出来ました!Chainlitを使うととてもスピーディーにチャット型のアプリケーションを作ることが出来ます。今回はChainlitを使ってAzure OpenAI Serviceのgpt-3.5-turboやgpt-4を使えるチャットアプリケーションを作ってみました。
Chainlit
Chainlitは対話AIや対話Agentとのチャットアプリケーションをスピーディーに開発することが出来るFrameworkです。
結構色々な機能が用意されていて、さらにLangChainやAutoGenといった別のLLM関連のFrameworkと機能統合をしています。前回までMulti-Agent ConversationやAutoGenについて色々調べていたのでChainlit+AutoGenの組み合わせは今後ぜひ試していきたいところです。
今回はChainlitの本当に基本的な機能だけを使い、Azure OpanAI Serviceで提供されているChatGPTと対話が出来るチャットアプリケーションの作り方をご紹介します。
基本型
Chainlitを用いた一番シンプルなチャットアプリケーションを作成してみます。具体的には次のようなチャットアプリケーションです。
基本型ですが、デザインがきれいでとてもいいな、と思っています。このアプリのメインとなるPythonのコードは次のようなとてもシンプルな内容です。
""" 基本形のAzureOpenAIと接続したアプリ """ import chainlit as cl from src.llm_response import generate_message, SYSTEM_CONTENT # 会話の履歴を格納する変数 message_history = [ { "role":"system", "content":SYSTEM_CONTENT } ] @cl.on_message async def main(message: cl.Message): """ ユーザーからメッセージが送られたら実行される関数 """ message_history.append({ "role":"user", "content":message.content }) # Azure OpenAI Serviceと通信を行う response = generate_message(message_history) # 画面にAzure OpenAI Serviceから受け取った応答を表示する await cl.Message( content=response["content"] ).send() message_history.append({ "role":"assistant", "content":response["content"] })
chainlit
のon_message
デコレータは、チャットアプリケーションの画面でユーザーがメッセージを送信すると実行される処理を定義します。実行される処理はmain
関数にまとめていて、内部ではgenerate_message
からAzure OpenAI ServiceのChatGPTを呼び出してユーザーメッセージへの応答を作成し、画面に表示させています。
generate_message
は別のファイルで定義しています。
import os from typing import List,Dict from openai import AzureOpenAI SYSTEM_CONTENT = """あなたはフレンドリーなアシスタントです。質問に答えて下さい。""" def generate_message( messages: List[Dict], model_name: str = "gpt-35-turbo-16k", max_tokens: int = 800, temperature: float = 0.0 ): client = AzureOpenAI( api_key=os.environ.get("AZURE_OPENAI_API_KEY"), azure_endpoint=os.environ.get("AZURE_OPENAI_API_BASE"), api_version="2023-12-01-preview" ) chat_completion = client.chat.completions.create( messages=messages, model=model_name, max_tokens=max_tokens, temperature=temperature, ) return { "role":"assistant", "content":chat_completion.choices[0].message.content }
chainlit
で記述したアプリケーションを起動するには、ターミナルで以下のコマンドを実行します。
chainlit run main.py -w
コマンドにw
オプションを指定することで、アプリケーション実行後にソースコードに変更を加えると自動的にその変更内容を読み込み反映してくれるようになります。
デフォルトでは8000ポートでアプリケーションが起動します。ブラウザで"http://localhost:8000/"にアクセスするとアプリケーションを使用することが出来ます。
(少し)発展型
今度は基本型を少しだけ発展させてみます。使用するモデルを切り替えたり、温度パラメータなどを調整出来るような機能を追加してみます。アプリケーションは以下のような画面になります。
アプリケーションのメインのソースコードは次のようになります。
""" 使用するモデルやパラメータの調整を可能にしたバージョン """ import chainlit as cl from chainlit.input_widget import Slider from src.llm_response import generate_message, SYSTEM_CONTENT # 会話の履歴を格納する変数 message_history = [ { "role":"system", "content":SYSTEM_CONTENT } ] @cl.set_chat_profiles async def chat_profile(): """ 画面の上部に表示されるモデル一覧を設定する """ return [ cl.ChatProfile( name="gpt-35-turbo-16k", markdown_description="The underlying LLM model is **gpt-35-turbo-16k**.", icon="icon画像のURLを指定します。", ), cl.ChatProfile( name="gpt-4", markdown_description="The underlying LLM model is **gpt-4**.", icon="icon画像のURLを指定します。", ), ] @cl.on_chat_start async def start(): """ Chatを開始したタイミングで一度だけ呼ばれる。 """ # パラメータの設定項目を定義する settings = await cl.ChatSettings( [ Slider( id="max_tokens", label="最大応答", initial=800, min=1, max=4000, step=1 ), Slider( id="temperature", label="温度パパラメータ", initial=0, min=0, max=1, step=0.01 ) ] ).send() await update_settings(settings) @cl.on_settings_update async def update_settings(settings): """ パラメータの設定を変更する。 """ cl.user_session.set("llm_parameters",settings) @cl.on_message async def main(message: cl.Message): """ ユーザーからメッセージが送られたら実行される関数 """ llm_parameter = cl.user_session.get("llm_parameters") chat_profile = cl.user_session.get("chat_profile") message_history.append({ "role":"user", "content":message.content }) response = generate_message( message_history, model_name=chat_profile, max_tokens=int(llm_parameter["max_tokens"]), temperature=llm_parameter["temperature"] ) await cl.Message( content=response["content"] ).send() message_history.append({ "role":"assistant", "content":response["content"] })
いくつかポイントがあるので、以下にまとめていきます。
Chat Profile
Chainlitでは、チャットアプリケーションの上部にチャットのモード(Chat Profile)を切り替えることが出来る機能を追加することが出来ます。Chat Profileはchainlit
のset_chat_profiles
デコレータで定義することが出来ます。今回は"gpt-35-turbo-16k"と"gpt-4"をChat Profileとして設定しました。
Chainlitではさらに、ユーザーとのチャットセッション間に変数を保持する機能があり、chainlit
のuser_session
に格納することでセッション間値を保持することが出来ます。ユーザーが画面上でChat Profileを選択すると、user_session
にchat_profile
というキーに紐づいて選択したChat Profileのname
が格納されます。
Chat Settings
Chat Settingsを使うことでユーザーがチャット開始時に様々な設定を行うことが出来るようになります。
設定項目はchainlit
のChatSettings
を使ってリストで定義します。それぞれの項目には入力用のWidgetを設定することが出来、初期値や設定可能な範囲などをWidgetごとに設定できます。
Chat Settingsの定義はチャット開始時に1度だけ実行される処理の中で行っています。チャット開始時に実行される処理は、chainlit
のon_chat_start
デコレータで定義します。また設定が変更された際は設定内容を更新する必要がありますが、Chat Settingsが変更された時に実行したい処理はon_settings_update
デコレータで定義します。設定内容はChat Profileと同様user_session
に格納するようにしました。
起動時に表示される画面の変更
Chainlitのアプリケーションを起動すると、デフォルトでは以下のような画面が表示されます。
実はこの画面に表示している内容は、chainlit run
コマンドを実行したディレクトリに自動的に生成される"chainlit.md"というマークダウンに記述された内容です。"chainlit.md"を編集すると、起動時の画面を変更することが出来ます。
たとえば"chainlit.md"を次の様に書き換えます。
# Chatアプリ
Chainlitを使って作ったChatアプリです。
すると起動時の画面はこのようになります。
まとめ
今回はチャットアプリケーションを作るためのPythonのFramework Chainlitを試してみた話をまとめてみました。デザインがきれいでとてもいいな、と感じました。見た目だけでなく、Chainlitは様々な機能が搭載されているので、それらも使いこなせるようになりたいと思いました。