本文同步刊登於 BASHCAT 官網 ,最新修訂以官網版本為準。
在我們做過的 RAG 專案裡,卡關的原因很少是模型不夠聰明,多半是檢索這一步拿錯了資料。模型拿到錯的段落,就會很有自信地把錯的答案講得頭頭是道;拿到對的段落,回答品質才有基礎可言。
我們幫金融科技客戶做過一套 企業 RAG 知識庫 ,最後平均回應時間壓在 3 秒內,在客戶自己的內部題庫評測中回答準確率為 92%(題庫與評分標準由客戶定義,僅供參考)。回頭看,真正花時間的地方幾乎都在模型之外:文件怎麼切、中文怎麼搜、權限怎麼擋、品質怎麼量。這篇把這些環節按順序攤開來講,附上可以直接拿去用的程式片段,和我們踩過的坑。

先問一個問題:你真的需要 RAG 嗎?
RAG(Retrieval-Augmented Generation,檢索增強生成)的概念出自 Lewis 等人 2020 年在 NeurIPS 發表的 論文 :先從外部知識庫找出相關段落,再交給語言模型生成答案。它解決的是「模型沒讀過你公司的資料」和「資料會一直更新」這兩件事。
不過現在模型的 context window 已經很大,資料量小的時候,RAG 反而是多此一舉。Anthropic 在 Contextual Retrieval 這篇文章直接建議:知識庫小於 20 萬 token(大約 500 頁)時,可以把整份內容放進 prompt,搭配 prompt caching 降低成本與延遲,不必建檢索系統。
所以第一步先估資料量:
| 情境 | 建議做法 |
|---|---|
| 一份產品手冊、幾十頁規章,總量小於 20 萬 token | 直接放進 prompt,加 prompt caching |
| 上千份文件、每週都有更新 | RAG |
| 不同部門、不同職級只能看不同文件 | RAG,而且一開始就要設計權限(後面細講) |
| 問題多半是「整體趨勢、主要主題是什麼」這類綜觀型問題 | 考慮 GraphRAG(後面細講) |
RAG 架構全貌:資料怎麼從文件變成答案
一套企業 RAG 可以拆成「離線建索引」和「線上回答」兩條流程:
| 階段 | 做什麼 | 常見工具 |
|---|---|---|
| 1. 收集與解析 | 從 SharePoint、Google Drive、Confluence、檔案伺服器抓文件,PDF/Word/投影片轉成乾淨文字,同時記下每份文件的權限 | Unstructured、Azure Document Intelligence、自寫 parser |
| 2. 切塊(chunking) | 把長文件切成幾百 token 的段落,保留標題路徑等 metadata | LangChain/LlamaIndex 的 splitter |
| 3. 向量化(embedding) | 每個段落轉成向量 | BGE-M3、OpenAI、Cohere 等 embedding 模型 |
| 4. 建索引 | 向量索引+全文索引並存 | Azure AI Search、pgvector、Qdrant、Elasticsearch |
| 5. 檢索 | 使用者提問時,用關鍵字與向量各找一批候選 | 混合搜尋 |
| 6. 重排序(rerank) | 用更精準的模型把候選重新排序,只留前幾名 | Cross-encoder reranker |
| 7. 生成與引用 | 把段落交給 LLM 回答,並標出來源文件 | GPT、Claude、Gemini 等 |
在我們的專案裡,第 5、6 步對回答品質影響最大,第 1 步的權限設計則決定了這套系統能不能上線。下面依序講。
切塊:別迷信 overlap,也別塞太多段落
切塊(chunking)是最常被當成「設個參數就好」的步驟,偏偏影響很大。
2026 年 1 月一篇系統性比較切塊策略的 論文 (Bennani & Moslonka)在 Natural Questions 上做了端對端評估,結論有幾個很實用:
- overlap 沒有可量測的幫助,只會增加索引成本。很多教學預設 10–20% overlap,其實可以先拿掉再驗證。
- 句子切塊是最划算的做法:在論文測試的約 5k token 範圍內,表現和語意切塊(semantic chunking)差不多,成本低很多。
- 餵給模型的 context 超過約 2.5k token 後品質開始下滑,作者稱為「context cliff」。
這篇論文用的是 SPLADE 檢索加 Mistral-8B,換成別的組合數字不一定照搬,但方向很清楚:不要以為塞越多段落給模型越好。
實務上我們會這樣做:
- 先依文件結構切(標題、章節、條列),再在結構內按句子切到幾百 token。
- 每個 chunk 都帶 metadata:來源檔名、章節標題路徑、更新日期、權限群組。標題路徑很重要,「第三章 > 退款 > 例外情況」這種上下文,光看段落本身是看不出來的。
- 表格不要硬切成文字流。拆成「一列一段」並保留表頭,或另外存結構化資料,不然數字會和欄位名稱對不起來。
中文的坑:embedding 與斷詞
台灣企業的文件多半是繁體中文夾雜英文術語,這裡有兩個常被忽略的問題。
embedding 模型要支援多語。例如 BGE-M3 支援 100 多種語言、單段最長 8192 token、MIT 授權,可以自架;而且一個模型同時輸出稠密向量(dense)、稀疏詞彙權重(sparse)和多向量(multi-vector)三種表示,很適合拿來做混合搜尋。選模型時,用下面「建立評估集」那段準備的真實問題測一輪,比看排行榜可靠。
關鍵字搜尋要能正確斷詞。中文沒有空格,預設的分析器常常把整句當成一個詞,搜「退貨流程」可能完全搜不到「退貨的處理流程」。各家的處理方式:
- Azure AI Search:欄位分析器設為
zh-Hant.microsoft或zh-Hant.lucene。 - PostgreSQL:內建全文搜尋不會切中文,要另外裝 pg_bigm(二元切詞)或中文斷詞擴充。
- Elasticsearch/OpenSearch:裝 IK 或 smartcn 這類中文分析器。
混合搜尋+重排序:檢索品質的最大槓桿

