為了打造 Notion Rag 系統,在前 21 天,我們做了許多「資料流」的工作:
現在,是時候讓這些資料真正能「被問、被用」了。今天我們將從後端開始,建立一個最小可行的 RAG 系統:用戶輸入問題 → 系統檢索相關筆記 → 生成智慧回答。
RAG (Retrieval-Augmented Generation) = 檢索增強生成,是一種結合「資訊檢索」和「語言生成」的 AI 技術。那麼,為什麼需要 RAG 呢?
在 LLM 的世界裡,模型的能力取決於「它知道什麼」。 而LLM 的三大問題:
因此,我們用 RAG 來「補足模型的記憶」:給 LLM 提供「參考資料」,讓它根據資料回答!
1. 用戶提問
↓
2. 從知識庫檢索相關資料(Retrieval)
↓
3. 把檢索到的資料 + 問題一起給 LLM
↓
4. LLM 根據資料生成回答(Generation)
用戶:我們公司 Q3 營收多少?
AI:抱歉,我不知道你們公司的內部資料
用戶:我們公司 Q3 營收多少?
↓
系統:[從公司文件庫檢索] → 找到「Q3 財報.pdf」
↓
AI:根據 Q3 財報,營收為 500 萬美元,
較 Q2 成長 15%
今天的目標是實作一個最小可行版本(MVP),串接前面完成的 Embedding 和 ChromaDB。
📝 用戶提問
↓
🔢 問題向量化(Embedding)
↓
🔍 ChromaDB 檢索(Top 3 相關筆記)
↓
📋 組合 Prompt(檢索內容 + 問題)
↓
🤖 LLM 生成回答
↓
💬 返回結果給用戶
notion_rag_backend.py
import os
import chromadb
from openai import OpenAI
from dotenv import load_dotenv
# 1. 載入環境變數
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# 2. 初始化 Chroma Client
chroma_client = chromadb.PersistentClient(path="db/chroma_db")
collection = chroma_client.get_or_create_collection("notion_notes")
# 3. 定義檢索函式
def retrieve_context(query, top_k=3):
# 將 query 轉換為 embedding
embedding = client.embeddings.create(
model="text-embedding-3-small",
input=query
).data[0].embedding
# 從 ChromaDB 檢索最相關的 chunks
results = collection.query(
query_embeddings=[embedding],
n_results=top_k
)
docs = results["documents"][0]
metadatas = results["metadatas"][0]
return list(zip(docs, metadatas))
# 4. 組合 prompt 並請求 LLM
def generate_answer(query):
context_pairs = retrieve_context(query)
context_text = "\n\n".join([f"- {doc}" for doc, _ in context_pairs])
prompt = f"""
你是一位資料助理,請根據以下內容回答問題,若無相關資訊請說「資料庫中尚無此內容」:
---
{context_text}
---
問題:{query}
請以繁體中文回答,保留英文專有名詞。
"""
completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant for knowledge retrieval."},
{"role": "user", "content": prompt}
]
)
return completion.choices[0].message.content
# 5. 主程式入口
if __name__ == "__main__":
query = input("請輸入你的問題:")
answer = generate_answer(query)
print("\n🔍 回答:\n", answer)
chroma_client = chromadb.PersistentClient(path="db/chroma_db")
collection = chroma_client.get_or_create_collection("notion_notes")
get_or_create_collection()
:若 notion_notes
已存在則載入,否則新建。documents
:筆記內容的文字片段(chunk)embeddings
:每段文字的向量表示metadatas
:頁面、分類、來源資訊等retrieve_context()
embedding
向量。top_k
筆文件。metadata
的組合:
return list(zip(docs, metadatas))
text-embedding-3-small
→ 成本低、速度快,適合個人筆記系統。text-embedding-3-large
。generate_answer()
gpt-4o-mini
模型進行生成(性價比高)。你是一位資料助理,請根據以下內容回答問題,
若無相關資訊請說「資料庫中尚無此內容」:
---
{context_text}
---
問題:{query}
請以繁體中文回答,保留英文專有名詞。
這樣可讓 LLM 生成時有明確上下文,減少「幻覺性回答」。if __name__ == "__main__":
query = input("請輸入你的問題:")
answer = generate_answer(query)
print("\n🔍 回答:\n", answer)
假設我問:
Q:AI 的發展有什麼關鍵訊號?
輸出可能像這樣:
🔍 回答:
根據數創電子報的內容,AI 模型的長任務處理能力與真實工作表現正在加速進步。
主要訊號包括:
1️⃣ 模型可連續執行任務的時間每 7 個月翻倍。
2️⃣ AI 開始參與模型研發,形成自我強化的回饋迴路。
3️⃣ 人類角色正從執行轉向監督與策展。
這樣,我的「Notion 筆記」終於能夠像資料助手一樣被提問、被引用。
今天我們完成了第一個可運作的 RAG pipeline:
核心流程:問題 → 檢索 → 回答
這代表著從「靜態儲存」進化到「主動應用」—— Notion 筆記不再只是沉默的記錄本,而是能對話、能回應的智能知識助手。
下一步,我們將用 Streamlit 打造一個互動式前端介面。從 CLI 到視覺化,從技術原型到實用工具。