StreamlitとRAGで作る 実用的なAIチャットボット(1) Streamlit超入門

Streamlit
この記事は約16分で読めます。

こんにちは、JS2IIUです。
今回から全10回にわたり、「StreamlitとRAGで作る:実用的なAIチャットボット開発ガイド」というシリーズ連載を開始します。

近年、大規模言語モデル(LLM)の発展により、私たちエンジニアは強力なAIアプリケーションを個人レベルでも開発できるようになりました。しかし、「PythonでAIモデルは動かせたけれど、それを他人に使ってもらうためのUI(ユーザーインターフェース)を作るのが面倒だ」「HTMLやCSS、JavaScriptまで勉強する時間がない」と悩んでいる方は多いのではないでしょうか。

そこで登場するのが Streamlit です。

第1回となる今回は、このStreamlitの基礎を徹底的に解説します。単なる使い方の羅列ではなく、「なぜAIエンジニアにとって必須ツールなのか」「裏側でどのような仕組みで動いているのか」を深く理解し、今後のRAGアプリ開発の強固な土台を築くことが目的です。

それでは、PythonひとつでWebアプリを爆速構築する世界へ飛び込みましょう。今回もよろしくお願いします。

1. はじめに:なぜ今、Streamlitなのか?

AIエンジニアやデータサイエンティストにとって、作成したモデルやデータ分析の結果を「可視化」し、「共有」することは、モデルの精度を上げることと同じくらい重要です。しかし、従来のWebフレームワーク(Flask, Django, FastAPIなど)を使ってリッチなUIを作ろうとすると、フロントエンドの知識が不可欠となり、学習コストが跳ね上がります。

Streamlitは、この課題を解決するために生まれました。

  • オールPython: HTML/CSS/JavaScriptを一切書かずにWebアプリが作れます。
  • データサイエンス特化: DataFrameやグラフの描画機能が標準で充実しています。
  • 爆速開発: 数行のコードで動的なウィジェット(ボタン、スライダーなど)を実装できます。

本連載では、最終的に「独自のドキュメントを検索して回答するAI(RAG)」を作成しますが、そのインターフェース部分はすべてStreamlitで構築します。今回はその第一歩です。

2. Streamlitの「実行モデル」を理解する

コードを書く前に、Streamlitの最もユニークで、かつ初心者が最もつまずきやすい特徴である「実行モデル」について触れておきます。

通常のPythonスクリプトは上から下へ一度だけ実行されますが、Webアプリはユーザーの操作(ボタンクリックなど)に応じて動的に変化する必要があります。Streamlitは、「ユーザーが何か操作をするたびに、スクリプト全体を最初から最後まで再実行する」という大胆な仕組みを採用しています。

これを頭の片隅に置いておいてください。後述する「ステート管理」のセクションで、この知識が非常に重要になります。

3. 環境構築とHello World

まずは手元の環境でStreamlitを動かしてみましょう。Python 3.8以上がインストールされている環境を前提とします。プロジェクトごとの依存関係を管理するため、仮想環境の使用を強く推奨します。

インストール

ターミナル(またはコマンドプロンプト)を開き、以下のコマンドを実行します。

Bash
# 仮想環境の作成と有効化(例:venv使用)
python -m venv .venv
# Windowsの場合
.venv\Scripts\activate
# Mac/Linuxの場合
source .venv/bin/activate

# Streamlitのインストール
pip install streamlit

Hello World アプリの作成

任意のディレクトリに app.py というファイルを作成し、以下のコードを記述してください。

Python
# app.py
import streamlit as st
import pandas as pd
import numpy as np

# タイトルの表示
st.title('私の初めてのStreamlitアプリ')

# テキストの表示
st.write('こんにちは!これはPythonだけで作ったWebアプリです。')

# データの作成
df = pd.DataFrame({
    '1列目': [1, 2, 3, 4],
    '2列目': [10, 20, 30, 40]
})

# データフレームの表示
st.write('以下のデータフレームはインタラクティブに操作できます:')
st.write(df)

