從 RAG 開始:讓大模型讀懂你的私有知識庫實戰指南

接續上回「從大模型應用開始」把 LLM API 接進前端之後,這次要解決一個更實際的問題:模型只知道訓練資料裡的公開知識,你公司的內部文件、產品手冊、私有資料,它一概不知道,而且還會「一本正經地胡說八道」。這篇文章我們用 RAG(檢索增強生成,Retrieval-Augmented Generation) 來解決——這是大模型應用進階的第一課,也是目前業界落地最廣的架構。

一、為什麼需要 RAG?

直接問大模型「我們公司的退貨流程是什麼」,它會出現兩種情況:要麼老實說不知道,要麼編一個看似合理的答案——這就是幻覺(Hallucination)。原因很簡單:模型的知識停留在訓練資料的截止日,而且它根本沒見過你的私有文件。

RAG 的思路很樸素:先查資料,再回答。就像開卷考試——與其讓考生硬背,不如讓他先翻書,再按書本內容作答。答案有據可查,幻覺自然大幅減少。

二、RAG 的核心流程

一個最小的 RAG 系統分成兩個階段:

  • 離線索引:把文件切成小塊(chunk),用嵌入模型(Embedding Model)把每塊文字變成一串向量,存進向量資料庫。
  • 線上問答:用戶提問 → 把問題也轉成向量 → 找出語義最相似的幾塊文件 → 拼進 Prompt → 交給 LLM 生成答案。

整條鏈路裡,LLM 只負責最後「讀資料、寫答案」,「去哪裡找資料、找哪些資料」完全由你的程式決定——這正是 RAG 可控、可審計的原因。

三、步驟 1:把文件切成小塊

切塊是 RAG 效果的第一道關卡。塊太大,檢索不精準還浪費 Token;塊太小,語義上下文斷裂。常見做法是按 300~500 字切塊,相鄰塊保留 10%~20% 的重疊(overlap),避免關鍵句子被硬生生切斷:

// 滑動窗口切塊(偽代碼)
function chunkText(text, size = 400, overlap = 80) {
  const chunks = [];
  for (let i = 0; i < text.length; i += size - overlap) {
    chunks.push(text.slice(i, i + size));
  }
  return chunks;
}

四、步驟 2:向量化與相似度檢索

把每個 chunk 和用戶問題都送進 Embedding 模型,各自變成一個高維向量。語義越相近的文字,向量夾角越小,用「餘弦相似度」衡量。實際專案不用自己算數學,直接用向量資料庫(如 pgvector、Qdrant、Milvus)的 topK 相似度查詢即可:

// 呼叫後端代理:問題向量化後查最相近的 4 塊文件
const res = await fetch("/api/rag/search", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: userQuestion, topK: 4 }),
});
const { chunks } = await res.json();

五、步驟 3:組裝 Prompt 交給 LLM

把檢索到的 chunks 拼進系統提示詞,連同用戶問題一起送給模型:

const prompt = `請僅根據下列參考資料回答問題。
若資料中沒有答案,請直接回答「資料中未提及」,不要自行推測。

【參考資料】
${chunks.join("\n---\n")}

【問題】${userQuestion}`;

重點:Prompt 裡必須明確要求「僅根據參考資料回答、找不到就說找不到」——這句話是抑制幻覺的關鍵,比任何參數調優都有效。

特別注意:API 金鑰永遠放在後端代理,別圖方便寫進前端;檢索到的文件內容要記得做轉義與長度截斷,防止 Prompt 注入與超出模型上下文視窗。

小結

RAG = 檢索 + 生成:離線階段把私有文件建成向量知識庫,線上階段先查再答。它讓 LLM 從「博學但過時」變成「精通你的私有資料」,而且知識更新不需要重新訓練模型——改資料庫就行。下一課我們聊聊 Function Calling,讓模型從「會回答」進化到「會行動」。

互動話題:你的工作或生活裡,有哪一堆文件最想餵給大模型?留言聊聊,我幫你設計檢索方案!