0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonを使ったAIチャットボットの開発

0
Posted at

PythonでRAGチャットボットを構築する

概要

OpenAI・Pinecone・Notionを組み合わせたRAG(Retrieval-Augmented Generation)チャットボット。
Notionをナレッジベースとして使用し、Pineconeでベクトル検索、OpenAIで回答生成を行う。


システム構成

Notion(ナレッジDB)
    ↓ ページ取得・テキスト抽出
Pinecone(ベクトルDB)
    ↓ 類似検索
OpenAI(回答生成)
    ↓
ユーザーへ返答 + スプレッドシートにログ記録

モジュール構成

以下の役割ごとにモジュールを分割して実装している。

  • エントリーポイント(main.py) : 各モジュールを統合して回答を生成・ログ出力
  • エラー通知 : 例外発生時にメールで通知
  • スプレッドシート操作 : 行の追加・読み書き
  • Notion連携 : ページリストの取得、ブロックAPIでのテキスト抽出
  • Pinecone連携 : ベクトルデータの登録・更新・削除
  • OpenAI連携 : テキストのベクトル化、回答・質問文の生成
  • DBメンテナンスバッチ : Notionとの差分検出・Pinecone同期
  • フロントエンド : StreamlitによるチャットUI

各モジュールの要点

エントリーポイント(main.py)

  • 設定ファイルから各種APIキーや設定値を読み込む
  • プロンプトファイルからシステムプロンプトを読み込む
  • 回答生成後、質問・回答・参照ナレッジ・日時をスプレッドシートにログ記録
  • 例外発生時はスタックトレースをメールで通知
# UTC→JSTに変換して記録
dt_now_utc = datetime.datetime.now(datetime.UTC)
dt_now_jst = dt_now_utc + datetime.timedelta(hours=9)

⚠️ APIキー等の機密情報は設定ファイルに外出しし、コードに直書きしない


エラー通知モジュール

SMTPでGmailを使ったエラー通知メール送信。

smtpobj = smtplib.SMTP('smtp.gmail.com', 587)
smtpobj.starttls()
smtpobj.login(sendAddress, password)

⚠️ パスワードはGmailのアプリパスワードを使用。コードへの直書きは避け、設定ファイルや環境変数で管理する


Notion連携モジュール

NotionブロックAPIでページ内テキストを再帰的に取得。

  • next_cursor を使ったページネーション対応
  • rich_text を持たないブロックは安全にスキップ
  • リスト系ブロックは先頭に を付与

Pinecone連携モジュール

  • インデックスが存在しない場合は自動作成(次元数:1536、距離:euclidean)
  • index.update() でベクトルとメタデータ(ナレッジ本文)を更新

設定ファイルの構成例

[OPENAI]
OPENAI_API_KEY = your_api_key

[PINECONE]
PINECONE_API_KEY = your_api_key
PINECONE_EMVIRONMENT = us-east-1
PINECONE_INDEX = your_index_name

[NOTION]
NOTION_KEY = your_notion_key
NOTION_ID = your_database_id

[GSS]
GSS_TEMP_KEY = your_spreadsheet_key
GSS_NAME = your_spreadsheet_name
GSS_SHEET_NAME_LOG = log
KEY_FILE_NAME = credentials.json

DBメンテナンスバッチ

Notionのナレッジベースとの差分を検出し、Pineconeを自動で同期するバッチ処理。

処理フロー

スプレッドシートから最終実行日・ナレッジIDリスト取得
    ↓
Notionから全ページ情報を取得
    ↓
各ページの作成日・更新日と最終実行日を比較
    ↓ 新規 or 更新
    テキスト取得 → 質問文生成(OpenAI)→ ベクトル化 → Pineconeに登録/更新
    ↓
スプレッドシートの最終実行日を更新
    ↓
差分チェック(追加:未登録IDを登録 / 削除:消去IDをPineconeから削除)

ポイント

処理 内容
差分検出 スプレッドシートのIDリストとNotionのIDリストを set で差分比較
ベクトル化 ナレッジ本文 + OpenAIで生成した想定質問文を結合してベクトル化(検索精度向上)
削除同期 Notionで削除されたページはPineconeからも自動削除
エラー通知 例外発生時はスタックトレースをメール通知
# 差分チェックのコア部分
InsertDiff = list(set(notionIds) - set(gsIds))   # Notionにあってシートにない → 新規
DeleteDiff = list(set(gsIds) - set(notionIds))   # シートにあってNotionにない → 削除

フロントエンド(Streamlit)

StreamlitでチャットボットのフロントエンドUIを構築。

画面構成

  • チャット履歴をバブル形式で表示(ユーザー/ボットで色分け)
  • ボットの回答はMarkdown→HTMLに変換してレンダリング
  • 入力中は「考え中...」スピナーを表示

状態管理のポイント

Streamlitは毎回フルリロードされるため、st.session_state で状態を管理する。

# 回答の二重処理を防ぐフラグ制御
if last_msg["role"] == "user" and "answered" not in st.session_state:
    # 回答生成
    st.session_state.answered = True
    st.rerun()

elif "answered" in st.session_state:
    del st.session_state.answered  # 次回入力に備えてフラグをクリア

st.rerun() でユーザー入力を即時反映してから回答を生成することで、自然なチャット体験を実現


全体アーキテクチャ

【バッチ】DBメンテナンス(定期実行)
    Notion → テキスト抽出 → ベクトル化 → Pinecone登録/更新/削除
    ↓ IDリスト・実行日を管理
    スプレッドシート

【フロント】Streamlit
    ユーザー入力
    ↓
    main.py → Pinecone検索 → OpenAI回答生成
    ↓
    チャット画面に表示 + スプレッドシートにログ記録

ポイントまとめ

  • APIキーは設定ファイルで一元管理し、コードに直書きしない
  • エラーは必ずキャッチしてメール通知する運用にする
  • Notionのページネーションに対応することで大量ナレッジにも対応可能
  • スプレッドシートへのログ記録で運用後のQA分析が可能
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?