📌 本文重點
- 單一檢索策略讓 RAG 在真實場景很容易翻車
- Hybrid Search 能互補向量與關鍵字的盲點
- 讓 Agent 負責檢索策略與多輪重試能顯著提升穩定度
- 不換模型也能透過 eval、Hybrid 與權限控管大幅升級 RAG
在實際專案裡,多數 RAG 翻車不是因為模型不夠聰明,而是檢索策略太單一:只用向量會被專有名詞和代碼玩死,只用關鍵字又抓不到語義相近的長文件內容。Agentic RAG + Hybrid Search 的組合,重點就是讓「檢索」變成可調度、可重試、可觀測的一級公民,而不是一個寫死的 search(query) 函式。
重點說明
1. 為什麼單一檢索在真實專案會翻車?
常見四種翻車場景:
- 長文件 / 手冊
- 只用向量:整份手冊被切成很多 chunk,語義太接近,top-k 都很像,但真正要的那一段不一定排前面。
-
只用 BM25:查詢句子太口語,關鍵字重疊度不高,直接 miss。
-
專有名詞 / 法規條文 / 內部代號
- 向量模型常常把
DS-104、DS-140當成類似,專案實際上兩者完全不同。 -
法規編號、API 名稱、Ticket ID 等,關鍵字檢索反而更穩。
-
程式碼、表格、錯誤訊息
- 向量對縮排、符號、stack trace 的敏感度很差。
-
Log ID 或錯誤碼這類「硬字串」,BM25/關鍵字幾乎是必要條件。
-
跨語言 / 口語查詢
- 使用者用自然語言描述問題,文件是正式用語或英文,公司內還混雜縮寫。
- 需要先用 LLM 做 query 改寫,再讓向量與 BM25 各自發揮。
Hybrid Search(向量 + BM25) 的實際好處:
- 可以 補各自的盲點:專有名詞用 BM25 鎖定,模糊描述用向量補齊。
- 可以針對不同類型文件設定 權重策略(例如法規 > 內部 wiki > Slack 摘要)。
- 可以後面用 rerank 模型 做第二次排序,穩定提升回答可靠度。
💡 關鍵: 單一檢索在長文件與專有名詞場景很容易漏抓關鍵內容,Hybrid Search 能同時顧到語義相似與精確字串匹配,明顯降低 RAG 翻車率。
2. 讓 Agent 負責檢索策略,而不是把檢索寫死
典型 Agentic RAG 設計:
- 一個 Orchestrator Agent(對話主控)
- 多個 retriever 工具:
keyword_retriever、vector_retriever、hybrid_retriever、legal_retriever等
Agent 的工作不是「自己產生答案」,而是先判斷:
- 要用哪種檢索策略?
- 查錯誤碼或 ticket:優先 關鍵字 → 再向量精抽
- 問概念解釋:優先 向量 → 再用 BM25 找原始定義
-
法規/權威階層:改用 分層 retriever(例如每一層級至少取 1–2 筆)
-
要不要改寫 Query?
-
第一輪命中文件相關度低時,讓 Agent 自動:
- 摘出關鍵詞
- 加上同義詞 / 全名(例如:
DS→Data Steward) - 限縮 domain(例如:限定
product=core-banking)
-
多輪重試與合併結果
- 第一輪檢索後如果信心不足(例如 top-3 相似度都
< 0.7), - Agent 改寫 query 或更換 retriever,再抓一次,最後合併去重後送入 LLM。
這樣做的實際好處:
- 檢索策略可迭代:只要調整工具 / prompt,不必重寫服務架構。
- 容易在線上 A/B:只換掉 Orchestrator 的 prompt 或 routing 邏輯即可。
- 可以針對不同客戶 / 部門掛不同的工具組合。
3. 架構骨架:Orchestrator + 多 retriever + Hybrid Search
一個可落地的組合:
- LLM:OpenAI(
gpt-4.1)、Anthropic(claude-3.7)皆可 - 檢索:
- Elasticsearch:BM25 + dense vector + hybrid score
- 或 Weaviate / Qdrant:向量 + keyword filter
簡化架構:
User → Orchestrator Agent → (tool calls) →
- keyword_retriever (Elasticsearch BM25)
- vector_retriever (Weaviate / ES dense vector)
- hybrid_retriever (ES rank_feature / script_score)
→ merge + dedup + rerank → LLM answer
實作範例
1. Orchestrator Agent Prompt(決定使用哪個 retriever)
假設用 OpenAI Assistants API 或自行封裝 tools:
系統指示(Orchestrator):
你是一個檢索協調代理,負責從多種檢索器取得最相關的企業知識。
- 若使用者詢問:
- 錯誤碼、ticket ID、法規條號、API 名稱 → 優先使用 **keyword_retriever**。
- 抽象概念、最佳實踐、流程說明 → 優先使用 **vector_retriever**。
- 法律 / 合規問題,且需多層級來源 → 使用 **legal_hybrid_retriever**。
流程:
1. 先決定要呼叫哪些工具(可以多個)。
2. 若第一輪檢索結果的「來源數量 < 3」或「相關度評估偏低」,
- 自行改寫查詢(更精簡、加入關鍵字),再重試一次。
3. 最終將所有檢索結果去重、排序,回傳給後續回答模型。
禁止自行編造公司內部資料,所有答案必須可追溯到文件片段。
2. Elasticsearch Hybrid Search 設定範例
索引 mapping:
PUT knowledge_base
{
"mappings": {
"properties": {
"content": { "type": "text" },
"content_vec": { "type": "dense_vector", "dims": 1536, "index": true },
"source_type": { "type": "keyword" },
"tenant_id": { "type": "keyword" }
}
}
}
簡化版 hybrid 查詢(BM25 + 向量):
POST knowledge_base/_search
{
"size": 20,
"query": {
"script_score": {
"query": {
"bool": {
"must": [
{"match": {"content": "GDPR data retention"}},
{"term": {"tenant_id": "acme_corp"}}
]
}
},
"script": {
"source": "0.6 * _score + 0.4 * cosineSimilarity(params.q_vec, 'content_vec')",
"params": {"q_vec": [/* query embedding */]}
}
}
}
}
關鍵點:
- BM25 與向量權重(例子中
0.6 / 0.4)要透過線上 A/B 或離線 eval 調整。 tenant_idfilter 做多租戶權限隔離,非常重要。
💡 關鍵: 在同一個查詢裡用 script score 同時結合 BM25 分數與 cosine similarity,能控制兩者權重,調整出最適合自己資料分佈的 Hybrid 策略。
3. Chunking 與 max context 的工程細節
基本原則:
- 以 語義切分(semantic splitting)+ 適度 overlap 為主,而不是死切
512 tokens。 - 避免 chunk 過長導致:
- 向量語義太混濁,top-k 噪音變高。
- LLM context 塞滿 retrieval 噪音,回答變模糊。
實作骨架(pseudo-code):
from semantic_splitter import split_semantic
def chunk_doc(text: str):
sections = split_semantic(text, max_chars=1200)
chunks = []
overlap = 150 # 字元級 overlap
for sec in sections:
if len(sec) <= 1200:
chunks.append(sec)
else:
# 針對長 section 再做 sliding window
for i in range(0, len(sec), 1200 - overlap):
chunks.append(sec[i:i+1200])
return chunks
與 max context tokens 的關係:
- 假設 LLM context
32k,系統 prompt + 對話占4k,其實留給 RAG 的只有約28k。 - 若每個 chunk 約
400 tokens,你實際能塞 約 50–60 個 chunk 就爆,但通常8–16個 chunk 就夠,更多只會拉高成本與噪音。
rerank 與去重:
- 先取寬一點的
top_k(例如30–50),再用輕量 rerank(如 bge-reranker)縮到8–12個。 - 去重邏輯可以用:
same doc_id + 高度相似直接只留一個,減少重複內容浪費 context。
💡 關鍵: 雖然 context 可能有 32k tokens,但實務上只保留約 8–16 個高質量 chunk,通常就能兼顧成本與效果,塞太多反而害答題品質下滑。
建議與注意事項
1. 不要只做 embedding,不做 eval
常見錯誤流程:
- 把全部文件 embed → 塞進向量庫 → 上線。
- 發現回答怪怪的 → 開始懷疑模型。
比較健康的流程:
- 先準備一組 標記好的 QA/Eval 集(
10–50題也好)。 - 對同一組問題,分別跑:
- 純 BM25
- 純向量
- Hybrid + 不同權重
- 用簡單指標(
hit@k、人工評分)挑一個 baseline,再上線 A/B。
2. 向量庫維護:重建 / 追加 / 版本化
- Embedding 模型版本變更 時:
- 盡量用新 index 重建(
kb_v2),舊版保留一段時間做對照。 - 不要在同一個 index 裡混不同 embedding 模型的向量。
- 大量文件更新策略:
- 批次追加新文檔時,要記錄 批次 ID / 資料版本,方便 rollback。
- 下線文件要標記
is_active=false或直接 soft delete,避免回答引用過期政策。
3. 多租戶與權限過濾
- 在 Elasticsearch / Weaviate 中務必存:
tenant_id、visibility、role等欄位。 - 檢索 query 層一定要加:
"filter": [
{"term": {"tenant_id": "${current_tenant}"}},
{"terms": {"visibility": ["public", "internal"]}}
]
- 不要指望 LLM 自己遵守權限,權限控制一定要在檢索階段完成。
4. 線上評測與 A/B 驗證
簡易做法:
- 選一組真實高頻 query(客服 ticket、搜尋 log)。
- 設計兩條路線:
- A:純向量 RAG
- B:Agentic RAG + Hybrid Search
- 隨機分流流量,收集:
- 使用者是否重問 / 追問率
- 是否需要人工接手
- CSR / domain expert 的
1–5分主觀評分
通常在企業知識庫場景,只要加上 Hybrid Search + Agent 重試,就能看到 10–30% 的 query 成功率提升,而且失誤類型會明顯變少(比較少「答錯法規條」、「引用過期政策」)。
總結:如果你現在的 RAG 還是「單一向量庫 + top-k 塞給 LLM」,要提升穩定性,不一定要換更大的模型,先把 Hybrid Search 與 Agentic 檢索策略補上,通常是成本最低、效果最直接的升級路線。
🚀 你現在可以做的事
- 從現有專案中抽出 10–50 則真實 query,分別用純 BM25、純向量與 Hybrid 跑一次,記錄 hit@k 與人工評分
- 在現有 RAG 服務前面加一個簡單 Orchestrator,把關鍵字與向量檢索拆成兩個
tool,用 prompt 控制選用策略- 在搜尋層加入
tenant_id與visibility欄位與 filter,先確保權限過濾正確,再進一步調整 Hybrid 權重與 rerank 策略


發佈留言