iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0
佛心分享-IT 人自學之術

LLM入門學習系列 第 27

Day 27 升級報告:Gradio ChatInterface 應用與透明度優化

  • 分享至 

  • xImage
  •  

一、學習目標與工程實現

本日目標是將 Day 24 產生的知識向量資料庫(持久化資料)載入,並使用 Gradio 建立一個可互動的 Web Chatbot。

任務目標 核心技術 實現說明
資料持久化載入 pickle, faiss.read_index 成功連結 Day 24 建立的 docs.pklindex.faiss
工程健壯性 FAISS + sklearn.NearestNeighbors 提供備援索引機制,提升系統穩定性。
前端部署 Gradio gr.Interface 建立可輸入查詢、輸出檢索結果的基礎問答介面。

二、程式碼解析:資料連結與檢索核心

本次延伸版程式碼的核心價值在於其工程的健壯性,能夠從磁碟讀取多種格式的索引,確保 RAG 檢索服務可以順利啟動。

(1) 模組一/二:知識庫與索引載入(Day 24 成果連結點)

此模組是 Day 24 成果的體現。它載入了 FAQ 文本 (docs.pkl)、向量 (embeddings.pkl),並優先嘗試載入 FAISS 索引,若失敗則退而求其次載入 sklearn 的備援索引。

#  載入資料路徑
data_dir = Path("faq_chatbot/data")
docs_pkl = data_dir / "docs.pkl"
embeddings_pkl = data_dir / "embeddings.pkl"
faiss_index_file = data_dir / "index.faiss"
nn_file = data_dir / "nn.pkl"

# ===== 1️ 載入知識資料 =====
print("載入 docs 和 embeddings ...")
with open(docs_pkl, "rb") as f:
    docs = pickle.load(f)
with open(embeddings_pkl, "rb") as f:
    embeddings = pickle.load(f)
print(f"✅ 已載入 {len(docs)} 筆 FAQ 資料")

# ===== 2️⃣ 嘗試載入索引 =====
use_faiss = False
index = None
nn = None

if faiss_index_file.exists():
    try:
        import faiss
        index = faiss.read_index(str(faiss_index_file))
        use_faiss = True
        print("✅ 使用 FAISS 索引")
    except Exception as e:
        print("⚠️ 無法載入 FAISS 索引:", e)

if not use_faiss and nn_file.exists():
    from sklearn.neighbors import NearestNeighbors
    import joblib
    nn = joblib.load(nn_file)
    print("✅ 使用 sklearn NearestNeighbors 備援索引")

# ===== 3️⃣ 載入 embedding 模型 =====
embed_model_name = "sentence-transformers/all-MiniLM-L6-v2"
embedder = SentenceTransformer(embed_model_name)

(2) 模組三:檢索與回答邏輯 (retrieve_answer)

retrieve_answer 函數實現了從使用者輸入到結果輸出的完整檢索鏈路。

def chatbot_reply(message, history):
    query = message.strip()
    if not query:
        return "請輸入問題喔~"
    
    query_vec = embedder.encode([query], convert_to_numpy=True)
    
    # 檢索相似問答
    if use_faiss and index is not None:
        D, I = index.search(query_vec.astype(np.float32), 3)
        results = [{"rank": i+1, "doc": docs[idx], "distance": float(D[0][i])} for i, idx in enumerate(I[0])]
    elif nn is not None:
        dists, idxs = nn.kneighbors(query_vec, n_neighbors=3)
        results = [{"rank": i+1, "doc": docs[idxs[0][i]], "distance": float(dists[0][i])} for i in range(len(idxs[0]))]
    else:
        return "❌ 尚未載入任何索引,請先執行 Day24 建立知識庫。"

    # ===== 生成清楚的回答 =====
    best_doc = results[0]["doc"]
    q_text = best_doc.split("\nA:")[0].replace("Q: ", "").strip()
    a_text = best_doc.split("\nA:")[1].strip() if "\nA:" in best_doc else best_doc
    
    answer = f"**問題:** {q_text}\n\n**回答:** {a_text}\n\n(相似度距離:{results[0]['distance']:.4f})"
    return answer

(3) 模組四:Gradio 介面建立與啟動

使用 gr.Interface 快速建立一個基礎的單次問答介面。

# ===== 5️⃣ 建立 Gradio 互動介面 =====
chatbot = gr.ChatInterface(
    fn=chatbot_reply,
    title="🤖 FAQ 智慧客服 Chatbot",
    description="輸入你的問題,我會從知識向量資料庫中找出最合適的答案。",
    theme="soft",
    textbox=gr.Textbox(placeholder="請輸入問題,例如:如何建立 Google 帳號?"),
    examples=[
        "如何建立 Google 帳號?",
        "我忘記密碼怎麼辦?",
        "如何設定兩步驟驗證?"
    ]
)
chatbot.launch()

三、成果總結

(1) 成果總結

本次延伸版成功地將後端數據工程與前端應用介面結合,證明了 RAG 系統可以從持久化數據中快速啟動服務。

  • 工程成熟度達到生產環境應用所需的健壯性(索引載入備援機制)。
  • 功能驗證:在 Web 介面中成功實現了 基於 Day 24 數據的語義檢索
    https://ithelp.ithome.com.tw/upload/images/20251012/201694888dhYBDXf5v.png
    https://ithelp.ithome.com.tw/upload/images/20251012/20169488DF9GCLeUF7.png

上一篇
Day 26:前端互動介面(Gradio)
下一篇
Day 28:系統優化與安全回答邏輯實作
系列文
LLM入門學習29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言