RAG策略详解:三层检索架构与工程实践
1. 这篇文章真正要解决的问题先问大家一个问题面试官问“RAG策略”你脑子里最先冒出来的是什么很多人的第一反应是RAG 不就是把文档切块做向量检索然后丢给大模型生成答案吗再熟练一点的能说出 embedding、向量数据库、TopK 这些词。但如果你真的在面试现场把这个答案说完面试官大概率会追问一句那你说的“检索策略”具体分几层每一层分别解决什么问题如果检索结果本身是错的你怎么发现这一追问大多数人就卡住了。原因很简单很多人对 RAG 的理解停留在“检索 生成”的两段式没有意识到 RAG 真正的技术难点集中在检索链路里而且这条链路远不止“算相似度、取 TopK”这么简单。这篇文章想讲清楚一个核心判断RAG 真正拉开差距的地方不是大模型而是检索策略。同一个文档库、同一个大模型检索策略设计得好不好最终答案的质量可以差出几个量级。而所谓的“三层检索”正是把这条链路拆开来看的关键框架第一层粗召回也叫向量检索层负责从海量文档里快速捞回候选片段。第二层重排序也叫精排层负责对粗召回结果做精细化打分把真正相关的信息排到最前面。第三层生成与校验层负责把精排后的上下文交给模型生成答案并验证答案有没有“忠实于”检索到的资料。读完这篇文章你能得到三样东西一套可以直接讲给面试官听的 RAG 检索策略框架。一套能跑通的 Python 代码示例覆盖切块、向量检索、重排序、生成全流程。一组在真实项目中踩坑后总结出的切块策略、参数调优和排查方法。无论你是准备面试还是在做企业知识库问答这篇文章都值得仔细看一遍。2. RAG 基础概念与核心原理2.1 什么是 RAGRAGRetrieval-Augmented Generation检索增强生成是一种把“外部知识检索”和“大语言模型生成”组合起来的架构。它的基本流程是用户提一个问题先从预先构建的私有知识库中检索出与问题最相关的文本片段再把这些片段作为上下文拼接给大语言模型让模型基于这些片段生成答案。为什么要这么做因为大语言模型有三个天然的短板知识有截止日期模型训练完之后新发生的事情它不知道。私有数据不可见企业内部文档、个人笔记、业务数据库模型在训练时根本没接触过。幻觉问题模型不确定答案时会一本正经地编造。RAG 解决这三个问题的方式很直接模型不需要“记住”所有知识它只需要学会“阅读”你给它的资料。知识从模型的参数里搬到了外部数据库里随时可以更新。2.2 RAG 的核心组件一个标准的 RAG 系统至少包含四个组件组件作用常见选型Embedding 模型把文本转换成向量OpenAI Embedding、BGE、M3E、text2vec向量数据库存储向量并支持相似度检索FAISS、Chroma、Milvus、Qdrant、Weaviate大语言模型基于上下文生成答案GPT 系列、Claude、Qwen、DeepSeek、GLM 等检索链路负责切块、召回、排序、过滤通常由开发者自己设计也是本文重点2.3 三层检索策略到底指什么这里要先澄清一个容易混淆的点很多人把“检索”理解成“向量检索 关键字检索”这种多路召回再拿 RRF 融合一下就觉得完成了检索策略。这种理解不是不对但不够完整。因为它只覆盖了“怎么把候选找出来”没有回答两个更关键的问题找出来的候选是不是足够准模型生成的结果有没有忠实于检索到的资料所以在面试或者实际项目里更推荐的表达方式是RAG 的检索策略是一个三层漏斗每一层解决一个不同的问题。层级名称核心问题典型技术第一层粗召回层如何在几十万甚至上千万文档中快速找到候选向量检索、BM25、混合检索第二层精排层如何从几十个候选里挑出最相关的几个Cross-Encoder 重排序、RRF 融合、LLM 排序第三层生成校验层如何保证生成的答案基于正确资料而不是模型编造引用溯源、置信度阈值、自检提示词这个三层结构既是面试回答的骨架也是实际搭建 RAG 系统时的架构参考。3. 第一层检索粗召回与向量检索3.1 粗召回要解决什么问题粗召回是检索链路的第一站。它的目标不是“准”而是“快”和“全”。想象一个企业知识库有 50 万条文档片段。用户提问后系统需要在几百毫秒内把可能相关的候选找出来然后交给后面的精排层去精细化筛选。如果第一层就做非常复杂的计算整个系统会慢到不可用。所以粗召回的技术选型通常是向量检索用 embedding 模型把问题和文档都转成向量然后计算余弦相似度或者内积。稀疏检索用 BM25 这类基于词频的关键字检索。混合检索向量检索和 BM25 各跑一路再用 RRF 或加权方式合并结果。3.2 一个最小可用的向量检索实现下面用一个最简示例演示粗召回层。这里选 FAISS 作为向量数据库因为它在本地开发环境里很好部署不需要额外启动服务。先安装依赖pip install faiss-cpu sentence-transformers然后构建一个最小示例import faiss import numpy as np from sentence_transformers import SentenceTransformer # 1. 加载 embedding 模型 model SentenceTransformer(BAAI/bge-small-zh-v1.5) # 2. 准备文档片段实际项目中这里来自切块阶段 documents [ RAG 检索增强生成是一种结合检索和生成的技术。, 向量数据库用于存储高维向量支持相似度检索。, 切块策略是 RAG 系统效果的关键影响因素。, 重排序可以显著提高检索结果的准确率。, 大语言模型存在幻觉问题RAG 是缓解手段之一。, ] # 3. 文档向量化 doc_vectors model.encode(documents, normalize_embeddingsTrue) dimension doc_vectors.shape[1] # 4. 构建 FAISS 索引 index faiss.IndexFlatIP(dimension) # 内积 归一化向量 余弦相似度 index.add(doc_vectors) # 5. 用户问题 question 为什么 RAG 可以缓解幻觉问题 question_vector model.encode([question], normalize_embeddingsTrue) # 6. 检索 TopK k 3 scores, indices index.search(question_vector, k) print(检索结果) for i, idx in enumerate(indices[0]): print(f第 {i 1} 名相似度 {scores[0][i]:.4f}内容{documents[idx]})这段代码做的事情很直观用SentenceTransformer加载中文 embedding 模型。把文档片段编码成向量。构建 FAISS 索引并添加向量。对用户问题进行编码检索最相似的 TopK 个片段。这里有个细节值得注意normalize_embeddingsTrue配合IndexFlatIP内积索引得到的相似度就是余弦相似度。如果你不加归一化内积数值会受到向量长度影响结果不一定等同于语义相似度。3.3 粗召回层的常见误区第一层有个高频误区追求“一次检索就精准命中”。真实情况是粗召回的目标是把“可能相关”的内容捞进来允许里面混入一些不相关内容。你把候选从 50 万过滤到 50 条这层就算成功了。真正决定最终答案质量的是后面怎么从 50 条里选出 5 条。所以如果你在粗召回层把 TopK 设得太小比如只取 1一旦向量检索第一轮就没命中后面再怎么做重排序都无力回天。更稳妥的思路是粗召回多取一些精排层再去伪存真。4. 第二层检索重排序与精排4.1 为什么向量检索之后还要重排序向量检索的本质是“语义压缩”把一个长句子压缩成一个高维向量这中间必然丢失大量细节。两个句子可能在向量空间里距离很近但细看之后一个是讲 RAG 的切块另一个只是在讲文本处理的一般概念。相似度分数高不代表真的是用户要的答案。重排序层就是来解决这个问题的。它的思路是既然向量检索的粗粒度打分不够精细那就用一个更强的模型把“问题 候选文档”拼在一起做深度交互逐字逐句计算它们之间的相关性。这里有一个非常关键的区分双塔模型Bi-Encoder与交叉编码器Cross-Encoder。类型输入方式速度精度适用阶段Bi-Encoder如 embedding 模型问题和文档分别编码成向量快可预计算中等粗召回Cross-Encoder问题和文档拼接后同时输入模型慢无法预计算更高重排序在粗召回阶段文档向量可以提前算好存进向量库用户提问时只需要算问题向量速度很快。但 Cross-Encoder 必须把每一对“问题 文档”都真实算一遍所以它注定了只能在一个小的候选集上使用。4.2 用 Cross-Encoder 做重排序这里使用sentence-transformers里的 CrossEncoder 类代码非常简洁from sentence_transformers import CrossEncoder # 加载重排序模型 reranker CrossEncoder(BAAI/bge-reranker-base) # 粗召回阶段拿到的候选文档 candidates [ RAG 检索增强生成是一种结合检索和生成的技术。, 大语言模型存在幻觉问题RAG 是缓解手段之一。, 向量数据库用于存储高维向量。, ] question 为什么 RAG 可以缓解幻觉问题 # 构造 问题 文档 对 pairs [(question, doc) for doc in candidates] # 计算相关分数 scores reranker.predict(pairs) print(重排序结果) for i, (score, doc) in enumerate(sorted(zip(scores, candidates), keylambda x: x[0], reverseTrue)): print(f分数 {score:.4f}{doc})注意重排序的输出结果和粗召回的顺序可能完全不同。在刚才的示例里粗召回第三名的向量数据库那条很可能语义距离也很近但重排序模型读完发现它和“幻觉”关系不大打分就会往下压。4.3 重排序层的工程意义从效果角度看重排序通常能带来 10% 到 30% 的检索准确率提升这在 RAG 场景里是肉眼可见的差别。不同重排序模型效果不同但“加一层重排序”这件事本身已经是从 demo 到生产环境的分水岭。从面试角度看如果你能主动说出“粗召回 重排序”的两段式设计并且解释清楚为什么不用 Cross-Encoder 直接做召回面试官基本就能判断你是真的做过 RAG 项目而不是只背过概念。5. 第三层生成与校验5.1 检索完了不等于就能直接生成很多 RAG 项目把流程设计成检索 TopK → 拼 Prompt → 调 LLM → 返回答案。第三层想提醒你的是“生成环节”也应该有一套策略而不是无脑生成。原因在于检索得到的内容即使经过重排序也可能存在问题。比如重排后的 Top1 问题和文档相关性够了但文档本身是过时信息。文档足够相关但答案不在其中模型为了完成任务强行编造。多篇文档之间存在矛盾模型可能哪边都不完全采用。这些问题的共同本质是模型生成的答案可能没有“忠实于”检索到的资料。RAG 领域把这个问题叫作“忠实性”Faithfulness问题。5.2 生成校验策略有哪些常见的做法有四类引用溯源要求模型在生成答案时标注依据来自哪一段文档。用户可以看到答案出处。置信度阈值检索结果最高分低于某个阈值时直接让模型说“当前知识库中未找到相关信息”。自检提示词在 Prompt 里明确要求模型如果资料不充分就直接回答不知道不许编造。答案验证用一个验证模型检查生成的答案是否被检索文档支持。一个简单的 Prompt 设计示例你是一个知识库问答助手。 请基于以下资料回答问题。 回答要求 1. 只使用资料中出现的信息。 2. 如果资料不足以回答问题请明确回复“资料中未找到相关信息”。 3. 在回答末尾标注依据片段编号例如【1】【2】。 资料 【1】RAG 通过检索外部知识来缓解大模型的幻觉问题。 【2】切块策略影响检索到的内容质量。 【3】重排序可以提升检索准确率。 问题RAG 如何缓解幻觉问题5.3 校验层的代码实现用一个轻量判断实现生成校验def check_answer_supported(question: str, answer: str, contexts: list[str]) - bool: 简单校验答案是否明确表示未找到以及是否出现了上下文中的关键词。 生产环境建议用 LLM 或专门模型做更精细的验证。 if 未找到相关信息 in answer: return False if 资料中未找到 in answer: return False # 简单检查答案文本是否至少引用了一个上下文片段的关键内容 context_text .join(contexts) # 这里用最朴素的方式做检查实际项目可以替换为语义匹配 overlap set(answer) set(context_text) return len(overlap) 20 # 示例 contexts [ RAG 通过检索外部知识来缓解大模型的幻觉问题。, 向量数据库用于存储高维向量。 ] answer RAG 通过检索外部知识把相关内容拼接到 Prompt 中缓解了幻觉问题。 print(check_answer_supported(RAG 如何缓解幻觉, answer, contexts))上面这个函数逻辑非常简单实际项目中更推荐用打分模型或者让 LLM 自己判断“答案是否被资料支持”。这里想强调的是生成以后一定要有一道校验逻辑这是 RAG 系统走向生产环境的必修课。6. 切块策略RAG 效果的分水岭6.1 为什么切块在热搜榜上RAG 相关的技术讨论里“切块策略”是出现频率非常高的词。原因很简单检索效果的上限在切块那一刻就已经被锁定了。这么说可能有点绝对但事实确实如此。向量检索只能找出“和问题相似的文本块”如果你切的块本身信息残缺、语义混杂、粗细不当后面的重排序再强也无济于事。6.2 常见切块方式对比切块方式实现思路优点缺点适用场景固定长度切块按字符数或 token 数切割实现简单性能稳定容易切断句子或语义单元快速原型、通用场景递归字符切块依次按段落、句子、字符层级递归切尽量保持语义完整性参数需要调优大多数文档场景结构感知切块按 Markdown 标题、HTML 标签、代码结构切保留文档逻辑依赖文档格式技术文档、网页、Markdown语义切块用 embedding 相似度判断句子边界语义完整计算成本高边界仍启发式对语义完整性要求较高的场景6.3 最实用的切块策略代码实际项目中使用最广的是 LangChain 里的RecursiveCharacterTextSplitter它的核心思想是维护一个分隔符列表按优先级从上到下尝试切分尽量保证每个块语义完整。from langchain.text_splitter import RecursiveCharacterTextSplitter text RAG 系统面临的核心挑战是检索质量。 如果检索到的内容不相关生成的答案就会跑偏。 切块策略直接影响检索质量是 RAG 项目中最需要调优的环节之一。 在实践中我们可以根据文档结构先按段落切分再按句子切分。 太小的块会丢失上下文太大的块会引入噪声。 因此需要平衡上下文长度和语义纯度。 # 核心参数chunk_size 和 chunk_overlap text_splitter RecursiveCharacterTextSplitter( chunk_size100, # 每块的最大字符数可按实际 token 数调整 chunk_overlap20, # 相邻块之间的重叠字符数 separators[\n\n, \n, 。, , , , ], keep_separatorTrue, ) chunks text_splitter.split_text(text) for i, chunk in enumerate(chunks): print(f第 {i 1} 块长度 {len(chunk)}{chunk})6.4 切块参数选择的关键判断关于chunk_size和chunk_overlap直接给出经验参考一般中文知识库场景下chunk_size在 200 到 500 之间比较稳妥。chunk_overlap通常设置为chunk_size的 10% 到 20%。如果文档是技术问答对可以适当减小块尺寸让每个块聚焦一个完整问答。如果文档是长篇幅的论述型内容块太小会丢失上下文块太大检索命中精度会下降。要注意的是不同 embedding 模型的输入长度上限不同切块大小不要超过模型的 max sequence length。BGE 系列一般支持 512 token大约对应 700 到 900 个中文字符。6.5 长文档的切块进阶策略遇到几十页甚至上百页的长文档时仅仅靠“切块”还不够通常还需要配合元数据给每个块打上文档名、章节标题、页码标签。检索时先按元数据过滤缩小候选范围。回答时可以根据章节标题生成答案的上下文位置说明。这种做法在面试里讲出来会明显高于“我会用 LangChain 的 splitter 切一下”这种回答。7. 完整示例跑通一个三层检索 RAG 流程7.1 环境准备这里给出一个完整的 Python 实现覆盖前面三层检索的核心链路。先安装依赖pip install faiss-cpu sentence-transformers langchain langchain-community openai如果使用的是 OpenAI 接口需要配置环境变量export OPENAI_API_KEYyour-api-key如果模型接口是兼容 OpenAI 格式的国内服务也可以通过base_url来指定这里不展开代码里会留出配置位。7.2 项目文件结构rag_demo/ ├── data/ │ └── raw_docs.py # 模拟知识库文档 ├── rag_engine.py # 三层检索主流程 └── evaluate.py # 效果验证脚本7.3 构造模拟知识库# 文件路径rag_demo/data/raw_docs.py DOCUMENTS [ RAGRetrieval-Augmented Generation是一种将检索与生成结合的架构。 它通过从外部知识库中检索相关内容帮助大语言模型回答私有数据问题。 这样可以缓解幻觉问题同时让模型知识保持最新。 , 向量数据库是 RAG 系统的重要组件之一。 它负责存储文档的向量表示并提供相似度检索能力。 常见的向量数据库包括 FAISS、Chroma、Milvus 等。 , 切块策略直接影响 RAG 检索质量。 如果切块过大会引入噪声如果切块过小会丢失上下文。 推荐使用递归字符切块并配合 chunk_overlap 保持语义连贯。 , 重排序是 RAG 检索链路中的关键步骤。 粗召回负责快速获取候选重排序负责精细筛选。 交叉编码器Cross-Encoder在重排序任务中表现优于双塔模型。 , OpenAI 提供了 embedding 接口和 chat 接口。 embedding 接口用于将文本转换为向量。 chat 接口用于基于检索到的上下文生成最终答案。 , 切块长度越高单块包含的信息越丰富但检索精度可能下降。 切块长度越小检索精度可能提高但上下文可能不完整。 实际项目中需要通过评估数据来确定最优参数。 , ]7.4 三层检索主流程# 文件路径rag_demo/rag_engine.py import os import numpy as np import faiss from sentence_transformers import SentenceTransformer, CrossEncoder from data.raw_docs import DOCUMENTS os.environ.setdefault(OPENAI_API_KEY, your-api-key) class SimpleRAGEngine: 一个简化的三层检索 RAG 引擎 1. 切块 2. 粗召回向量检索 3. 精排重排序 4. 生成LLM通过 openai 接口 def __init__(self, chunk_size: int 80, top_k_candidates: int 5, top_k_final: int 3): self.chunk_size chunk_size self.top_k_candidates top_k_candidates self.top_k_final top_k_final self.embedder SentenceTransformer(BAAI/bge-small-zh-v1.5) self.reranker CrossEncoder(BAAI/bge-reranker-base) self.index None self.chunks [] self._build_index() def _build_index(self): 把文档切块向量化构建 FAISS 索引。 chunks [] for doc in DOCUMENTS: # 这里用最简单的方式切块实际项目中建议用 RecursiveCharacterTextSplitter for i in range(0, len(doc), self.chunk_size): chunk doc[i: i self.chunk_size].strip() if chunk: chunks.append(chunk) self.chunks chunks vectors self.embedder.encode(chunks, normalize_embeddingsTrue) self.index faiss.IndexFlatIP(vectors.shape[1]) self.index.add(vectors) print(f索引构建完成共 {len(chunks)} 个块) def _recall(self, query: str): 第一层粗召回 q_vec self.embedder.encode([query], normalize_embeddingsTrue) scores, indices self.index.search(q_vec, self.top_k_candidates) candidates [self.chunks[idx] for idx in indices[0]] return candidates def _rerank(self, query: str, candidates: list[str]): 第二层重排序 pairs [(query, doc) for doc in candidates] scores self.reranker.predict(pairs) ranked sorted(zip(scores, candidates), keylambda x: x[0], reverseTrue) return [doc for _, doc in ranked[:self.top_k_final]] staticmethod def generate(query: str, contexts: list[str]) - str: 第三层生成 校验。这里通过 openai 接口调用 LLM。 from openai import OpenAI client OpenAI() context_text \n\n.join( f【{i 1}】{ctx} for i, ctx in enumerate(contexts) ) prompt f请基于以下资料回答问题。 资料 {context_text} 要求 - 只使用资料中出现的信息。 - 如果资料不足请回答资料中未找到相关信息。 - 回答末尾标注依据片段编号例如【1】【2】。 问题{query} resp client.chat.completions.create( modelgpt-4o-mini, # 实际使用哪个模型以订阅或部署为准 messages[ {role: system, content: 你是知识库问答助手。}, {role: user, content: prompt}, ], temperature0.2, ) return resp.choices[0].message.content def answer(self, query: str) - str: 完整流程召回 - 重排 - 生成 candidates self._recall(query) contexts self._rerank(query, candidates) answer self.generate(query, contexts) return answer, contexts if __name__ __main__: engine SimpleRAGEngine() questions [ 切块长度对 RAG 效果有什么影响, 向量数据库在 RAG 中起什么作用, 什么是重排序, ] for q in questions: print(- * 60) print(f问题{q}) answer, contexts engine.answer(q) print(检索到的上下文) for i, ctx in enumerate(contexts, 1): print(f 【{i}】{ctx}) print(f回答\n{answer})代码中的_build_index使用固定长度切块这个设计只是为了演示真实项目应替换为递归字符切块或语义切块。generate方法通过openai库调用模型如果本地没有配置密钥可以把generate替换成调用任何兼容接口的封装。7.5 运行方式cd rag_demo python rag_engine.py8. 运行结果与效果验证8.1 预期输出运行上面代码后控制台会先显示索引构建日志索引构建完成共 12 个块然后逐条显示问题、检索到的上下文和回答。理想的输出效果是检索到的上下文和问题高度相关回答能够从上下文中找到充分依据并且引用了对应的片段编号。8.2 如何判断成功判断一个 RAG 系统是否“跑通了”不能只看“模型生成了答案”。建议用三个维度验证检索相关度人工检查每个问题的检索结果前三个片段是否都围绕问题展开。答案忠实度检查答案中的关键信息是否都能在上下文片段中找到出处。完整性对于知识库里有明确答案的问题模型是否完整覆盖了要点。8.3 失败时第一步排查如果发现检索结果不相关不要急着调 Prompt先从检索链路开始排查问题第一步排查检索结果完全是乱取看看切块结果是不是把多个无关话题切进了一个块检索结果相关但答案不对检查 Prompt 是否限制了模型只能使用资料回答答案有幻觉检查生成参数 temperature 是否偏高或校验层是否生效检索太慢检查向量索引类型IndexFlatIP在海量数据下不适合生产环境9. 常见问题与排查思路以下是真实项目中高频出现的 RAG 检索链路问题问题现象可能原因排查方式解决方案检索结果不相关切块过大块内混合多个主题查看具体切块文本缩小 chunk_size改用递归切块相似问题效果不稳定缺少重叠信息检查相邻块是否语义断裂提高 chunk_overlap关键词匹配好的文档排不上去纯向量检索对专有名词不敏感测试 BM25 效果改用混合检索 RRF重排序后效果反而变差粗召回阶段候选丢失检查 TopK 是否太小扩大粗召回 TopK模型回答“资料中没有”但仍编造校验 Prompt 约束不足检查生成的回答文本增加后置校验逻辑长文档后半段内容检索不到切块破坏了段落结构检查文档结构是否被忽略使用结构感知切块中文问题编码效果差embedding 模型不是中文优化的对比不同模型检索效果换用 BGE/M3E 等中文模型10. 最佳实践与工程建议10.1 切块参数要基于评估调整不要直接照抄网上的参数。每个知识库的文档风格不同建议构建一个 50 到 100 条的小型评估集每个问题带上标准答案或标准检索片段。然后对比不同chunk_size、chunk_overlap和切块方式的检索命中率用数据确定参数。10.2 元数据过滤比想象中更重要如果知识库包含多种类型文档比如技术手册、产品公告、故障记录建议在切块时保留文档类型、时间、来源等元数据。检索时先按元数据过滤再走向量检索。这比单纯靠向量找效果要稳定得多。10.3 混合检索是生产环境的常态向量检索擅长语义相关BM25 擅长关键词精确匹配。业务名称、型号、异常码这类内容向量不一定认识但 BM25 几乎不会漏。推荐两条路都走最后用 RRF 合并结果。10.4 重排序必须限定候选集大小一般粗召回 TopK 在 20 到 50 之间比较合理。如果候选太多重排序模型会变慢如果太少重排序没有意义。经验上 20 到 50 是一个不错的起点。10.5 不能忽略安全边界RAG 系统里涉及权限管理时切块和检索必须在用户权限范围内进行。否则可能出现“用户问了一个问题检索结果里包含了他无权访问的文档内容”这类越权泄露问题。生产环境一定要在检索链路中增加权限过滤而不能只靠 Prompt 约束模型。10.6 生成层要控制温度RAG 场景下temperature设置为 0.1 到 0.3 比较合适。温度过高模型的表达会更“自由”也更容易脱离资料编造温度过低回答比较保守但更利于验证忠实性。11. 总结与后续学习方向RAG 检索策略不是一个单一步骤而是一条三层链路。第一层粗召回负责“找得快”第二层重排序负责“找得准”第三层生成校验负责“答得稳”。把这三层讲清楚面试的时候能明显高出“我会向量检索”一个段位做项目的时候也能少走很多弯路。代码层面建议你照着第 7 节的示例把它跑通然后依次做三件事替换成自己的文档建一个小型知识库。尝试调整切块参数观察检索结果变化。加入混合检索和重排序对比效果差异。如果想把这篇内容继续深入以下几个方向值得关注各种 embedding 模型在中文场景下的效果对比。Cross-Encoder 重排序模型的训练与微调。基于 LLM 的答案忠实性评估方法。长文档情况下的层级检索与摘要增强方案。建议收藏备用。下次面试再被问到“RAG 策略”你可以从切块开始讲到检索链路的三层设计再落到评估和参数调优。这已经不是背诵答案而是一套能真正落地的方法论。