iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
自我挑戰組

AI 不只會回答:30 天打造一套真正能上線的智慧助理系列 第 10

[Day 10] Reranking:讓真正相關的文件排在前面

  • 分享至 

  • xImage
  •  

[Day 10] Reranking:讓真正相關的文件排在前面

今天為什麼要做這件事

在 Day 9 中,我們完成了 Hybrid Search,結合:

  • Vector Search:理解語意相似度
  • Keyword Search:匹配精確關鍵字
  • RRF:整合不同搜尋方式的結果

但即使結合多種搜尋方法,仍然可能遇到一個問題:

搜尋結果中可能包含相關文件,但真正重要的文件沒有排在前面

這些文件可能都與問題有關聯,但第 3 筆才是最直接的答案依據

如果我們只取前 2 筆文件建立 Context,LLM 就可能無法取得最重要的內容

因此,今天要引入 Reranking (重新排序),讓系統在初步搜尋後,再次判斷文件與使用者問題的關聯程度

今天要解決什麼問題

今天主要處理以下問題:

  1. 初步搜尋結果不一定按照實際相關性排序
  2. Vector Search 與 Keyword Search 產生的結果可能包含雜訊
  3. 重要文件可能被排在較後面
  4. 直接將所有候選文件交給 LLM,會增加 Context 長度與成本
  5. 如何透過第二階段排序,將真正相關的文件放到前面

整體概念是:

先廣泛搜尋,再精準排序

這種方式也稱為 Retrieve → Rerank

什麼是 Reranking

Reranking 是指:

對初步檢索取得的候選文件,再使用另一個排序模型或規則重新評估,產生更符合查詢需求的排序結果

初步搜尋的目標是提高 Recall (找得到相關文件的能力)

Reranking 的目標則是改善 排序品質與 Precision (前段結果的相關程度)

為什麼初步搜尋後還需要重新排序

初步搜尋通常偏向快速篩選

Vector Search 主要透過向量相似度找出候選文件

但「語意相似」不一定代表「回答問題時最有用」

文件 B 可能比文件 A 更直接符合使用者的具體需求

初步搜尋可能忽略查詢與文件的完整關係

Embedding 通常會分別建立:

  • Query 的向量
  • Document 的向量

再比較兩者之間的相似程度

這種方法可以有效處理大量文件,但不一定會深入分析:

  • 問題中的關鍵條件
  • 文件是否完整回答問題
  • 問題與文件之間的細節關係
  • 特定詞語在上下文中的意義

因此,我們可以使用第二階段模型,直接將 Query + Document 一起輸入模型,進行更細緻的相關性評估

Reranking 常見模型架構

Bi-Encoder:適合初步檢索

Bi-Encoder 會分別將 Query 與 Document 轉換成向量

優點:

  • 可以預先建立文件向量
  • 搜尋速度較快
  • 適合大量文件的初步檢索

限制:

  • Query 與 Document 通常分開編碼
  • 對細節關聯的判斷能力可能有限

Cross-Encoder:適合重新排序

Cross-Encoder 會分別評估兩份文件與查詢的關聯程度

在這個例子中,文件 B 包含更直接的回答資訊,因此可能取得較高的相關性分數

Cross-Encoder 的優點

  • 可以同時理解 Query 與 Document
  • 適合分析更細緻的語意關係
  • 常用於候選文件的重新排序

Cross-Encoder 的限制

  • 每一組 Query 與 Document 都需要重新推論
  • 文件數量越多,推論成本越高
  • 不適合直接對整個大型文件庫逐筆計算

因此,常見做法是:

先使用快速檢索縮小範圍,再使用 Cross-Encoder 重新排序

為什麼初步搜尋要取較多文件?

假設初步搜尋只取得 3 筆:

如果真正相關的文件沒有進入這 3 筆,Reranking 就沒有機會將它找出來

因此,可以在檢索範圍與推論成本之間取得平衡

實作環境

本次使用 Sentence Transformers 提供的 Cross-Encoder

安裝套件:

pip install sentence-transformers torch

模型名稱與下載來源可能隨版本變化
實際使用前,請確認模型的語言支援、授權條款與硬體需求

Step 1:載入 Cross-Encoder

from sentence_transformers import CrossEncoder