# 折れ線グラフの表示
st.line_chart(df)

アプリの起動

ターミナルで以下のコマンドを実行します。

Bash
streamlit run app.py

コマンドを実行すると自動的にブラウザが立ち上がり、ローカルサーバー(通常は http://localhost:8501)上でアプリが表示されます。たったこれだけのコードで、タイトル、テキスト、ソート可能な表、そしてグラフが表示されたはずです。これがStreamlitの威力です。

4. 【基本編】情報を表示する:st.write の魔法

Streamlitで最も頻繁に使う関数が st.write() です。これは非常に高機能な「スイスアーミーナイフ」のような関数で、引数に渡されたオブジェクトの型を自動判別して、適切な形式でレンダリングしてくれます。

  • 文字列を渡せばテキストとして表示(Markdownも解釈されます)。
  • PandasのDataFrameを渡せばインタラクティブな表として表示。
  • MatplotlibやPlotlyの図形オブジェクトを渡せばグラフとして表示。
  • KerasやPyTorchのモデル、辞書型データなどを渡せば、デバッグしやすい形式で表示。

明示的な表示メソッド

st.write() は便利ですが、より細かい制御を行いたい場合は、専用のメソッドを使うのが良いでしょう。

Python
import streamlit as st

st.header("表示機能のデモ")

# Markdown記法
st.markdown("これは **太字** で、こちらは *イタリック* です。")

# コードブロックの表示
code = '''def hello():
    print("Hello, Streamlit!")'''
st.code(code, language='python')

# 数式の表示(LaTeX)
st.latex(r'''
    e^{i\pi} + 1 = 0
''')

これらを使い分けることで、技術ブログのようなリッチなドキュメント形式のページも簡単に作成できます。

5. 【対話編】ユーザー入力を受け取る:ウィジェットとサイドバー

AIアプリでは、ユーザーからの質問テキストを受け取ったり、パラメータを調整したりする必要があります。Streamlitには st.buttonst.text_inputst.slider などの入力ウィジェットが用意されています。

これらは、「変数 = ウィジェット関数」という形で記述します。ユーザーが値を変更するとスクリプトが再実行され、変数の値が更新される仕組みです。

Python
import streamlit as st

st.title("インタラクティブなウィジェット")

# サイドバーへの配置
# st.sidebar を使うと、左側のサイドバーに要素を配置できます。
# 設定項目などを置くのに便利です。
st.sidebar.header("設定エリア")
user_name = st.sidebar.text_input("あなたの名前を入力してください", "ゲスト")

# メインエリア
st.write(f"ようこそ、{user_name} さん!")

# ボタン
if st.button('挨拶する'):
    st.write("こんにちは!今日も良いコードを書きましょう!")

# スライダー
age = st.slider('あなたの年齢は?', 0, 100, 25)
st.write(f"あなたは {age} 歳ですね。")

このコードを実行し、サイドバーの名前を変更してみてください。エンターキーを押した瞬間(あるいはフォーカスが外れた瞬間)、画面中央の「ようこそ〜」というメッセージが即座に更新されるはずです。これは、入力値が変わるたびにPythonスクリプト全体が再実行されている証拠です。

6. 【核心編】Streamlitの最大の壁「ステート管理」を攻略する

ここまでの知識で簡単なツールは作れますが、AIチャットボットのような「会話の履歴」を保持する必要があるアプリを作ろうとすると、ある問題に直面します。

「ボタンを押すたびに変数がリセットされてしまう問題」です。

前述の通り、Streamlitは操作のたびにスクリプト全体を再実行します。つまり、通常の変数は再実行のたびに初期化されてしまうのです。これを解決するために提供されているのが st.session_state です。これは、ユーザーのセッション(ブラウザを開いている間)が続く限り値を保持できる辞書のようなオブジェクトです。

失敗例:カウンターが動かないコード

Python
import streamlit as st

st.title("動かないカウンター")

# 通常の変数
count = 0

if st.button('カウントアップ'):
    count += 1

st.write(f"現在のカウント: {count}")

このコードでは、ボタンを何度押してもカウントは常に「1」になります。なぜなら、ボタンを押して再実行されるたびに count = 0 が実行されてしまうからです。

成功例:st.session_state を使ったカウンター

Python
import streamlit as st

st.title("正しく動くカウンター")

# session_stateに 'count' というキーが存在しなければ初期化する
if 'count' not in st.session_state:
    st.session_state['count'] = 0

# ボタンが押されたら session_state の値を更新する
if st.button('カウントアップ(ステート利用)'):
    st.session_state['count'] += 1

st.write(f"現在のカウント: {st.session_state['count']}")

このパターン(存在確認 → 初期化 → 利用)は、Streamlit開発における定石中の定石です。チャットの履歴管理、認証状態、RAGにおけるロード済みモデルの保持など、あらゆる場面で使用します。

7. 【実践編】RAGに向けた第一歩:チャットUIのプロトタイプ

それでは、第1回の総仕上げとして、次回以降に構築するRAGアプリの骨格となる「チャットUI」を作成してみましょう。ここではまだAIは組み込みませんが、ユーザーの入力とボットの返答(ダミー)を履歴として保存し、画面に表示するロジックを実装します。

Python
import streamlit as st
import time

st.title("シンプルチャットボット (UIのみ)")

# 1. チャット履歴の初期化
# リスト形式でメッセージを保存します
if "messages" not in st.session_state:
    st.session_state.messages = []

# 2. 過去のチャット履歴を表示
# アプリ再実行時に履歴が消えないように、session_stateから読み出して表示します
for message in st.session_state.messages:
    # st.chat_message は役割(user/assistant)に応じたアイコンと枠を表示します
    with st.chat_message(message["role"]):
        st.write(message["content"])

# 3. ユーザー入力の受け付け
# st.chat_input はチャット特化の入力欄です
if prompt := st.chat_input("何か話しかけてください"):
    # ユーザーの入力を表示
    with st.chat_message("user"):
        st.write(prompt)

    # 履歴に追加
    st.session_state.messages.append({"role": "user", "content": prompt})

    # 4. ボットの応答(ここではダミー)
    # 実際にはここでRAGやLLMの処理が入ります
    response = f"あなたが言ったこと: 「{prompt}」ですね。まだ私はAI脳を持っていませんが、UIは機能しています!"

    # ボットの応答を表示
    with st.chat_message("assistant"):
        st.write(response)

    # 履歴に追加
    st.session_state.messages.append({"role": "assistant", "content": response})

コードのポイント

  1. st.chat_messagest.chat_input: Streamlitにはチャットアプリ専用のコンポーネントが用意されており、これを使うだけでモダンなチャットUIが完成します。
  2. 履歴のループ表示: ユーザーが新しいメッセージを送るとスクリプトが再実行されます。その際、「過去の履歴を表示する処理」→「新しい入力を処理する処理」の順で動くため、会話が積み重なっていくように見えます。

このコードを実行すると、まるで本物のチャットアプリのように会話がスクロールしていく様子が確認できるはずです。

8. まとめと次回予告

今回は、Streamlitの基礎からステート管理、そしてチャットUIの実装までを一気に駆け抜けました。

  • Streamlitは「データスクリプト」: 上から下へ再実行されるシンプルなモデル。
  • st.write: なんでも表示できる万能関数。
  • st.session_state: 再実行間でデータを保持するための必須機能。
  • チャットUI: 専用コンポーネントで簡単に実装可能。

これで、AIアプリを受け入れる「器」は完成しました。しかし、今のボットはオウム返しをするだけです。

次回、第2回「RAGの基本を理解する:LangChain/LlamaIndexを使った最小構成」では、いよいよこの器に「知能」を吹き込みます。OpenAIのAPIなどを使い、実際にAIと会話できるようにし、さらにRAG(Retrieval-Augmentation-Generation)の基本概念について深掘りしていきます。

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

連載記事リンク

コメント

タイトルとURLをコピーしました