整理自多方資料
如果只有 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 分鐘體驗)
用 Dify 或 Coze 這類平台,拖拉式介面:
- 上傳你的文件(PDF、Markdown 都行)
- 平台自動幫你切 chunk、建 embedding、存向量
- 直接在介面上問問題,馬上能用
適合:先驗證「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. 組裝 Prompt | chunk + 問題交給 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,先跑起來再慢慢優化。
延伸思考
-
如果你的團隊文件同時有中文和英文,embedding 模型該怎麼選? 同一個模型能同時處理多語言嗎?還是需要分開處理?
-
當文件持續更新(比如每週都有新的 release note),你的 RAG 系統怎麼保持索引是最新的? 要全部重建,還是可以只更新有變動的部分?
整理自:LlamaIndex 官方文件、Vercel AI SDK、AWS - What is RAG?、Supabase pgvector 指南 等多方資料