純向量搜尋擅長「意思相近但用詞不同」的查詢,卻常漏掉精確字詞。微軟在 Azure AI Search 的混合搜尋文件 講得很直接:產品型號、專業術語、日期、人名這類查詢,關鍵字搜尋表現更好,因為它能抓到完全符合的字;而他們在真實資料與基準資料集上的測試顯示,混合搜尋加上語意重排序,相關性有明顯提升。
企業文件裡充滿料號、法規條號、專案代碼,所以我們的專案預設都用混合搜尋。兩路結果怎麼合併?最常用的是 RRF(Reciprocal Rank Fusion):每份文件的分數 = 它在各路結果中「1 ÷(k + 排名)」的總和。好處是不用把 BM25 分數和向量相似度換算到同一個尺度。下面是可以直接執行的 Python 版本:
from collections import defaultdict
def rrf(result_lists, k=60, top_n=50):
"""Reciprocal Rank Fusion:合併多路檢索結果,k=60 沿用 Cormack 等人 2009 年原始論文的設定"""
scores = defaultdict(float)
for results in result_lists:
for rank, doc_id in enumerate(results, start=1):
scores[doc_id] += 1.0 / (k + rank)
return sorted(scores, key=scores.get, reverse=True)[:top_n]
bm25_hits = ["doc7", "doc2", "doc9", "doc4"] # 關鍵字搜尋結果(依排名)
vector_hits = ["doc2", "doc5", "doc7", "doc1"] # 向量搜尋結果(依排名)
print(rrf([bm25_hits, vector_hits]))
# ['doc2', 'doc7', 'doc5', 'doc9', 'doc4', 'doc1']
兩路都排得前面的 doc2、doc7 自然浮上來。合併後取前 50 筆左右,交給 reranker(cross-encoder,例如 bge-reranker 系列或雲端的 rerank API)重新打分,最後依 token 預算決定留幾段:每段 300–500 token 的話,3–5 段大約是 1k–2.5k token,剛好在前面那篇論文的 context cliff 以內,適合當起點;再用評估集測試往上加段數有沒有幫助。那個 2.5k 門檻是在特定模型上量到的,你的上限要自己測出來。
這套組合的效果有多大?Anthropic 在 Contextual Retrieval 實驗裡用「前 20 筆沒撈到正確段落的比例」當指標:
| 做法 | 檢索失敗率 | 相對降低 |
|---|---|---|
| 一般 embedding | 5.7% | - |
| Contextual Embeddings | 3.7% | 35% |
| Contextual Embeddings+Contextual BM25 | 2.9% | 49% |
| + 重排序 | 1.9% | 67% |
所謂 Contextual Retrieval,是在建索引時先讓 LLM 替每個 chunk 寫一兩句「這段在整份文件中講什麼」,再把這句話接在 chunk 前面一起做 embedding 和 BM25。用 prompt caching 的話,Anthropic 估算的一次性成本是每百萬 token 文件 1.02 美元(假設每份文件 8k token、每個 chunk 800 token、每段補 100 token 的說明),實際費用會隨文件長度與模型價格變動。這些數字是 Anthropic 自己的跨領域平均,換到你的資料要重新驗證,但「混合搜尋+重排序」帶來的提升方向,和微軟的結論一致。
權限控管:企業 RAG 最容易出事的地方