class DocumentReranker:
    def __init__(
        self,
        model_name="cross-encoder/ms-marco-MiniLM-L-6-v2"
    ):
        self.model = CrossEncoder(model_name)

    def rerank(
        self,
        query,
        documents,
        top_k=5
    ):
        pairs = [
            [query, document]
            for document in documents
        ]

        scores = self.model.predict(pairs)

        ranked_results = sorted(
            zip(documents, scores),
            key=lambda item: float(item[1]),
            reverse=True
        )

        results = []

        for document, score in ranked_results[:top_k]:
            results.append({
                "document": document,
                "score": float(score)
            })

        return results

程式說明

建立 Query 與 Document 的配對:

pairs = [
    [query, document]
    for document in documents
]

接著取得每份文件的分數,並按照分數由高到低排序

注意事項

不同模型的分數定義可能不同:

  • 有些模型分數越高,代表越相關
  • 有些模型可能輸出 Logit
  • 有些模型可能需要額外的分數轉換

因此,不能直接將不同模型的分數視為相同意義,也不應直接與 BM25 或向量距離相加。

Step 2:建立測試文件

這個實驗可以觀察:

  • 哪些文件被排在前面
  • 相關性分數的差異
  • Reranking 是否將更符合問題的內容移到前面

Step 3:將 Reranking 串接至 Hybrid Search

前面 Day 9 的 Hybrid Search 會產生候選文件

接下來將候選文件傳給 Reranker

from src.retrieval.reranker import DocumentReranker


class RerankPipeline:
    def __init__(
        self,
        hybrid_searcher,
        reranker
    ):
        self.hybrid_searcher = hybrid_searcher
        self.reranker = reranker

    def search(
        self,
        query,
        retrieve_top_k=20,
        final_top_k=5
    ):
        candidates = self.hybrid_searcher.search(
            query=query,
            top_k=retrieve_top_k
        )

        documents = [
            result["document"]
            for result in candidates
        ]

        reranked_results = self.reranker.rerank(
            query=query,
            documents=documents,
            top_k=final_top_k
        )

        return reranked_results

實務上的改善方向

上面的程式只保留文件文字與 Reranking 分數

但在實際 RAG 系統中,應該保留原本的 Metadata

否則重新排序後,可能無法追蹤文件來源

Step 4:保留 Metadata 與引用資訊

Reranking 應該保留完整的候選資料

接著就能在建立 Context 時,繼續顯示引用來源

遇到什麼問題

問題一:Reranking 速度比 Vector Search 慢

Vector Search 可以預先建立文件向量,查詢時只需要進行向量比對

但 Cross-Encoder 必須針對每一組 Query 與 Document 進行推論

解決方式

不要直接對整個文件庫執行 Reranking

透過先縮小候選集合,可以降低推論時間與硬體負擔

問題二:模型不一定支援中文

本篇示範的模型主要針對英文資訊訓練

如果文件與查詢以繁體中文為主,可能遇到:

  • 中文語意理解效果有限
  • 中文專有名詞判斷不準確
  • 版本號與英文混合文字的排序不穩定

解決方式

選擇 Reranker 時,需要確認:

  1. 是否支援中文
  2. 是否支援繁體中文
  3. 是否有中文或多語資料訓練
  4. 模型授權是否允許商業使用
  5. 推論速度是否符合應用需求

不能只因為模型名稱包含 Cross-Encoder,就假設它適合所有語言與場域

分數高不一定代表答案正確

Reranking 模型的分數代表模型對相關性的判斷,不等於事實正確性

這份文件可能與查詢相關,但沒有明確說明是否支援 Ubuntu 24.04

解決方式

需要區分:

  • **相關性 (Relevance) **:文件是否與問題有關。
  • 答案充分性 (Answer Sufficiency):文件是否提供足夠資訊回答問題
  • 事實正確性 (Factual Correctness):內容是否正確
  • 引用正確性 (Citation Correctness):引用是否真的支持回答

Reranking 主要改善排序,不能單獨解決所有 RAG 問題

Reranking 可能將過短或過長文件判斷錯誤

如果 Chunk 太短,可能缺少必要上下文

如果 Chunk 太長,可能同時包含多個不同主題

對於複雜問題,Chunk B 可能更有用,因為它包含完整的回答背景

解決方式

Reranking 不是用來取代良好的 Chunking,而是建立在合理文件切分之上

如何評估 Reranking 效果

不能只觀察模型輸出的分數,應該使用實際測試案例進行評估

Precision@K

觀察前 K 筆文件中,有多少筆真正相關

MRR

MRR (Mean Reciprocal Rank) 主要觀察第一份相關文件出現的位置

