
在開發 RAG檢索增強生成系統時檢索和重排往往被當成兩個獨立環節來處理先拉向量庫再做重排最后拼 Prompt 丟給大模型。但真正把系統落到生產環境你會發現一個很棘手的問題每一步都在消耗計算資源而計算資源和回答質量之間并不是簡單的線性關系。有時候多召回幾段文本重排模型大了幾個檔次效果提升卻很有限反而把響應延遲和 GPU 成本拉高了一大截。近期看到 SciRet 這樣一個以“計算感知Compute-Aware”為核心視角、針對科學文獻 RAG 場景的檢索與重排實證研究覺得這個方向對做知識庫問答、論文解讀、技術文檔問答的開發者都很有參考價值。本文會圍繞 SciRet 的研究思路展開拆解它關注的核心問題并結合常見 RAG 框架給出可落地的實驗設計與工程配置思路。如果你正在糾結“檢索到底召回多少條”“重排模型選多大”“RAG 效果怎么評估”這篇文章可以幫你理清頭緒。1. 背景為什么 RAG 的檢索與重排需要被重新審視1.1 從 RAG 的基本鏈路說起RAG 的經典鏈路可以概括為四個步驟文檔加載與解析。文本切塊Chunking與向量化。向量檢索召回候選文本。對候選文本做重排Rerank把最相關的內容送入大模型生成回答。很多入門教程會把重點放在第 2 步和第 3 步比如如何選 Chunk 大小、用哪種 Embedding 模型、向量庫選 Milvus 還是 Qdrant。但實際上大部分線上 RAG 系統的效果瓶頸并不在生成端而在“召回質量”和“排序質量”。召回質量決定了大模型能不能“看到”正確答案所在的段落。如果檢索回來的一大堆文本都不相關那么無論 Prompt 寫得再好大模型也只能基于噪聲生成答案。重排的作用則是在召回的候選集中做二次篩選把相關性最高的段落排到前面同時壓縮真正送入大模型的上下文長度。1.2 科學文獻場景的特殊性SciRet 把研究對象聚焦在“Scientific RAG”也就是面向論文、技術報告、實驗文檔的問答場景。這類場景和通用知識庫問答相比有幾個明顯的差異術語密度高論文里充滿了縮寫、專有名詞、公式、引用編號普通切塊方式很容易把一個完整的術語或公式攔腰截斷。語義粒度細科學文獻的答案往往集中在某一小段而不是整篇文檔需要檢索器具備更強的段落級語義理解能力。結構復雜論文有摘要、引言、方法、實驗、結論等結構不同部分的信息價值差異很大單純的向量相似度難以體現這種結構信息。評估成本高科學問題的答案通常需要專家標注自動評估指標如命中率、準確率和人工判定的相關性之間可能存在較大偏差。正是因為這些特殊性SciRet 這類研究才強調“計算感知”也就是在評估檢索和重排效果時把計算開銷作為一個關鍵維度而不是只關心準確率。1.3 什么是“Compute-Aware”研究視角傳統的信息檢索研究通常以“效果指標”為核心比如 RecallK、MRRMean Reciprocal Rank、NDCGNormalized Discounted Cumulative Gain。而計算感知的研究視角會額外引入一組問題為了提升 1 個百分點的 Recall需要多消耗多少倍的檢索時間更大的重排模型帶來的增益是否值得它在 GPU 上占用的顯存和延遲在固定計算預算下應該優先擴大召回數量還是升級重排模型換句話說Compute-Aware 研究關注的不是“哪種方法最好”而是“在給定的算力約束下哪種配置組合最劃算”。這對實際工程落地特別重要因為線上服務的延遲和成本都有硬性指標不可能無限堆算力。2. SciRet 研究的核心問題拆解SciRet 雖然是一篇實證研究但它的選題思路可以拆解成若干個可以遷移到日常開發中的問題。下面逐個展開分析。2.1 檢索器與重排器的組合如何影響最終效果在 RAG 系統中檢索器和重排器并不是獨立發揮作用的。檢索器決定了候選集的上限重排器決定了最終送入 Prompt 的內容質量。SciRet 這類研究會系統比較稀疏檢索如 BM25與密集檢索如向量相似度在不同領域數據上的表現差異。混合檢索稀疏 密集相對單一檢索方式帶來的提升幅度。不同規模的重排模型如小型的 cross-encoder 與大型跨編碼器對最終答案質量的影響。從工程角度看比較經典的組合方式有下面幾種檢索方式重排方式適用場景計算成本純向量檢索不重排原型驗證、對延遲極度敏感的場景低純向量檢索小型 Cross-Encoder 重排通用知識庫問答中混合檢索BM25 向量小型 Cross-Encoder 重排專業術語較多的場景中高混合檢索大型重排模型對回答質量要求極高的場景高2.2 Chunk 切分策略對檢索上限的影響SciRet 關注的另一個核心問題是 Chunk 切分。科學文獻中一個“理想”的 Chunk 應該滿足兩個條件語義完整能夠獨立表達一個事實或論點。粒度適中既能被檢索器有效匹配又不會因為過長而稀釋相關性。在實踐中Chunk 大小通常設置在 256 到 1024 個 token 之間但單純調整大小并不夠。更關鍵的是切分方式固定窗口切分實現簡單但容易切斷語義。遞歸字符切分按段落、句子、標點逐級切分對普通文本效果好。語義切分基于 embedding 相似度判斷句子邊界適合科學文獻。結構感知切分按 Markdown 標題、LaTeX 章節結構切分適合論文 PDF 轉化后的文本。SciRet 研究的價值在于它會量化不同切分策略對后續檢索和重排的影響而不是孤立地看切分結果。2.3 Top-K 數量與上下文窗口的權衡檢索后送入大模型的文本數量Top-K是 RAG 系統中的關鍵超參數。K 值越大大模型能看到的信息越多但也會引入更多噪聲同時增加生成階段的輸入 token 數進而提高成本和延遲。SciRet 這類實證研究會關注在固定重排器下Top-K 從 3 增加到 10效果提升是否顯著。在固定上下文窗口如 4K、8K、32K下檢索段數增加后有效信息占比是否下降。重排器能否在 Top-K 較大的情況下通過精準排序降低噪聲干擾。工程上一個比較實用的策略是檢索階段多召回比如 K20重排階段少保留比如 K5。這樣既保證了召回率又控制了上下文噪聲。2.4 重排器參數規模與效果的關系重排通常使用 Cross-Encoder 模型它能同時編碼 Query 和文檔計算相關性分數因此效果優于向量檢索的雙塔結構。但 Cross-Encoder 的計算開銷隨著參數規模增長非常明顯。SciRet 關注的核心矛盾在于重排器的參數規模增大帶來的效果提升是否值得額外的計算成本。小型模型如幾億參數的版本在 CPU 上也能跑大型模型則需要 GPU 加速部署成本和延遲都會顯著上升。一個直觀的判斷方法是在小規模測試集上對比不同重排器的排序質量再結合線上延遲要求選擇模型。如果小型重排器已經能把相關文檔排在 Top 5那么換用大型模型的意義就不大。3. 環境準備與實驗設計要復現 SciRet 這類研究的思路并不需要完整復刻它的實驗環境。我們可以在自己的 RAG 項目中設計一組小規模的對照實驗來衡量檢索、重排和計算成本之間的關系。3.1 推薦的技術棧下面是一個比較通用的 RAG 實驗技術棧重點在于方便快速迭代組件推薦方案說明開發語言Python 3.10生態最豐富RAG 框架LlamaIndex 或 LangChain兩者都支持檢索、重排的插拔式設計向量數據庫Chroma 或 Qdrant本地開發用 Chroma 最方便數據量大的場景用 QdrantEmbedding 模型BAAI/bge-small-zh-v1.5 或 OpenAI embedding中文場景推薦 bge 系列重排模型BAAI/bge-reranker-base 或 Cohere Rerank開源場景優先 bge-reranker評估框架RAGAS 或自定義腳本用于評估 Faithfulness、Answer Relevance 等指標版本需要根據你的項目實際情況調整本文示例以常見環境為例重點演示配置思路。3.2 實驗設計模板在復現 SciRet 思路時建議按照下面這個模板設計實驗固定數據集準備一批科學文獻段落以及對應的 Query 集合。確定變量每次只改變一個變量其他保持不變。記錄指標同時記錄效果指標和計算指標。對比基線設置一個最簡單的基線比如純向量檢索 不重排所有改進都與基線對比。實驗矩陣可以這樣設計實驗組檢索方式重排方式Top-KChunk 大小Baseline向量檢索無5512實驗 A向量檢索小型重排5512實驗 B混合檢索小型重排5512實驗 C混合檢索小型重排10512實驗 D混合檢索小型重排10256通過這張表可以系統分析每個變量對結果的影響。4. 用代碼實現一個計算感知的實驗框架下面通過一個完整的 Python 示例演示如何構建一個可以對比不同檢索和重排配置的最小實驗框架。4.1 創建項目結構sci_ret_demo/ ├── data/ # 存放待檢索的文檔 ├── experiments/ # 實驗結果輸出 ├── src/ │ ├── __init__.py │ ├── ingest.py # 文檔加載、切塊、寫入向量庫 │ ├── retrievers.py # 不同檢索方式的封裝 │ ├── rerankers.py # 重排器封裝 │ └── evaluate.py # 評估腳本 └── requirements.txt4.2 安裝依賴pip install llama-index-core llama-index-readers-file llama-index-vector-stores-chroma llama-index-postprocessor-cohere-rerank chromadb sentence-transformers不同版本對 API 的封裝略有差異如果遇到導入錯誤建議根據實際安裝版本查閱對應文檔。4.3 文檔索引模塊先實現文檔加載、切塊和向量化存儲的功能。# 文件路徑sci_ret_demo/src/ingest.py from llama_index.core import SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter from llama_index.core.schema import TextNode from llama_index.core.vector_stores import VectorStoreIndex from chroma import PersistentClient def load_documents(data_dir: str): 加載目錄下的所有文檔 reader SimpleDirectoryReader(data_dir) documents reader.load_data() return documents def build_nodes(documents, chunk_size: int 512, chunk_overlap: int 50): 將文檔切分為節點chunk_size 是實驗中的關鍵變量 splitter SentenceSplitter( chunk_sizechunk_size, chunk_overlapchunk_overlap, ) nodes splitter.get_nodes_from_documents(documents) return nodes def create_index(nodes, collection_name: str sci_ret_demo): 創建向量索引這里使用 Chroma 作為持久化存儲 client PersistentClient(path./chroma_data) service_context None # 實際使用時需要配置 embedding model # 這里需要根據 LlamaIndex 版本傳入 service_context 或 settings # 建議在外部統一初始化 embedding 模型后傳入 vector_store client.get_or_create_collection(collection_name) # 在更高版本中需要將 vector_store 與 Index 關聯 index VectorStoreIndex.from_nodes(nodes) return index注意上面的代碼是核心片段實際運行時需要根據你安裝的 LlamaIndex 版本補全 Embedding 模型的初始化邏輯。4.4 檢索與重排模塊然后封裝檢索和重排的對比邏輯。# 文件路徑sci_ret_demo/src/retrievers.py from llama_index.core import VectorStoreIndex from llama_index.core.retrievers import VectorIndexRetriever from llama_index.core.schema import QueryBundle def retrieve_top_k(index: VectorStoreIndex, query_text: str, top_k: int 5): 向量檢索 Top-K retriever VectorIndexRetriever( indexindex, similarity_top_ktop_k, ) nodes retriever.retrieve(QueryBundle(query_text)) return nodes# 文件路徑sci_ret_demo/src/rerankers.py from llama_index.core.postprocessor import SentenceTransformerRerank def build_reranker(model_name: str BAAI/bge-reranker-base, top_n: int 3): 構建重排器這里以 bge-reranker 為例 reranker SentenceTransformerRerank( modelmodel_name, top_ntop_n, ) return reranker4.5 評估腳本評估部分需要實現兩個維度的指標效果指標和計算指標。# 文件路徑sci_ret_demo/src/evaluate.py import time from dataclasses import dataclass from typing import List, Optional dataclass class ExperimentResult: config_name: str recall_at_k: float mrr: float latency_ms: float cost_notes: str def calculate_hit_rate(retrieved: List[str], relevant_ids: set) - float: 計算命中率檢索結果中是否包含相關文檔 if not retrieved: return 0.0 hits sum(1 for doc_id in retrieved if doc_id in relevant_ids) return hits / len(retrieved) def calculate_mrr(retrieved: List[str], relevant_ids: set) - float: 計算 MRR第一個相關結果排名的倒數 for idx, doc_id in enumerate(retrieved, start1): if doc_id in relevant_ids: return 1.0 / idx return 0.0 def run_experiment( config_name: str, retrieve_func, rerank_func: Optional, query: str, relevant_ids: set, top_k: int 10, final_n: int 3, ): 運行單個實驗記錄效果和耗時 start time.time() # 召回階段 nodes retrieve_func(query, top_k) retrieved_docs [n.node.node_id for n in nodes] if nodes else [] # 重排階段 if rerank_func is not None: reranked rerank_func.postprocess_nodes(nodes, query_strquery) final_docs [n.node.node_id for n in reranked[:final_n]] else: final_docs retrieved_docs[:final_n] latency_ms (time.time() - start) * 1000 result ExperimentResult( config_nameconfig_name, recall_at_kcalculate_hit_rate(final_docs, relevant_ids), mrrcalculate_mrr(final_docs, relevant_ids), latency_msround(latency_ms, 2), cost_notesf召回{top_k}條保留{final_n}條, ) return result4.6 運行實驗現在可以串聯所有模塊跑一組簡單對比實驗。# 文件路徑run_experiments.py from src.ingest import load_documents, build_nodes, create_index from src.retrievers import retrieve_top_k from src.rerankers import build_reranker from src.evaluate import run_experiment # 1. 加載與索引 docs load_documents(./data) nodes build_nodes(docs, chunk_size512) index create_index(nodes) # 2. 定義實驗查詢和期望命中的文檔 ID queries [ { query: 什么是檢索增強生成, relevant_ids: {doc_001, doc_002}, } ] # 3. 構建不同配置 reranker_small build_reranker(BAAI/bge-reranker-base, top_n3) # 4. 執行對比實驗 results [] for item in queries: # 基線不重排 base run_experiment( config_namebaseline_vector_top5, retrieve_funclambda q, k: retrieve_top_k(index, q, top_kk), rerank_funcNone, queryitem[query], relevant_idsitem[relevant_ids], top_k5, final_n3, ) results.append(base) # 實驗組向量檢索 重排 exp run_experiment( config_namevector_rerank_top10, retrieve_funclambda q, k: retrieve_top_k(index, q, top_kk), rerank_funcreranker_small, queryitem[query], relevant_idsitem[relevant_ids], top_k10, final_n3, ) results.append(exp) # 5. 輸出結果 for res in results: print(res)預期輸出會展示每個配置下的命中率、MRR 和延遲。通過對比基線和實驗組的差異就能判斷重排器的加入是否真的帶來了收益。5. 常見問題與排查思路在搭建類似實驗框架的過程中下面幾個問題是出現頻率最高的。問題現象常見原因解決思路檢索結果總是缺少正確答案段落Embedding 模型與語料領域不匹配換成領域適配的 Embedding如 bge 系列嘗試混合檢索重排前后效果幾乎沒有變化重排模型與檢索模型來自不同領域或 Top-K 太小擴大召回數量更換重排模型檢查相關文檔是否在候選集內響應延遲過高Top-K 過大、重排模型過重、文檔切分過長降低 Top-K使用小規模重排模型限制上下文長度生成的回答經常“答非所問”上下文噪聲太多大模型被無關文本干擾提高重排后保留的段落質量增加 Prompt 中的引用要求不同實驗之間結果波動明顯數據集太小、評估指標不穩定擴大測試集多次運行取平均使用人工標注的子集做驗證向量庫召回結果無法穩定復現Chunk 切分參數不一致或隨機種子未固定固定切分參數固定 Embedding 模型權重排查是否用到重排器的下降問題有一個比較容易忽視的問題重排器雖然能在相關性上做二次判斷但它無法解決“召回階段就漏掉正確答案”的問題。如果向量檢索階段 Top-K 太小把正確答案段落排在了候選集之外重排器再強也無能為力。所以排查效果不佳時建議先看“召回命中率”再看“重排準確率”。6. 最佳實踐與工程建議基于 SciRet 的研究視角可以從下面幾個維度優化實際 RAG 系統。6.1 把“計算成本”當成一等公民指標在 RAG 項目里建議在評估表格中同時記錄召回階段耗時。重排階段耗時。LLM 生成階段消耗的 token 數。單次問答的總成本估算按 token 單價折算。不要把目光只盯在準確率上因為很多情況下準確率提升 2%成本卻上升了 50%這在生產環境是不可接受的。6.2 按場景選擇檢索和重排策略通用知識庫向量檢索 bge-reranker-baseTop-K 設為 10重排后保留 3 到 5 條性價比最高。專業文獻問答建議使用混合檢索BM25 向量Top-K 設為 20重排后保留 5 條。科學文獻中術語的精確匹配往往比語義相似度更可靠。延遲敏感場景可以考慮不做重排但把向量檢索的相似度閾值調高用規則過濾掉明顯不相關的段落。大模型上下文很長如 128K不要盲目塞入大量檢索文檔。檢索質量下降時增加文檔數量只會增加噪聲不會提升答案質量。6.3 Chunk 策略要綁定評估一起調不要把 Chunk 大小當作一個固定參數。建議在評估中加入一組“Chunk 大小對比實驗”比如 256、512、1024觀察對 Recall 和最終答案質量的影響。科學文獻場景可以考慮“按段落切分 段落級檢索 關鍵句提取”的組合避免固定 token 窗口切斷語義。6.4 安全與權限邊界當 RAG 系統接入企業內部文檔時要特別注意檢索階段的權限隔離。向量庫中不允許存放未脫敏的敏感信息檢索結果也應按用戶權限過濾后再送入大模型。生產環境建議在向量庫中增加文檔級權限字段。檢索后、重排前進行權限過濾。記錄完整的檢索、重排、生成日志用于追溯和審計。6.5 日志與可觀測性RAG 系統的調優高度依賴日志。建議每條線上請求都記錄查詢文本檢索召回的所有文檔 ID 和分數重排后的排名和最終得分LLM 生成答案引用的文檔 ID有了這些日志之后做效果回歸和錯誤分析時就有據可依不用靠“猜”來調參。7. 下一步可以深入的方向SciRet 這類計算感知研究給實際工程帶來的最大啟發是提醒我們不要孤立地看檢索和重排方法而是要以“系統總開銷”為約束尋找最優組合。沿著這個思路后續可以深入的方向包括Agentic RAG把檢索、重排、查詢改寫交給 Agent 動態決定適合多輪復雜問題但延遲和成本更高需要做更精細的計算預算控制。RAG 評估體系引入 RAGAS、TruLens 或自建評估集把 Faithfulness、Answer Relevance、Context Relevance 納入評估框架。知識圖譜與向量數據庫結合先用知識圖譜做結構化過濾再用向量檢索做語義召回能夠顯著提升專業領域的檢索精度但工程復雜度更高。引用溯源與 Groundedness 校驗讓大模型在回答中標注引用來源用規則或模型校驗生成內容是否忠實于檢索到的文檔。這在企業場景幾乎屬于剛需。如果你正在做自己的 RAG 項目可以先從這篇論文的實驗思路中抽離出一部分搭建一個小型評估平臺固定數據集、固定評估指標、逐項對比檢索器、重排器和 Chunk 參數。不要一上來就追求復雜的框架先把“計算成本”和“回答質量”這兩本賬算清楚再逐步擴展。這樣無論是做技術選型還是向業務方解釋系統行為都會更有底氣。如果你想進一步落地也可以把本文的實驗框架擴展成自動化的回歸測試每次升級 Embedding 模型、重排模型或調整切塊策略時都跑一遍標準測試集對比效果和耗時。這是讓 RAG 系統從“能跑”走向“可控”的關鍵一步。