這是 Demo 和正式上線之間最大的差距。向量資料庫本身不知道「現在是誰在問」,如果檢索時沒過濾權限,實習生問一句「今年的調薪幅度」,模型就可能引用人資的機密簡報。
OWASP 在 2025 年版 LLM 應用十大風險裡,把這類問題獨立成 LLM08:Vector and Embedding Weaknesses ,列出的風險包括:存取控制不足造成資料外洩、多租戶共用向量庫時的跨使用者洩漏、從 embedding 反推原文,以及資料投毒。官方建議的第一條防線,就是使用「具權限意識(permission-aware)的向量與 embedding 儲存」,並嚴格切分資料集。
落地時記住三個原則:
- 在檢索階段過濾,不要靠 prompt。在 prompt 裡寫「不要透露機密」沒有用,模型已經看到了。權限要在搜尋時就套上,未授權的段落根本不進 context。
- 過濾條件由伺服器端依登入身分產生,絕不接受前端傳來的群組參數。
- 權限要跟著來源系統同步。某人被移出群組,索引裡的權限沒更新,就是一個正在發生的洩漏。
以 PostgreSQL+pgvector 為例,每個 chunk 存一欄允許的群組,查詢時帶上群組條件並依距離排序(近似索引實際的執行順序見下方說明):
-- 索引:向量用 HNSW,群組陣列用 GIN
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON chunks USING gin (allowed_groups);
-- ef_search 預設 40,要取 50 筆需調高;pgvector 0.8.0 起支援迭代掃描,避免過濾後結果不足
SET hnsw.ef_search = 100;
SET hnsw.iterative_scan = relaxed_order;
SELECT id, source_file, content
FROM chunks
WHERE allowed_groups && $1::text[] -- 使用者所屬群組,由伺服器端依登入身分帶入
ORDER BY embedding <=> $2::vector -- 餘弦距離
LIMIT 50;
這裡有個細節:pgvector 的近似索引(HNSW、IVFFlat)是先掃索引、再套過濾條件,權限很分散時可能撈不到足夠的結果,所以要開啟 0.8.0 加入的 iterative scan。relaxed_order 的結果不保證嚴格依距離排序,需要嚴格順序時改用 strict_order,或在外層查詢再排序一次;反正後面還會經過 reranker,多數情況用 relaxed 即可。另外,迭代掃描有上限(hnsw.max_scan_tuples,預設 20,000),權限極度分散時仍可能不足 50 筆;上線前用 EXPLAIN 確認規劃器實際用的是 HNSW 還是 GIN 索引。用 Azure AI Search 的話,正式推出的做法是 security filters(以使用者或群組 ID 做字串比對的安全性篩選);直接用 Microsoft Entra 身分比對 ADLS Gen2 的 ACL/RBAC、SharePoint 權限與 Purview 敏感度標籤的原生功能,截至 2026 年 10 月都還在預覽,細節見 官方文件層級存取說明 。
怎麼知道 RAG 有沒有變好?建立評估集
沒有評估,每次調參數都是憑感覺。我們的經驗做法是先準備 50–100 題「真實使用者會問的問題+標準答案+應該引用的文件」,每次改切塊、換模型、調 top-k 都跑一輪。
指標可以用開源框架 Ragas 的四個核心指標,分數越高越好:
| 指標 | 量什麼 | 分數低代表 |
|---|---|---|
| Context Precision | 撈回來的段落中,相關的比例與排序 | 檢索雜訊太多 |
| Context Recall | 回答所需的資訊有沒有被撈到(需要標準答案) | 檢索漏掉關鍵段落 |
| Faithfulness | 回答的每個說法是否都有段落支持 | 模型在「腦補」 |
| Response Relevancy | 回答是否切題 | 答非所問 |
這四個指標拆開看,就能分辨問題出在檢索還是生成,不會一律怪模型。另外要提醒,這些指標本身由 LLM 判讀,也會有誤差,關鍵題目仍要人工抽查。
進階選項:什麼時候用 GraphRAG?
一般 RAG 擅長「某條規定怎麼寫」這種精確問題,但遇到「這一年客訴的主要原因有哪些」這種要綜觀整個資料集的問題,只撈幾段文字是答不好的。
微軟研究院的 GraphRAG 論文 針對這類「全域理解」問題,先用 LLM 從文件抽出實體與關係建成知識圖譜,再分群寫摘要。在約百萬 token 的資料集上,它在回答的完整性與多樣性都明顯優於一般 RAG。代價是建索引時要大量呼叫 LLM,成本和時間都高很多。
我們的建議是:先把基本的混合搜尋+重排序做好,確認使用者真的大量在問綜觀型問題,再考慮 GraphRAG,不要一開始就上。
技術選型:用雲端服務還是自架?
| 方案 | 適合情境 | 優點 | 要注意 |
|---|---|---|---|
| Azure AI Search | 已在用 Microsoft 365/Azure 的企業 | 混合搜尋、語意重排序、繁中分析器都內建,權限可用 security filters | 費用隨索引規模與重排序用量增加;Entra 原生 ACL 仍在預覽 |
| PostgreSQL+pgvector | 已有 Postgres、資料量中等、想自己掌控 | 向量、全文、權限過濾都在同一個資料庫,SQL 就能寫 | 中文全文搜尋要自己裝擴充,重排序要另外接 |
| 專用向量資料庫(Qdrant、Weaviate、Pinecone 等) | 向量量體大、需要高吞吐 | 向量檢索效能與功能完整 | 權限資料要和來源系統同步,架構多一個元件 |
我們的經驗是:中小型專案從 pgvector 起步最快,資料、權限、應用都在同一個 Postgres 裡,維運簡單;已經全面使用 Microsoft 生態系的企業,直接用 Azure AI Search 能省下大量整合工作;向量量體大、對吞吐有要求時再考慮專用向量資料庫,我們的金融科技案例就是用 Pinecone。
踩坑清單
- 掃描檔 PDF 沒做 OCR:解析出來是空白,知識庫等於少了一塊。上線前先統計每份文件抽出的文字量,抓出異常的檔案。
- 同一份規章有好幾個版本:舊版和新版一起被撈到,模型會混著回答。建索引時就要標版本與生效日,檢索時優先新版。
- 只測自己想得到的問題:開發者問的問題和第一線同事問的差很多。評估集一定要收真實提問。
- 回答沒有引用來源:使用者無法驗證,就不敢用。每個回答都要附上原始文件連結和段落。
- 一次塞 50 段給模型:成本變高,品質反而下降(還記得前面的 context cliff)。重排序後只留真正相關的。
常見問題
RAG 和微調(fine-tuning)差在哪?該選哪個? RAG 是在回答時查資料,適合會更新、需要引用來源的知識;微調是改變模型本身的行為與語氣,不適合用來塞大量會變動的事實。以企業知識庫問答來說,通常選 RAG;兩者也可以並用。
建一套企業 RAG 知識庫要多久? 資料來源單純、權限簡單的 POC 大約幾週可以做出來;要串多個資料來源、處理文件權限、建立評估集並上線,通常要以月計算。我們的金融科技案例從需求到上線約 6 個月。
資料可以不上雲嗎? 可以。embedding 可以用 BGE-M3 這類開源模型自架,向量庫用 pgvector 或 Qdrant 架在內網,生成模型也能選本地部署的開源模型,代價是要自己負責硬體與維運。
一定要用 LangChain 或 LlamaIndex 嗎? 不一定。框架能加快開發,我們的金融科技案例也用了 LangChain。重點是不論用不用框架,檢索、權限、評估這些核心邏輯都要自己看得懂、測得到,出問題時才追得到原因。
結語:先把檢索做對
在我們的經驗裡,企業 RAG 的成敗主要取決於模型之外的工程:文件解析、切塊、混合搜尋、重排序、權限、評估。這些沒做好,換再強的模型也救不了撈錯資料的檢索。
如果你正在評估導入企業知識庫,或手上的 RAG POC 卡在準確率、權限或效能,歡迎參考我們的 企業 RAG 知識庫案例 ,或直接透過 聯絡頁 、LINE @141clxra 跟我們聊聊需求。
參考資料
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks(Lewis et al., NeurIPS 2020)
- Introducing Contextual Retrieval(Anthropic)
- A Systematic Analysis of Chunking Strategies for Reliable Question Answering(Bennani & Moslonka, 2026)
- Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods(Cormack, Clarke & Büttcher, SIGIR 2009)
- Hybrid search overview(Microsoft Learn, Azure AI Search)
- Document-level access control(Microsoft Learn, Azure AI Search)
- Add language analyzers to string fields(Microsoft Learn)
- BGE-M3(BAAI, Hugging Face)
- pgvector(GitHub)
- LLM08:2025 Vector and Embedding Weaknesses(OWASP GenAI Security Project)
- Ragas metrics(Ragas 文件)
- From Local to Global: A GraphRAG Approach to Query-Focused Summarization(Edge et al., Microsoft Research)
沒有留言:
張貼留言