第一份相關文件越早出現,MRR 通常越高

NDCG

NDCG (Normalized Discounted Cumulative Gain) 可以處理不同程度的相關性

這比單純判斷「相關/不相關」更有彈性

可以將文件 C 評為高度相關,文件 A 評為相關

建立簡單的 Reranking 測試

TEST_CASES = [
    {
        "query": "Ubuntu 24.04 安裝需要注意什麼?",
        "expected_keywords": [
            "Ubuntu",
            "24.04",
            "相依套件"
        ]
    },
    {
        "query": "安裝完成後需要做什麼?",
        "expected_keywords": [
            "重新啟動"
        ]
    }
]


def is_relevant(document, expected_keywords):
    return all(
        keyword in document
        for keyword in expected_keywords
    )


def evaluate_results(results, expected_keywords):
    relevant_count = 0

    for result in results:
        document = result["document"]

        if is_relevant(
            document,
            expected_keywords
        ):
            relevant_count += 1

    total = len(results)

    if total == 0:
        return 0.0

    return relevant_count / total

注意

這是一個簡化的測試方法

實際上,文件不一定需要包含所有預期關鍵字才算相關。例如:

「重新啟動」與「重新開機」語意相近,但字串不同

因此,正式評估時應該建立人工標註資料,或搭配語意評估與人工審查。

初步搜尋與 Reranking 的參數如何調整

觀察不同設定對以下指標的影響:

  • Precision
  • Recall
  • MRR
  • 回答正確性
  • 平均回應時間
  • Token 使用量

Reranking 與 LLM 直接評分有什麼不同

除了專用 Reranker,也可以讓 LLM 直接評估文件相關性

這種方法具有彈性,但也可能有以下問題:

  • 推論成本較高
  • 回應時間較長
  • 分數穩定性可能不足
  • 模型輸出格式需要控制
  • 不同模型的評分標準可能不同

因此,若系統需要大量且穩定的排序工作,通常會考慮使用專門的 Reranker。


今天學到什麼

今天從 Hybrid Search 進一步加入 Reranking,讓文件檢索流程從「找到候選文件」走向「重新判斷相關程度」。

初步搜尋不代表最終排序

Vector Search 與 Keyword Search 適合快速取得候選文件,但前段結果不一定是最適合回答問題的內容。

Reranking 是第二階段檢索

Reranking 會重新分析 Query 與 Document 的關係,讓較相關的文件排在前面。

Retrieve → Rerank 可以兼顧效率與品質

第一階段:快速取得較大的候選集合
第二階段:精細判斷候選文件的相關性

這比直接對整個文件庫逐筆使用 Cross-Encoder 更有效率。

Reranking 需要搭配評估

不能只看模型分數,而應該觀察:

  • 相關文件是否排到前面
  • Precision是否改善
  • MRR 是否提升
  • 回答是否更正確
  • 回應時間是否可接受

Reranking 不等於事實查核

Reranker 主要評估文件與問題的相關性,不能保證文件內容一定正確,也不能取代來源驗證與回答評估


目前系統進度

目前的檢索流程已經從:

單純向量搜尋

逐步發展成:

Vector Search
    +
Keyword Search
    ↓
Hybrid Search
    ↓
Reranking
    ↓
Context 建立
    ↓
LLM 回答

這樣的架構能讓 RAG 系統更有機會取得與問題直接相關的文件

明天要做什麼?

即使我們已經加入:

  • Hybrid Search。
  • Reranking。
  • 文件引用。
  • Precision@K。
  • MRR 等評估概念。

仍然可能遇到一個核心問題:

檢索結果看起來相關,但 LLM 產生的答案是否真的正確

因此,下一步將從「檢索品質」延伸到「整體 RAG 評估」。

明天可以探討:

  • RAG Evaluation 是什麼?
  • 如何評估 Context Relevance?
  • 如何評估 Answer Relevance?
  • Faithfulness 與 Groundedness 的差異。
  • 如何建立自動化評估資料集。
  • 如何避免只憑主觀感覺判斷系統效果。

Day 11:RAG Evaluation——如何知道 AI 助理回答得好不好

確認「這些文件是否真的支援 AI 產生的答案」


上一篇
不只靠向量搜尋:用 Hybrid Search 提升 RAG 檢索品質
下一篇
[Day 11] RAG Evaluation:如何知道 AI 助理回答得好不好
系列文
AI 不只會回答:30 天打造一套真正能上線的智慧助理12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言