本教學將透過一個實際範例,示範完整的 RAG(Retrieval-Augmented Generation,檢索增強生成)實作。我們將從零開始建立一個向量資料庫,並使用一份範例報告文件執行 RAG 工作流程的全部五個步驟。
設定向量資料庫
此實作使用自訂的 VectorIndex 類別,負責儲存嵌入向量並執行相似度搜尋。這個類別提供了我們進行向量資料庫操作所需的核心功能。
五步驟 RAG 實作
步驟 1:依章節切分文字
首先,我們使用先前介紹過的以章節為基礎的切分方法,載入並切分我們的來源文件:
with open("./report.md", "r") as f:
text = f.read()
chunks = chunk_by_section(text)這會將我們的報告拆分成可以獨立處理的邏輯章節。
步驟 2:為每個區塊產生嵌入向量
接下來,我們使用列表推導式為每個區塊建立嵌入向量:
embeddings = [generate_embedding(chunk) for chunk in chunks]這個步驟涉及多次 API 呼叫,因此需要一些時間才能完成。每個區塊都會被轉換成數值向量表示。
步驟 3:將嵌入向量儲存到向量資料庫中
現在我們建立向量儲存區,並將嵌入向量及其對應的文字一併填入:
store = VectorIndex()
for embedding, chunk in zip(embeddings, chunks):
store.add_vector(embedding, {"content": chunk})這裡的關鍵在於,我們同時儲存了嵌入向量和原始文字。僅僅取回一串數字並沒有用處——我們需要的是與這些嵌入向量對應的實際文字內容。這個元資料讓我們之後能夠取得有意義的結果。
步驟 4:產生使用者查詢的嵌入向量
當使用者提出問題時,我們會將其轉換成相同的嵌入格式:
user_embedding = generate_embedding("What did the software engineering dept do last year?")這會建立使用者問題的向量表示,可用於與我們儲存的嵌入向量進行比較。
步驟 5:搜尋並檢索相關區塊
最後,我們搜尋向量儲存區,找出最相似的內容:
results = store.search(user_embedding, 2)
for doc, distance in results:
print(distance, "\n", doc["content"][0:200], "\n")這會回傳兩個最相關的區塊,以及它們的餘弦距離分數。距離越小,表示相似度越高。

理解結果
搜尋結果會依相關性排序。在我們的範例中,軟體工程章節的距離最小(0.71),因此是最相關的匹配結果。方法論章節則以 0.72 的距離排名第二。
距離指標能幫助您了解系統對每個結果相關性的信心程度。距離越近,表示與使用者查詢的匹配度越好。
為何要將文字與嵌入向量一併儲存
一個關鍵的設計決策,就是將原始文字與每個嵌入向量一併儲存。如果沒有這樣做,您只會取回一堆數字陣列,這對於產生回應並沒有用處。透過納入來源文字,您就能立即使用檢索到的區塊,為您的語言模型提供上下文。
這樣就完成了核心的 RAG 工作流程,不過在實際應用場景中,還有其他可以提升效能的優化與改進方式。