7-5. 【生成AI活用】社内ナレッジ検索・AI回答RAGダッシュボード

第5章(実践開発:スクレイピング・データ分析・生成AI活用)で学んだ生成AI(LLM)APIと、社内ドキュメントを高速にセマンティック検索(意味ベースの検索)できるベクトルデータベースを統合し、「社内ナレッジ検索・AI回答RAGダッシュボード」を構築します。

1. システムの設計と要件

本アプリケーションは、以下の技術要素を組み合わせて実現します。

  1. RAG(Retrieval-Augmented Generation): 社内マニュアルや規程などのテキストをベクトル化して保持し、ユーザーの質問に関連する情報を自動で検索・参照してハルシネーション(嘘の回答)を防ぐ仕組み。
  2. Chroma DB: 軽量かつローカルで動作する高速なベクトルデータベース。
  3. Google Gemini API / OpenAI API: 検索された文脈をベースに、ユーザーの質問に対する自然な回答を生成。
  4. Streamlit: 非エンジニアの社員でもブラウザから直感的に質問・検索を行えるWebダッシュボード。

2. 実装コード(rag_dashboard.py)

以下のコードを rag_dashboard.py というファイル名で保存し、手元で動かしてみましょう(事前に pip install streamlit chromadb google-generativeai が必要です)。

Python

import os
import streamlit as st
import chromadb
import google.generativeai as genai

# --- 1. ページ設定と初期化 ---
st.set_page_config(page_title="社内ナレッジAIアシスタント", layout="wide")
st.title("🤖 社内マニュアル・ナレッジ検索 AIアシスタント(RAG)")
st.markdown("社内の各種規定やマニュアル文書をAIが横断検索し、根拠となる情報と共にご質問にお答えします。")

# Chroma DB の初期化(ローカルメモリ上に作成)
@st.cache_resource
def init_vector_db():
    client = chromadb.Client()
    collection = client.get_or_create_collection(name="company_knowledge_base")
    
    # 初期データの登録(実際の運用ではPDFやMarkdownファイルから読み込んで登録します)
    sample_docs = [
        "リモートワーク手当は、月額一律 5,000 円が給与に上乗せして支給されます。",
        "有給休暇の申請は、取得希望日の 3 営業日前までに社内ワークフローシステムより申請してください。",
        "社内サーバーへのアクセスには、VPN接続および二段階認証(2FA)の設定が必須となります。",
        "経費精算の締め日は毎月末日であり、翌月の第 5 営業日までに申請と領収書の提出が必要です。"
    ]
    sample_ids = ["doc_001", "doc_002", "doc_003", "doc_004"]
    
    # 既存データがない場合のみ登録
    if collection.count() == 0:
        collection.add(documents=sample_docs, ids=sample_ids)
    
    return collection

collection = init_vector_db()

# --- 2. サイドバー:新規ナレッジの追加 ---
st.sidebar.header("📝 ナレッジ(ドキュメント)の追加")
new_doc_id = st.sidebar.text_input("ドキュメントID (例: doc_005)")
new_doc_text = st.sidebar.text_area("ドキュメントの内容を入力")

if st.sidebar.button("ベクトルDBに登録"):
    if new_doc_id and new_doc_text:
        collection.add(documents=[new_doc_text], ids=[new_doc_id])
        st.sidebar.success(f"ドキュメント '{new_doc_id}' を追加しました!")
    else:
        st.sidebar.error("IDと内容の両方を入力してください。")

# --- 3. メイン画面:検索・RAG質問応答 ---
st.subheader("💬 AIへの質問・検索窓")
user_query = st.text_input("質問を入力してください (例: 「有給はいつまでに申請すればいい?」)")

if user_query:
    with st.spinner("AIが社内ナレッジを検索・考察中..."):
        # 1. ユーザーの質問に類似する社内文書をベクトル検索(上位2件取得)
        search_results = collection.query(query_texts=[user_query], n_results=2)
        retrieved_docs = search_results['documents'][0] if search_results['documents'] else []
        
        # 2. 検索された文脈(Context)を結合
        context_text = "\n".join([f"- {doc}" for doc in retrieved_docs])
        
        # 3. プロンプトの構築
        prompt = f"""
以下の【社内ナレッジ(参考情報)】をもとに、質問に対して正確に回答してください。
もし参考情報の中に答えが含まれていない場合は、「社内ナレッジからは確認できませんでした」と正直に答えてください。

【社内ナレッジ(参考情報)】
{context_text}

【質問】
{user_query}
"""
        
        # 4. 生成AI APIの呼び出し (例: Gemini 1.5 Flash)
        # ※ 実際に動かす際は環境変数に GEMINI_API_KEY を設定してください
        api_key = os.environ.get("GEMINI_API_KEY", "YOUR_API_KEY_HERE")
        
        try:
            if api_key != "YOUR_API_KEY_HERE":
                genai.configure(api_key=api_key)
                model = genai.GenerativeModel('gemini-1.5-flash')
                response = model.generate_content(prompt)
                ai_answer = response.text
            else:
                # APIキーが未設定の場合はモック回答を表示
                ai_answer = f"(APIキー未設定のためプレビュー表示)\nAIが以下の参考情報をもとに回答を生成します。\n\n【参照されたナレッジ】\n{context_text}"
        except Exception as e:
            ai_answer = f"API呼び出しエラーが発生しました: {e}"

        # 5. 結果の表示
        st.markdown("### 💡 AIの回答結果")
        st.info(ai_answer)
        
        with st.expander("🔍 根拠となった社内ナレッジ(参照コンテキスト)"):
            for i, doc in enumerate(retrieved_docs, 1):
                st.write(f"{i}. {doc}")

3. アプリケーションの起動方法

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

Bash

streamlit run rag_dashboard.py

ブラウザが自動で立ち上がり、社内規定の検索や質問に対するAIの根拠付き回答をインタラクティブにテストできます。

まとめ

本記事では、第5章で学んだ生成AI(LLM)APIの活用法と、Chroma DBによるベクトル検索を組み合わせて、ハルシネーションを防ぎながら社内情報を正確に引き出すRAGシステムをStreamlitで構築しました。

コメント

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