/

從零開始建立 RAG 系統:完整流程拆解

整理自多方資料

如果只有 30 秒,這在說什麼?

RAG 聽起來很厲害,但流程其實就兩件事:先把你的文件切碎、變成數字存起來(建索引),之後每次有人問問題,就去找最相關的碎片塞給 AI 看(查詢)。搞懂這兩步,你就能自己建一個 RAG 系統。

核心概念拆解

1. Chunking(切 Chunk)

一句話解釋: 把一份長文件切成一小段一小段,方便後續搜尋和比對。

生活中的比喻: 想像你有一本 500 頁的使用手冊。有人問你「怎麼重設密碼?」你不會把整本書丟給他,而是翻到第 87 頁第三段,把那一段撕下來遞過去。Chunking 就是事先把整本書拆成一段一段,讓系統能精準地找到「那一段」。

為什麼重要: 切太大,AI 會抓不到重點,像是給它整本書叫它回答一個小問題。切太小,每段資訊不完整,AI 拼不出有意義的答案。通常 500-1000 個 token 一段,段跟段之間留一點重疊(overlap),是目前最常見的做法。

2. Embedding(向量嵌入)

一句話解釋: 把一段文字轉換成一串數字(向量),讓電腦能計算「兩段話有多像」。

生活中的比喻: 想像每段文字都有一個 GPS 座標。意思相近的文字,座標就會靠在一起。「如何請假」和「休假申請流程」字面上完全不同,但它們的座標會非常靠近——因為它們在講同一件事。

為什麼重要: 這是 RAG 能做到「語意搜尋」的關鍵。傳統搜尋只能比對關鍵字,Embedding 能理解意思。

3. Vector Store(向量儲存)

一句話解釋: 一個專門用來存放和搜尋向量的資料庫。

生活中的比喻: 你有 10 萬個 GPS 座標(每段文件一個)。有人給你一個新座標(問題),你要在幾毫秒內找出離它最近的 5 個點。向量資料庫就是專門做這件事的——超快速的「找鄰居」系統。

為什麼重要: 沒有它,每次查詢都要重新算所有文件的相似度,資料量大的時候根本跑不動。

4. Prompt Augmentation(提示詞增強)

一句話解釋: 把搜尋到的文件片段塞進 AI 的提示詞裡,讓它「看著資料回答」。

生活中的比喻: 你問一個很聰明的朋友一個專業問題。如果你只問問題,他可能亂猜。但如果你同時遞給他三份相關文件說「看完這些再回答」,他的答案就會靠譜得多。

為什麼重要: 這一步決定了 AI 回答的品質。塞對了資料,答案精準;塞錯了資料,答案就會驢唇不對馬嘴。

完整流程:用一個具體例子走一遍

假設你要做一個「團隊元件庫問答機器人」,文件有 Button.md、Modal.md、Form.md 等 100 個檔案。

階段一:建索引(做一次就好)

你的文件                    系統處理
┌─────────────┐
│ Button.md   │─→ 切成小段 ─→ 每段轉成向量數字 ─→ 存進向量資料庫
│ Modal.md    │   "Button 支援     [0.12, -0.34,     DB: chunk_id → 向量
│ Form.md     │    primary 和       0.78, ...]
│ Table.md    │    secondary"
│ ...100個檔案│
└─────────────┘

白話說:把文件切碎 → 變成數字 → 存起來。文件沒更新的話,這步不用再跑。

階段二:查詢(每次提問都跑)

使用者問:「Modal 怎麼用 controlled mode?」
         │
         ▼
  ① 問題轉成向量 [0.08, -0.29, 0.81, ...]
         │
         ▼
  ② 拿去向量資料庫比對,找出最像的 3~5 個 chunk
     → "Modal 支援 controlled 和 uncontrolled 兩種模式..."
     → "使用 isOpen 和 onClose props 控制開關..."
     → "範例:<Modal isOpen={show} onClose={...}>"
         │
         ▼
  ③ 組裝 prompt,交給 LLM
     ┌──────────────────────────────────────┐
     │ 根據以下文件回答問題,不要編造。      │
     │                                      │
     │ 【文件】                              │
     │ Modal 支援 controlled 和 ...          │
     │ 使用 isOpen 和 onClose props...       │
     │ 範例:<Modal isOpen={show}...          │
     │                                      │
     │ 【問題】Modal 怎麼用 controlled mode?│
     └──────────────────────────────────────┘
         │
         ▼
  ④ LLM 回答
     "傳入 isOpen 和 onClose 兩個 props:
      const [show, setShow] = useState(false);
      <Modal isOpen={show} onClose={() => setShow(false)}>
        ...
      </Modal>"

就這樣。整個 RAG 的魔法就在第②步——找到對的文件碎片,AI 自然就能給出對的答案。

動手做:三種起步方式

方式一:零程式碼(5 分鐘體驗)

DifyCoze 這類平台,拖拉式介面:

  1. 上傳你的文件(PDF、Markdown 都行)
  2. 平台自動幫你切 chunk、建 embedding、存向量
  3. 直接在介面上問問題,馬上能用

