在前面的實作中,我們的檢索流程是 「向量檢索 → 直接輸入 LLM」。
經過前幾篇的文章介紹,我們了解到可以透過hybrid search和Rerank來優化Retrieval,但繁體中文的Hybrid search在筆者的經驗中效果有限且相對繁瑣,故建議以導入 Rerank為優先測略,利用 Cross-Encoder 對初步檢索回來的結果進一步排序,雖然通常較慢,但往往能帶來更高的精確度(Precision)。
我們以Day 8 - 實作補充: RAG中的 AG- Augmented Generation為基礎來加入 Rerank,因為場景還是中文,我們先選擇調用BGE系列的BGE-raranker-base
,模型相關介紹可以參考huggingface-bge-reranker-base。
程式內容為了讓大家了解每一個細部,我們都是先拆解開來一步一步寫,希望大家可以清楚了解背後邏輯,而不是直接用組合包。
from sentence_transformers import CrossEncoder
# 初始化 Rerank 模型
rerank_model = CrossEncoder('BAAI/bge-reranker-base')
# 使用者查詢
query = "沙崙土地開發對草鴞會有影響嗎?"
# 先進行向量檢索,取出前10筆候選
query_vec = embedding_model.encode(query)
results = collection.query(
query_embeddings=[query_vec],
n_results=20
)
# 提取候選文檔
documents = results['documents'][0]
# 建立 (query, doc) pair,輸入 Rerank 模型
pairs = [(query, doc) for doc in documents]
scores = rerank_model.predict(pairs)
# 對文檔重新排序,取前 3 筆
doc_scores = list(zip(documents, scores))
doc_scores.sort(key=lambda x: x[1], reverse=True)
top_docs = [doc for doc, score in doc_scores[:3]]
# 準備給 LLM 的檢索內容
retrieved_docs = "\n".join(top_docs)
# 構建 Prompt
prompt = f"""
基於以下檢索到的文檔內容,回答用戶問題:
文檔內容:
{retrieved_docs}
用戶問題:{query}
請根據文檔內容提供準確的答案,並明確說明參考來源段落。
如果文檔內沒有明確寫出內容,請回答「資料不足」而不是捏造答案。
"""
# 調用 OpenAI API
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
max_tokens=1024,
temperature=0.1
)
# 輸出最終答案
answer = response.choices[0].message.content
print(answer)
透過上面流程調整,我們可以比較看看:
星期五趕車潮,僅先快速做了Rerank的補充,明天我們再來把片段的程式組合在一起,並使用Streamlit做一個完整的Demo吧!!