很多同學在做 RAG(檢索增強生成)項目時,都會遇到一個頭疼的問題:向量檢索召回的內容經常“文不對題”,導致大模型回答出現幻覺。今天我們就來聊聊如何通過 Rerank(精排)技術,讓你的 RAG 系統脱胎換骨。
大家好,我是王中陽。
最近在 我們AI就業陪跑訓練營 裏,有不少同學問我:“我的 RAG 系統明明把文檔切好了,向量庫也建好了,為什麼用户問問題時,找出來的文檔還是不準?”
其實,這是傳統 RAG 架構中一個非常經典的問題。今天這篇文,我就帶大家深入理解“粗排”與“精排”,並手把手教你在 Golang 項目中引入 Rerank 機制。
1. 為什麼向量檢索還不夠?
在標準的 RAG 流程中,我們通常使用向量檢索(Vector Search)來尋找相關文檔。
它的工作原理是:
- 把用户問題(Query)變成向量。
- 把文檔塊(Chunk)變成向量。
- 計算兩個向量的餘弦相似度,取 Top K。
這種方法叫 Bi-Encoder 架構。它的最大優勢是快(億級數據毫秒級響應),但缺點也很明顯:它丟失了細粒度的語義交互。
舉個例子:
- Query: "Python 怎麼調用 C++ 的動態庫?"
- Doc A: "Python 調用 C++ 動態庫的詳細教程..." (強相關)
- Doc B: "C++ 調用 Python 腳本的方法..." (不相關,但關鍵詞高度重合)
在向量空間中,Doc B 因為包含大量相同的關鍵詞(Python, C++, 調用),其向量距離可能和 Query 非常近,導致被錯誤召回。
這時候,大模型拿到的上下文是 Doc B,它自然就回答不出正確答案,甚至開始“一本正經地胡説八道”。
2. 什麼是 Rerank(精排)?
為了解決這個問題,我們需要引入第二階段:Rerank(重排序)。
這就好比招聘:
- 向量檢索(粗排):HR 快速篩選簡歷。只要簡歷裏有“Golang”、“3年經驗”這些關鍵詞,就先撈出來。這一步要快,可能撈出 100 份簡歷。
- Rerank(精排):面試官進行深度面試。面試官會仔細閲讀簡歷的每一個項目經驗,甚至進行面對面交流。這一步比較慢,但非常精準,最終只選出最匹配的 3 個人。
在技術上,Rerank 通常使用 Cross-Encoder 架構。它將 Query 和 Document 同時輸入到模型中,讓模型逐字逐句地對比兩者的關係,輸出一個相關性得分(Score)。
一圖勝千言
-
左邊的 Bi-encoder(雙塔編碼器) 正是向量檢索的核心架構:它會分別將輸入 A、B 編碼成獨立的向量,再通過餘弦相似度計算匹配度。
- 這種方式可以預計算文檔向量並存儲在向量數據庫中,適合大規模、高效率的召回(即向量檢索)。
-
右邊的 Cross-encoder(交叉編碼器) 是 Rerank(重排)的常用模型:它將輸入 A、B 拼接後一起編碼,直接輸出相關性分數,能捕捉文本間的細粒度交互。
- 精度更高,但速度慢,適合對向量檢索得到的候選集進行精準重排序(即 Rerank)。
3. RAG 進階架構:Retrieve + Rerank
加入 Rerank 後,我們的 RAG 流程變成了這樣:
- Retrieval (粗排) :使用向量檢索,快速召回 Top 50 個候選文檔。
- Rerank (精排) :使用 Cross-Encoder 模型,對這 50 個文檔進行精細打分。
- Filter: 截取得分最高的 Top 5。
- Generation: 將這 Top 5 餵給大模型生成答案。
雖然 Rerank 增加了一點點延遲(通常幾十毫秒),但它能帶來質的飛躍。實驗數據表明,加入 Rerank 後,RAG 系統的檢索準確率(MRR/NDCG)通常能提升 10%~20% 。
4. 實戰:在 Golang 中接入 Rerank
目前市面上有很多優秀的 Rerank 模型,比如 BGE-Reranker(開源最強)、Cohere Rerank(商業閉源效果好)。
這裏我們以 Cohere Rerank 為例,看看在 Golang 中怎麼寫代碼。
首先,你需要申請一個 Cohere 的 API Key(註冊送額度)。
package main
import (
"context"
"fmt"
"log"
cohere "github.com/cohere-ai/cohere-go/v2"
cohereclient "github.com/cohere-ai/cohere-go/v2/client"
)
func main() {
// 1. 初始化客户端
client := cohereclient.NewClient(cohereclient.WithToken("YOUR_API_KEY"))
// 2. 模擬粗排召回的文檔 (這裏包含了相關和不相關的)
docs := []*string{
ptr("Golang 是一種靜態強類型語言,性能優異。"),
ptr("Python 是一種解釋型語言,適合數據分析。"),
ptr("Java 的生態系統非常龐大。"),
ptr("Go 語言的併發模型基於 Goroutine 和 Channel。"), // 強相關
}
// 3. 用户問題
query := "Go 語言的併發優勢是什麼?"
// 4. 調用 Rerank 接口
resp, err := client.Rerank(context.TODO(), &cohere.RerankRequest{
Model: ptr("rerank-multilingual-v2.0"), // 支持多語言的模型
Query: query,
Documents: docs,
TopN: ptr(3), // 只取前 3 名
})
if err != nil {
log.Fatal(err)
}
// 5. 打印結果
fmt.Printf("用户問題: %s\n", query)
fmt.Println("--------------------------------------------------")
for _, result := range resp.Results {
docContent := *docs[result.Index]
fmt.Printf("排名: %d | 得分: %.4f | 內容: %s\n", result.Index, result.RelevanceScore, docContent)
}
}
func ptr[T any](v T) *T { return &v }
運行結果預期:
即便粗排時混入了很多不相關的文檔,Rerank 也能把最相關的 "Go 語言的併發模型基於 Goroutine 和 Channel。" 準確地排到第一名,並且給出一個很高的相關性得分。
5. 什麼時候需要“離線”精排?
標題裏提到了“離線精排”,這通常指的是在對檢索質量要求極高,或者模型私有化部署的場景。
如果你的數據非常敏感(不能發給 Cohere/OpenAI),或者你想追求極致的性價比,你可以選擇離線部署 BGE-Reranker 模型。
你可以使用 Python 的 sentence-transformers 庫加載 BGE 模型,將其封裝成一個 HTTP 服務,供 Golang 業務層調用。這樣既保證了數據安全,又節省了 API 費用。
總結
RAG 系統不是簡單的“向量庫 + 大模型”。要想效果好,Rerank 是必不可少的一環。
它就像一個嚴謹的“安檢員”,把那些濫竽充數的文檔擋在門外,只把最精華的內容送給大模型。
如果你現在的 RAG 系統效果卡在瓶頸期,不妨試試加上 Rerank,相信會給你帶來驚喜!
最後
如果你對 RAG 技術感興趣,或者在做 AI 應用落地時遇到了坑,歡迎瞭解 我們的AI就業陪跑訓練營。在這裏,我們不僅有全套的 Golang AI 實戰課程(從零手寫 RAG、Agent、微調),還有一羣志同道合的夥伴一起交流。