適合:先驗證「RAG 對我的場景有沒有用」,不寫一行程式碼。

方式二:Python + LlamaIndex(最主流)

from llama_index.core import SimpleDirectoryReader, VectorStoreIndex

# 建索引:讀文件 → 切 chunk → embedding → 存起來
documents = SimpleDirectoryReader("./docs").load_data()
index = VectorStoreIndex.from_documents(documents)
index.storage_context.persist()  # 存到硬碟,下次不用重建

# 查詢
query_engine = index.as_query_engine()
response = query_engine.query("Modal 怎麼用 controlled mode?")
print(response)

六行程式碼,LlamaIndex 把切 chunk、embedding、向量搜尋、組 prompt 全部包好了。

方式三:TypeScript + Vercel AI SDK(前端工程師友善)

import { openai } from '@ai-sdk/openai';
import { generateText, embed } from 'ai';

// === 建索引(跑一次)===
const chunk = "Modal 支援 controlled 和 uncontrolled 兩種模式...";
const { embedding } = await embed({
  model: openai.embedding('text-embedding-3-small'),
  value: chunk,
});
await db.insert({ text: chunk, vector: embedding });

// === 查詢(每次提問)===
// 1. 問題轉向量
const { embedding: queryVec } = await embed({
  model: openai.embedding('text-embedding-3-small'),
  value: "Modal 怎麼用 controlled mode?",
});

// 2. 向量搜尋
const relevantChunks = await db.similaritySearch(queryVec, 5);

// 3. 塞進 prompt 給 LLM
const { text } = await generateText({
  model: openai('gpt-4o'),
  prompt: `根據以下文件回答,不要編造:
${relevantChunks.map(c => c.text).join('
---
')}

問題:Modal 怎麼用 controlled mode?`,
});

向量資料庫可以用 Supabase pgvector(免費額度夠用),跟 Next.js 專案無縫整合。

流程總覽

步驟做什麼什麼時候跑
1. 收集文件把 .md / .pdf / .txt 準備好文件更新時
2. 切 Chunk長文件切成 500-1000 token 的小段同上
3. Embedding每個 chunk 轉成向量數字同上
4. 存進向量 DB向量存起來供搜尋同上
5. 問題轉向量使用者的問題也轉成向量每次提問
6. 向量搜尋找出最相似的 chunk每次提問
7. 組裝 Promptchunk + 問題交給 LLM每次提問
8. 生成回答LLM 根據真實資料回答每次提問

1-4 是「建索引」,做一次就好。5-8 是「查詢」,每次提問都跑。

最容易搞錯的地方

很多人以為 RAG 最重要的是選哪個 LLM,但實際上 檢索品質才是關鍵。再強的 LLM,如果你塞給它的文件不對,它也回答不好。先把 chunk 策略和 embedding 模型搞好,比換一個更貴的 LLM 有效得多。

很多人以為把文件丟進去就搞定了,但實際上 文件的「前處理」佔了 80% 的工作量。PDF 裡的表格怎麼解析?圖片裡的文字要不要 OCR?Markdown 的標題要不要當成 chunk 的邊界?這些細節直接影響搜尋品質。

很多人以為 chunk 切越小越精準,但實際上 切太小會讓每段話失去上下文。比如一段只有「回傳值是 boolean」,AI 根本不知道在講哪個函式的回傳值。所以切 chunk 時要帶 overlap(前後重疊),或是在每個 chunk 前面加上它屬於哪個文件、哪個章節的資訊。

用自己的話說一遍

建一個 RAG 系統,本質上就是在幫 AI 打造一個「開卷考試」的環境。

第一步是準備考試用的小抄——把你的文件切成小段,每段轉成一串數字存起來。這串數字代表了這段文字的「意思」,讓電腦能用數學方式比較兩段話像不像。

第二步是考試本身——使用者問問題時,系統先把問題也轉成數字,去小抄庫裡找最相關的幾段,然後把這些段落跟問題一起交給 AI。AI 看著這些真實資料回答,自然就不容易瞎掰了。

整件事最關鍵的不是 AI 多聰明,而是你的「小抄」做得好不好——文件有沒有切對、搜尋有沒有找到對的段落。這就是為什麼大家說 RAG 是「garbage in, garbage out」,資料品質決定一切。

起步的話,先用 Dify 體驗一下效果,確認有用再用 LlamaIndex 或 Vercel AI SDK 自己寫。不需要一開始就搞向量資料庫和複雜的 pipeline,先跑起來再慢慢優化。

延伸思考

  1. 如果你的團隊文件同時有中文和英文,embedding 模型該怎麼選? 同一個模型能同時處理多語言嗎?還是需要分開處理?

  2. 當文件持續更新(比如每週都有新的 release note),你的 RAG 系統怎麼保持索引是最新的? 要全部重建,還是可以只更新有變動的部分?


整理自:LlamaIndex 官方文件Vercel AI SDKAWS - What is RAG?Supabase pgvector 指南 等多方資料

分享