字节面试官:“RAG 不就是给大模型挂个知识库?“,我:“文档切分、向量检索、多路召回、Re-rank、RAG 评估、幻觉抑制……“ 做了两年 AI 开发说实话从 Java 转过来这条路走得不轻松我之前 Java 写了将近 10 年Java 相关的东西玩得贼溜两年前转向 AI 方向做 RAG 做了快一年半前阵子朋友去字节面试回来跟我说面试官上来就问“RAG 不就是给大模型挂个知识库嘛有啥难的”我当时就想这种这问题问得好、但问题底下坑贼深的想想都怕这篇文章我把 RAG 链路每个真正有技术含量的点都说清楚不讲 PPT只讲工程里真正踩过的那些事看完你能搞清楚这些问题面试题对应章节文档切分有哪些策略chunk size 怎么定overlap 有啥用文档切分Small-to-Big Chunking 是什么解决啥问题文档切分Bi-Encoder 和 Cross-Encoder 架构区别为啥 Re-rank 精度更高嵌入模型 / Re-rank嵌入模型怎么选型什么时候需要 fine-tuning嵌入模型HNSW 原理是什么ef_construction、ef_search 这些参数啥意思向量索引HyDE 是啥为啥用假设文档向量检索比直接用问题向量效果好Query 改写Multi-Query 和 Step-Back Prompting 分别解决什么问题Query 改写多路召回结果怎么融合RRF 算法原理是什么为啥不能直接按分数加权多路召回 RRFLost in the Middle 是什么现象对 RAG 有啥影响怎么应对Lost in the Middle上下文压缩是干嘛的LLMLingua 怎么工作的上下文压缩幻觉怎么抑制Prompt 约束为啥不够还需要什么机制幻觉抑制RAGAS 四个指标分别怎么计算的RAG 评估什么情况该用 RAG什么情况该微调怎么判断RAG vs 微调Self-RAG 和多跳检索是什么Agentic RAG 解决什么问题Agentic RAGRAG 最表面的样子确实很简单用户问题 → 检索知识库 → 召回相关内容 → 塞给大模型 → 得到回答这就是 RAG 的全貌嗯PPT 里是这样但从能跑到跑得好之间有一条他妈贼长的沟每一段都是独立的工程问题如果你近期准备面试跳槽建议在ddkk.com在线刷题涵盖 一万 道 Java 面试题几乎覆盖了所有主流技术面试题还有市面上最全的技术五百套精品系列教程免费提供。文档切分第一个坑没人告诉你切粒度怎么定知识库里的内容是你把 PDF、Word、网页、数据库内容塞进去的切之前先要解析这一步就有坑——PDF 里的表格、图片、多列排版普通解析工具拿出来的文本是乱的直接切就是在切垃圾切分策略大概分这几种面试经常问固定大小切分Fixed-size Chunking按 Token 数量硬切实现最简单语义边界全破坏基本不单独用递归字符切分Recursive Character Splitting按分隔符优先级递归切先找段落分隔没有再找换行没有再找句号是工程里最常用的 baseline语义切分Semantic Chunking对每两句之间算嵌入余弦相似度相似度突然下降的地方就是语义边界切在那儿语义完整性最好但计算成本高Small-to-Big / Parent-Child Chunking这是我觉得最值得说的一个——切成小 chunk 用来检索粒度细、语义准检索到之后往上找它的父级大 chunk 塞给大模型上下文完整。检索用小的、生成用大的两不误# Parent-Child Chunking 核心逻辑from llama_index.core.node_parser import HierarchicalNodeParser, get_leaf_nodesparser HierarchicalNodeParser.from_defaults( chunk_sizes[2048, 512, 128] # 三层文档级、段落级、句子级)nodes parser.get_nodes_from_documents(documents)leaf_nodes get_leaf_nodes(nodes) # 只索引最小粒度的叶子节点# 检索命中叶子节点后通过 parent_id 拿父级节点的完整内容传给 LLMchunk 之间一定要保留 overlap一般 10%~15% 的 Token 重叠防止关键信息被切断chunk size 没有银弹跟你的业务文档平均段落长度强相关上线前必须跑评估对比嵌入模型召回天花板在这里定死了文档切好了每个 chunk 过嵌入Embedding模型得到向量存进向量数据库这里有个认知误区很多人以为向量数据库是瓶颈实际上嵌入模型才是嵌入模型本质是个双塔编码器Bi-Encoder问题和文档各自独立编码成向量检索时算余弦相似度。速度快但问题向量和文档向量是在各自的语义空间里独立算的没有交互精度有损选型上看 MTEB 榜单Massive Text Embedding Benchmark分中文、英文、多语言榜国内私有化部署常用的BGE 系列BAAI 出的中文效果贼好、M3E、BCEOpenAI 的 text-embedding-3-large 效果确实强但数据不能出境、成本高嵌入模型 fine-tuning这个点面试经常问通用嵌入模型在垂直领域法律、医疗、金融表现会下滑因为这些领域术语和通用语料分布差异大。用领域内的正负样本对做对比学习微调召回率提升 10~20% 是正常的维度数量也有取舍text-embedding-3-large 支持 Matryoshka 压缩3072 维压到 256 维精度损失可接受存储和检索速度翻几倍在高并发场景下值得考虑向量索引HNSW 到底在干啥向量库里的索引不是说存个数组然后遍历算余弦那样 O(n) 的复杂度数据量一上来直接跪生产里用的是**近似最近邻ANN**算法牺牲一点召回精度换来亚线性查询速度最常用的是HNSWHierarchical Navigable Small WorldMilvus、Qdrant、Weaviate 默认都是这个原理简单说构建一个多层图底层是全量节点越往上节点越稀疏。查询时从最顶层少量节点开始贪心地往最近邻方向走逐层下降最终在底层找到候选集。类比跳表但在高维空间里HNSW 核心参数- M每个节点最多连接的邻居数越大图越稠密精度高但内存和构建时间涨- ef_construction构建时搜索候选集大小越大索引质量越好但构建越慢- ef_search查询时搜索范围越大召回越准但延迟越高IVF倒排文件索引是另一种选择先聚类分成 nlist 个桶查询时只搜最近的 nprobe 个桶。内存占用比 HNSW 低但精度也低一些适合内存敏感场景这里有个经典三角取舍精度 vs 延迟 vs 内存没有一种索引全赢得根据业务 SLA 选Query 改写被严重低估的一环这是大部分 RAG 教程里讲得最少、但工程里最有价值的一块问题在哪用户的原始问题通常不是好问题“那个合同的事怎么样了”——没有主语向量检索根本不知道往哪召回 “帮我看看条款”——歧义检索一堆不相关的 “我们产品的退款政策”——过于简短语义不够饱满HyDEHypothetical Document Embeddings这个是 2022 年 CMUCarnegie Mellon University的论文提出来的核心思想很反直觉用户的问题和知识库里的答案在嵌入空间里的分布是不一样的。问题的向量 ≠ 包含答案的文档的向量HyDE 的做法先让大模型根据问题生成一段假设性的回答文档不管对不对然后用这段假设文档的向量去检索而不是用原始问题向量# HyDE 实现核心def hyde_retrieve(query: str, vectorstore, llm): # 生成假设文档 hypothetical_doc llm.invoke( f请根据以下问题写一段可能的答案文档100字左右{query} ) # 用假设文档向量检索而不是原始问题 results vectorstore.similarity_search(hypothetical_doc.content, k10) return results为啥有效因为假设文档的词汇分布、语义风格跟知识库里的文档更接近向量空间对齐更好召回率提升非常明显尤其在专业领域问答里Multi-Query 改写一个问题生成 3~5 个不同角度的改写各自检索结果合并去重处理的是向量检索对措辞敏感的问题——同一个意思换个说法召回结果可能差很多from langchain.retrievers.multi_query import MultiQueryRetrieverretriever MultiQueryRetriever.from_llm( retrievervectorstore.as_retriever(), llmllm # 用 LLM 自动生成多个查询变体)# 内部会生成多个问题变体分别检索后去重合并docs retriever.invoke(张三的劳动合同什么时候到期)Step-Back Prompting把具体问题退一层变成一个更抽象的背景性问题先检索背景知识再把背景知识 原问题一起给大模型推理比如这款药能跟阿司匹林一起吃吗→ Step-Back 之后变成药物相互作用的判断原则是什么先检索这个更泛化的问题拿到药物相互作用的背景知识再结合原问题回答注意跟 Query Decomposition把一个问题拆成多个子问题并行检索不一样Step-Back 只生成一个更高抽象层次的问题目的是补充背景知识不是拆解原问题适合需要背景领域知识支撑的推理类问题多路召回 RRF融合算法不是随便加的向量检索ANN BM25 关键词检索各跑一路但融合怎么融直接按分数加权不行——两路的分数量纲完全不同余弦相似度理论范围是 [-1, 1]BM25 分数可能是 [0, 20]没法直接加工程里用的是RRFReciprocal Rank FusionRRF(d) Σ 1 / (k rank_i(d))k 是平滑常数一般取 60rank_i(d) 是文档 d 在第 i 路排序里的位置这个公式的妙处在于只用排名不用分数天然解决了量纲不统一的问题排名靠前的文档权重高靠后的文档贡献迅速衰减def reciprocal_rank_fusion(results_list: list[list], k: int 60): scores {} for results in results_list: for rank, doc in enumerate(results): doc_id doc.metadata[id] scores[doc_id] scores.get(doc_id, 0) 1.0 / (k rank 1) # 按融合分数重排 return sorted(scores.items(), keylambda x: x[1], reverseTrue)多路召回合并后候选集可能有 30~100 条直接塞给大模型上下文炸了这时候 Re-rank 上场Re-rank双塔 vs 交叉编码器原理要搞清楚嵌入模型是双塔Bi-Encoder问题和文档独立编码检索快但精度有损Re-rank 模型是交叉编码器Cross-Encoder把问题 文档拼接在一起走完整的 Transformer attention输出一个相关性分数为啥 Cross-Encoder 精度更高因为问题和文档的 Token 之间有完整的 attention 交互能捕捉到细粒度的语义匹配而双塔的向量是独立算的没有这种交互代价是推理成本高不能做全量检索只用于精排 top-Nfrom sentence_transformers import CrossEncoderreranker CrossEncoder(BAAI/bge-reranker-v2-m3) # 中文效果好的 Re-rank 模型pairs [(query, chunk.page_content) for chunk in candidate_chunks]scores reranker.predict(pairs)# 按 Re-rank 分数重排取 top5 送给 LLMranked sorted(zip(scores, candidate_chunks), keylambda x: x[0], reverseTrue)final_chunks [chunk for _, chunk in ranked[:5]]Re-rank 模型也可以 fine-tuning在特定领域用标注数据训练精度还能再上一层Lost in the Middle大模型对上下文位置的感知不均匀这是 2023 年 Stanford 的一篇论文《Lost in the Middle》发现的问题做 RAG 必须知道结论大模型对放在上下文开头和结尾的内容注意力最高中间的内容注意力显著下降你检索了 10 个 chunk最相关的那个如果被排在第 5 个位置塞进 Prompt大模型有可能没看清楚它影响直接Re-rank 排序好之后不要无脑按分数顺序拼接要把最相关的内容放在 Prompt 的开头或结尾def arrange_chunks_for_llm(ranked_chunks: list) - list: # Lost in the Middle 应对最相关的放两端次相关的放中间 if len(ranked_chunks) 2: return ranked_chunks result [] result.append(ranked_chunks[0]) # 最相关放开头 result.extend(ranked_chunks[2:]) # 次相关放中间 result.append(ranked_chunks[1]) # 第二相关放结尾 return result这个细节大部分 RAG 实现都没做但对答案质量有可感知的影响上下文压缩不是所有召回内容都有用Re-rank 之后拿到 top5 chunk但每个 chunk 里可能只有 1~2 句话是真正跟问题相关的剩下的都是噪声把这些噪声全塞给大模型一是占上下文窗口二是干扰大模型的注意力上下文压缩Context Compression对每个召回 chunk用一个小模型或 LLM 抽取其中跟问题真正相关的句子去掉无关内容from langchain.retrievers import ContextualCompressionRetrieverfrom langchain.retrievers.document_compressors import LLMChainExtractorcompressor LLMChainExtractor.from_llm(llm)compression_retriever ContextualCompressionRetriever( base_compressorcompressor, base_retrieverbase_retriever)# 返回的 doc 已经被压缩只保留跟 query 相关的句子docs compression_retriever.invoke(query)另一个思路是LLMLingua微软出的用一个小语言模型对 Prompt 做 Token 级压缩在保留语义的前提下通常能压缩到原长度的 1/31/535 倍压缩在长文档 RAG 里特别有用更激进的压缩比质量会明显下降不要轻易追求 10 倍压缩幻觉抑制多层机制叠加才能压住即便检索质量已经很好大模型还是可能创作知识库里没有的内容Prompt 约束是第一层也是最基础的你是一个问答助手请只根据以下材料回答问题。如果材料中没有足够的信息请回答根据现有材料无法回答不要编造内容。材料{context}问题{question}这一层有效但不够大模型有时候还是会偷偷补脑引用溯源是第二层要求大模型在回答中标注每句话来自哪个来源答案可追溯便于人工校验。同时大模型在生成时被迫对齐到具体来源幻觉率会下降忠实度自检是第三层用另一个 LLM或同一个 LLM对生成的答案做 NLI自然语言推断验证——判断答案中的每个声明是否能从检索到的上下文中推断出来。RAGAS 的 Faithfulness 指标就是这么算的拒答机制是第四层当检索到的内容跟问题相关性都低于阈值时直接拒答不要勉强生成做了一年多我的经验是幻觉没有银弹是多层叠加才能压到业务可接受的范围想靠一个 Prompt 模板搞定的都是想太多RAG 评估没有量化就是在瞎优化RAGAS 框架四个核心指标说一下每个的计算原理不只是知道名字忠实度Faithfulness把 LLM 的回答拆成若干原子声明逐条判断是否能从检索到的上下文推断出来能推断出的比例就是 Faithfulness。值越低说明幻觉越多答案相关性Answer Relevancy反过来用 LLM 根据答案生成若干个可能的问题算这些生成问题和原始问题的向量相似度均值。答案跑题了生成的问题跟原始问题就不像分数就低上下文召回率Context Recall把 ground truth 答案拆成原子声明判断每条声明是否能在检索到的上下文里找到支撑。覆盖不到说明检索漏了关键内容上下文精准率Context Precision检索到的每个 chunk判断它对生成正确答案是否真的有用有用的比例就是 Precision。噪声多了这个分低这四个指标互相制衡检索的 chunk 多Context Recall 上去了Context Precision 下去了Re-rank 阈值调高Precision 上去Recall 下去。没有全赢的参数得根据业务优先级取舍评估还有一个关键你必须有一个标注好的测评集至少 100~200 条问答对覆盖你业务的核心场景没有这个所有我优化了一下感觉好多了都是玄学RAG vs 微调选错了方向就白做了这是个高频面试题什么时候该用 RAG什么时候该微调Fine-tuning两者不是对立的但侧重点完全不同RAG 解决的是知识问题大模型不知道你的私有数据、实时数据、长尾知识。知识库可以随时更新不用重新训练成本低可解释性好能追溯来源微调解决的是行为问题模型回答风格不对、格式总是乱、专业术语总写错、特定任务推理能力弱。这些靠 Prompt 很难彻底解决需要通过数据让模型记住期望行为一个判断框架问题是模型不知道某个事实/数据 → RAG问题是模型知道但输出格式/风格不对 → Fine-tuning问题是模型在特定任务推理很差 → Fine-tuning问题是数据要实时更新、不能泄露 → RAG两者都有 → RAG Fine-tuning 联合先微调行为再 RAG 补知识微调还有个常见误区用 RAG 能解决的问题去微调。把 1000 条 FAQ 喂给模型微调效果还不如好好做 RAG因为微调的知识会随着数据变化失效而且微调的记忆是不透明的Agentic RAG更高阶但面试越来越爱问传统 RAG 是线性的检索一次生成一次Agentic RAG 让大模型自主决策检索过程Self-RAG模型在生成过程中动态判断我现在需不需要检索、“检索到的内容是否相关”、“我的回答是否有幻觉”。通过特殊 token 控制检索行为不是每次都检索而是按需检索多跳检索Multi-hop Retrieval对于复杂问题一次检索不够。先检索第一跳根据结果生成子问题再检索第二跳直到信息足够比如比较 A 公司和 B 公司 2024 年的净利润差异得先分别检索两家公司的财报数据再做比较这是两跳自适应检索Adaptive RAG根据问题复杂度选择策略。简单事实性问题直接检索一次需要推理的问题走多跳知识库完全覆盖不了的问题直接用大模型参数知识这块目前工程落地成本较高主要是链路变长了每一跳都可能引入误差评估也更难但在复杂企业知识问答场景里是大方向说回面试官那句话“RAG 不就是给大模型挂个知识库”没错就好比数据库不就是存数据的也没错但你把链路完整过一遍就知道文档解析和切分质量决定检索上限嵌入模型选型决定语义理解上限Query 改写决定你能不能把用户的烂问题变成好问题多路召回 RRF 解决覆盖率Re-rank 解决精排Lost in the Middle 决定你把内容怎么摆给大模型上下文压缩决定有多少噪声进去幻觉抑制决定大模型乱说话的概率评估体系让你知道自己在哪个坐标上哪个环节拉胯整个链路就塌我从 Java 转过来有个思维优势做过微服务的人天然知道链路里任何一环的质量都会拖累整体RAG 是同样的道理就是短板效应而且每一块都有独立的技术深度任何一块都能单独展开说很久真要做好一个企业级 RAG 系统不比搭一套稳定的 Java 微服务简单甚至某些地方更折腾因为大模型本身是个不确定的黑盒你优化完一块黑盒那头又给你整个幺蛾子出来学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】