LangChain×Streamlitを使ったチャットボットアプリを開発してみた

LangChain×Streamlitを使ったチャットボットアプリを開発してみた

Ranola Joshuel

Ranola Joshuel

Technology部のJoshです。

この記事では、大規模言語モデル(LLM)をデータに接続できるフレームワーク「LangChain」を使ったチャットボットアプリの開発例を紹介します。

生成AIを学んでいるみなさんの参考となれば幸いです。

▲完成したチャットボット

LangChainとは

LangChainは、大規模言語モデル(LLM)を扱うための強力なフレームワークです。

LLMは多くのタスクを効率的に処理できますが、特定のプライベートな情報、たとえば企業秘密に関する情報などを提供することはできません。また、特定の専門領域において詳細な回答を提供するのにも限界があります。

LangChainは、LLMを独自のデータセットに接続することでこれらの問題を解決します。たとえば、医療に関する大量のデータが手元にある場合、LangChainを使用してLLMを医療について学習させれば、医療領域における質問回答能力を強化することができます。

つまり、特定の専門領域におけるデータさえ持っていれば、LangChainはLLMをその領域における専門家にできるのです。

開発概要

LangChainの動作を確認するために、実際にアプリケーションを構築してみましょう。

アプリケーション仕様

今回開発するアプリケーション仕様は以下のとおりです。

Host ローカルホスト(MacOS Ventura 13.4.1)
プログラミング言語 Python(ver3.10)
仕様 PDFデータを読み込み、PDFの内容を回答するチャットボットアプリ
過去の質問と回答内容をメモリにプールすることも可能

ライブラリ

今回のアプリ開発では、PythonでWebアプリケーションを作成するフレームワーク「Streamlit」を使用します。また、その他にもさまざまなPythonのライブラリをインストールする必要があります。

Terminal
pip install streamlit streamlit_chat langchain openai faiss-cpu tiktoken pypdf

実装手順

一つひとつのコードについて説明します。なお、実装したコードは私のGitHubにもアップロードしているため、必要あればご覧ください。
https://github.com/joshuel09/chatbot-langChain/blob/main/langChainExp.py

1.ライブラリのインポート

まずは必要なパッケージをインポートします。

Python
import os
import streamlit as st
from streamlit_chat import message
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationalRetrievalChain
from langchain.document_loaders import PyPDFLoader
from langchain.vectorstores import FAISS
import tempfile
from langchain.text_splitter import RecursiveCharacterTextSplitter

 
Streamlit:Webアプリケーションを構築するためのPythonライブラリです。データの可視化、ダッシュボードの構築、チャットボットの作成など、インタラクティブなWebページを作成するために使用します。

Streamlit_chat:Streamlitを拡張してチャットボットをより簡単に構築できるようにするライブラリです。メッセージの送受信、会話の状態の管理をおこなう関数を提供します。

OpenAIEmbeddings:OpenAI GPT-3 言語モデルにアクセスできるライブラリです。テキストの生成、言語の翻訳、質問への回答に使用できます。

ChatOpenAI:OpenAI GPT-3 言語モデルを使用してチャットボットを実装するクラスです。ユーザーと会話できるチャットボットを作成するために使用します。

ConversationalRetrievalChain:会話型検索チェーンを実装するクラスです。データベースから情報を取得し、ユーザーのクエリに応答するために使用するチャットボットの一種です。

PyPDFLoader:PDFドキュメントをメモリにロードできるクラスです。PDFドキュメントのテキストコンテンツにアクセスする必要があるチャットボットに役立ちます。

FAISS:近似最近傍探索を実行するライブラリです。これは、ConversationalRetrievalChainが特定のクエリに対してもっとも関連性の高いドキュメントを見つけるために使用されます。

tempfile:一時ファイルやディレクトリを作成するための関数を提供するライブラリです。会話の状態など、一時データを保存する必要があるチャットボットに役立ちます。

RecursiveCharacterTextSplitter:テキストを文字に分割できるクラスです。個々の文字にアクセスする必要があるチャットボットに役立ちます。

2.OpenAI APIキー入力とPDFファイルアップロード

以下のコードでユーザーにOpenAI APIキーの入力を求め、チャットボットの元となる「PDFファイルのアップロード」を実施できるようにします。

Python
user_api_key = st.sidebar.text_input(
    label="OpenAI API key",
    placeholder="Paste your openAI API key here",
    type="password")

uploaded_file = st.sidebar.file_uploader("upload", type="pdf")

os.environ['OPENAI_API_KEY'] = user_api_key

 
ユーザーがPDFファイルをアップロードしたあと、LangChainのPyPDFLoaderクラスを使用して、PDFの内容を読み込みます。PyPDFLoaderクラスはPDFファイルを一意の行に分割することができます。

Python
text_splitter = RecursiveCharacterTextSplitter(
        chunk_size = 2000,
        chunk_overlap  = 100,
        length_function = len,
    
)

if uploaded_file :
    with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
        tmp_file.write(uploaded_file.getvalue())
        tmp_file_path = tmp_file.name

    loader = PyPDFLoader(file_path=tmp_file_path)  
    data = loader.load_and_split(text_splitter)

3.チャットボット機能の強化

