サイトアイコン アマチュア無線局JS2IIU

【Streamlit】LangSmithに対応したRAGチャットアプリ

こんにちは、JS2IIUです。
LangSmith は、LangChainアプリケーションのデバッグ、評価、パフォーマンス改善をサポートするためのツールセットです。LangChainとの組み合わせにより、アプリケーションの挙動を可視化し、問題を素早く特定できます。今回は、以前の記事で作成したRAGチャットアプリをLangSmithに対応させてみます。今回もよろしくお願いします。

LangSmithとは?

LangSmithは、LLM(大規模言語モデル)アプリケーションの開発を支援するための強力なツールで、以下の機能を提供します。

LLMを活用したアプリケーションでは、複雑なプロンプトやデータ処理を追跡しにくいため、LangSmithを利用することで、エラーの解析や応答精度の向上に繋がります。

LangSmithのセットアップ

APIキーの取得

LangSmithを利用するには、公式サイトからアカウントを作成し、APIキーを取得します。

  1. LangSmith公式サイトにアクセス
  2. アカウント作成後、APIキーを発行

環境変数の設定

取得したAPIキーを環境変数として設定します。

Bash
export LANGCHAIN_API_KEY="your-langsmith-api-key"

また、以下の2つの環境変数も必要です。

Bash
export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"

PDF対応RAGチャットアプリ

このアプリは、ユーザーがアップロードしたPDFファイルの内容を抽出し、質問応答(RAG: Retrieval-Augmented Generation)を行います。

アプリの機能概要

https://js2iiu.com/wp-content/uploads/2025/02/langsmith.mov

コード解説

Bash
import streamlit as st
import os
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langsmith import traceable

# LangSmithの環境変数の確認
def initialize_langsmith():
    os.environ["LANGCHAIN_TRACING_V2"] = "true"
    os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
    if not os.getenv("LANGCHAIN_API_KEY"):
        st.error("LangSmith APIキーが環境変数に設定されていません。")
        st.stop()

@traceable(name="process_pdf")
def process_pdf(uploaded_file, api_key):
    with open("temp.pdf", "wb") as f:
        f.write(uploaded_file.getbuffer())

    loader = PyPDFLoader("temp.pdf")
    documents = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=100)
    docs = text_splitter.split_documents(documents)

    embeddings = OpenAIEmbeddings(openai_api_key=api_key)
    vectorstore = FAISS.from_documents(docs, embeddings)

    return vectorstore

@traceable(name="initialize_chatbot")
def initialize_chatbot(api_key):
    st.session_state.llm = ChatOpenAI(model_name="gpt-4", openai_api_key=api_key)
    st.session_state.vectorstore = None
    st.session_state.qa_chain = None

def main():
    initialize_langsmith()

    st.set_page_config(page_title="PDF対応 RAGチャット", layout="wide")
    st.title("📄 PDF対応 RAGチャット")

    openai_api_key = os.getenv("OPENAI_API_KEY")
    if not openai_api_key:
        st.error("OpenAI APIキーが環境変数に設定されていません。")
        return

    if "llm" not in st.session_state:
        initialize_chatbot(openai_api_key)

    uploaded_file = st.file_uploader("PDFファイルをアップロード", type="pdf")

    if uploaded_file is not None:
        with st.spinner("PDFを処理しています..."):
            st.session_state.vectorstore = process_pdf(uploaded_file, openai_api_key)
            st.session_state.qa_chain = RetrievalQA.from_chain_type(
                llm=st.session_state.llm,
                retriever=st.session_state.vectorstore.as_retriever()
            )
            st.success("PDFの処理が完了しました。チャットを開始できます!")

    if st.session_state.qa_chain:
        user_query = st.text_input("💬 質問を入力してください")

        if user_query:
            with st.spinner("考えています..."):
                response = st.session_state.qa_chain.run(user_query)
                st.text_area("🤖 回答", value=response, height=200)

if __name__ == "__main__":
    main()

LangSmith初期化

Python
# LangSmithの環境変数の確認
def initialize_langsmith():
    os.environ["LANGCHAIN_TRACING_V2"] = "true"
    os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
    if not os.getenv("LANGCHAIN_API_KEY"):
        st.error("LangSmith APIキーが環境変数に設定されていません。")
        st.stop()

LangSmithのトレーシング機能を有効にし、APIキーを確認しています。

PDF処理関数

Python
@traceable(name="process_pdf")
def process_pdf(uploaded_file, api_key):
    with open("temp.pdf", "wb") as f:
        f.write(uploaded_file.getbuffer())

    loader = PyPDFLoader("temp.pdf")
    documents = loader.load()

    text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=100)
    docs = text_splitter.split_documents(documents)

    embeddings = OpenAIEmbeddings(openai_api_key=api_key)
    vectorstore = FAISS.from_documents(docs, embeddings)

    return vectorstore

この関数では、アップロードされたPDFを分割し、FAISSベースのベクトルデータベースを作成しています。

チャットボット初期化

Python
@traceable(name="initialize_chatbot")
def initialize_chatbot(api_key):
    st.session_state.llm = ChatOpenAI(model_name="gpt-4", openai_api_key=api_key)
    st.session_state.vectorstore = None
    st.session_state.qa_chain = None

ここでは、OpenAIのChatOpenAIモデルを初期化し、アプリケーションの状態を管理するためにst.session_stateを使用しています。

LangSmithダッシュボードでの確認

アプリケーションを実行した後、LangSmithのダッシュボードでトレースを確認できます。

  1. LangSmith Dashboardにアクセス
  2. process_pdfinitialize_chatbotの実行履歴を確認

トレースの確認

PDFの処理ステップがどの程度の時間を要しているかを確認できます。今回の例では、PDFの処理に約2秒、回答文の生成に約7秒かかっていることがわかります。LangChainを使った開発では欠かせないサービスです。

エラーの特定

入力データのエラーやAPI呼び出しの失敗が詳細に記録され、迅速な原因特定が可能です。

参考リンク

最後に、書籍のPRです。

最新のOpenAIのチャットAPIの使い方もしっかりと解説されている良書です。2024年11月初版発行、「LangChainとLangGraphによるRAG・AIエージェント[実践]入門」西見、吉田、大嶋著。

最後まで読んでいただきありがとうございます。

モバイルバージョンを終了