ConversationalRetrievalChainを使えば、過去の質問や回答内容を加味してテキストを出力できます。また、ドキュメントから関連情報を高速で検索できるようにするために、FAISS Vectorestoreを利用しました。

なお、今回は最適なパフォーマンスを確保するために、GPT-3.5-turboモデルの代わりにGPT-3.5-turbo-16kモデルを使用しています。GPT-3.5-turboモデルは4,096トークンの制限があり、PDFの内容を完全に処理することができません。一方、GPT-3.5-turbo-16kモデルは16,384トークンの容量を持っています。GPT-4が利用可能になれば、よりシームレスなソリューションを提供できます。
参考:https://platform.openai.com/docs/models/gpt-3-5

Python
embeddings = OpenAIEmbeddings()
    vectors = FAISS.from_documents(data, embeddings)

    chain = ConversationalRetrievalChain.from_llm(llm = ChatOpenAI(temperature=0.0,model_name='gpt-3.5-turbo-16k'),
                                                                      retriever=vectors.as_retriever())

 
実際の会話履歴はst.session_state[‘history’]に保存されます。

以下のように会話履歴をConversationalRetrievalChainに渡すことで、過去の応答や読み込んだファイルから回答を生成できるようにします。

Python
    def conversational_chat(query):
        
        result = chain({"question": query, "chat_history": st.session_state['history']})
        st.session_state['history'].append((query, result["answer"]))
        
        return result["answer"]

4.ユーザーエクスペリエンスの向上

続いて、ユーザーエクスペリエンス向上のための「セッションの初期化」と「メッセージ表示」をおこないます。

  • セッションを初期化するために、st.session_state[‘history’]の通りに宣言する
  • [‘generated’]にて、モデルから生成された回答を保存
  • [‘past’]は、ユーザーが入力したメッセージを保存

コンテナは必須ではありませんが、チャットメッセージの下に質問エリアを配置することで、ユーザーエクスペリエンスが向上します。

Python
    if 'history' not in st.session_state:
        st.session_state['history'] = []

    if 'generated' not in st.session_state:
        st.session_state['generated'] = ["Hello ! Feel free to ask about anything regarding this" + uploaded_file.name]

    if 'past' not in st.session_state:
        st.session_state['past'] = ["Hey !"]
        
    response_container = st.container()
    container = st.container()

5.入力の有効化

session.stateとコンテナを設定すれば、ユーザーが質問を入力し回答できる状態になります。submit_buttonが押下されたら、以下のようにconversational_chat関数が呼び出しされ、[‘generated’]並びに[‘past’]に対しても入力した質問と生成された回答が保存されます。

Python
 with container:
        with st.form(key='my_form', clear_on_submit=True):
            
            user_input = st.text_input("Query:", placeholder="Talk about your pdf data here (:", key='input')
            submit_button = st.form_submit_button(label='Send')
            
        if submit_button and user_input:
            output = conversational_chat(user_input)
            
            st.session_state['past'].append(user_input)
            st.session_state['generated'].append(output)

6.ユーザーとチャットボットのメッセージを表示

最後に、streamlit_chatモジュールを使用して、ユーザーとチャットボットの間でやり取りされるメッセージをStreamlitサイト上に表示します。

Python

    if st.session_state['generated']:
        with response_container:
            for i in range(len(st.session_state['generated'])):
                message(st.session_state["past"][i], is_user=True, key=str(i) + '_user', avatar_style="big-smile")
                message(st.session_state["generated"][i], key=str(i), avatar_style="thumbs")

7.チャットアプリケーションの実行

以下のコマンド実行することで、チャットアプリが実行できます!

※作成した実際のファイル名で、’name_of_your_chatbot.py’ を置き換えてください。

Terminal
streamlit run name_of_your_chatbot.py

8.テスト

アプリが起動したら、1〜3のステップを実行してテストしてみてください。

まとめ

LangChain、OpenAI、Streamlitを活用することで、以下が実現します。

  • LangChainで、LLMを動的に設定する
  • 過去の応答や読み込んだファイルの内容を保存し、その内容を元に回答する
  • Streamlitによりフロントエンドの知識がなくても簡単にチャットアプリが作れる

この記事がお役に立てば幸いです。

 

また、LIGでは生成AIコンサルティング事業をおこなっています。ぜひ気軽にご相談ください。

生成AIコンサルティング事業の詳細へ

この記事のシェア数

Ranola Joshuel
Ranola Joshuel DX / Application Development / Technical Director / ラノーラ ジョシュエル

ITプロフェッショナル/テクニカルディレクターとしてOpenAIを使用したサービスの実装に関する研究や実験に従事。JS、PHP、Python、Vue、Next、Reactの言語やフレームワークに関して深い知識を所有する。また、海外のエンジニアとのコミュニケーションをブリッジエンジニアとしても、通訳を含む各種を対応しています。プログラミングへの情熱は高校時代からあり、大学でコンピュータサイエンスの学位を取得後、エンジニアとして日本のIT系企業に就職。4年間フルスタックエンジニアに従事し、2023年LIGにジョイン。

このメンバーの記事をもっと読む
10年以上の開発実績があるLIGが、最適な開発体制や見積もりをご提案します
相談する サービス概要を見る