
先跑个题。我以前看 RAG 相关的东西总有一种“道理我都懂但让我自己搭一套完全不知道从哪下手”的感觉。什么 embeddings、向量数据库、检索增强、Chunk 切分每个词单独拿出来都能聊两句但合在一起——尤其是当那些概念堆在论文和博客里的时候——就变得特别抽象。直到我逼着自己把一个端到端的 RAG Notebook 从头到尾、一个单元格一个单元格地跑了一遍才真正意识到这东西没什么玄乎的它本质上就是一个拆解得很清楚的查资料流程只是把“人查资料”的这个动作用代码重新实现了一遍。这篇内容不是论文复现也不是框架文档的翻译。我会把那一套跑通的 Notebook 拆开讲清楚里面每一个环节到底在做什么、为什么这么做、以及在真实项目里哪些地方容易出问题。适合谁看如果你跟我一样被各路 RAG 概念轰炸过但还没亲手跑通过一个完整链路或者跑通了却总觉得隔着一层纱不确定每一步在自己的数据上为什么有效或者无效那这篇文章应该能帮你把最后那层窗户纸捅破。1. 先别急着写代码RAG 的本质是“查、补、写”三段式很多人在学 RAG 的时候第一个误区就是直奔代码上来就pip install llama-index或者langchain然后照着文档抄一遍完事。跑通了还好万一跑不通或者跑通了但效果很怪就完全不知道去哪里排查。因为头脑里没有一个清晰的“预期模型”——你不清楚每一步到底应该产出什么。1.1 一句话说清楚 RAG 在做什么用最朴素的话讲RAGRetrieval-Augmented Generation检索增强生成就是给大模型配了一个可以随时翻阅的资料库。模型本身有它的“内存”训练时学到的知识但当它面对一个需要特定上下文、或者超出训练时效、又或者需要企业内部知识的问题时只靠“内存”回答就会开始胡编。RAG 的做法是在模型开口回答之前先从外部资料库里把相关的片段“查”出来然后把问题加上查到的片段一起扔给模型让它基于这些材料作答。那一套经典的 RAG Notebook不管用的是什么框架本质上都是在做这三件事查Retrieval根据用户问题从知识库里找出最相关的几段文本。补Augmented把“用户问题 检索到的文本片段”组装成一个新的、带上下文的提示词Prompt。写Generation大模型阅读组装好的提示词生成最终答案。我在跑通 Notebook 之前的困惑很大程度来自于把这三件事混在一起看。一旦拆开很多问题的定位就变得清楚比如答案里出现了资料里没有的信息那问题可能出在“查”没查准或者“写”模型太自由上比如答案答非所问那大概率是“查”这一步返回的内容本身就是错的。1.2 Notebook 是学习 RAG 最合适的载体可能有人会问为什么不直接用现成的框架或者直接用 Flask/FastAPI 写一个服务来学我的体验是学习阶段Notebook 的交互式执行特性几乎是为你理解这种多阶段链路量身定做的。原因很简单。RAG 链路每一阶段的产出都是可被“观察”的数据对象切分后你可以直接打印出每个 Chunk 的内容看看边界是不是合理。向量化后你可以检查向量的维度、相似度的分布。检索后你可以看看 Top-K 的结果跟问题到底相不相关。用 Notebook 跑我可以随时把中间变量打印出来看可以在任何一个单元格后面插入新代码做验证发现问题立刻就地调整。你要是直接堆一个 .py 脚本然后python main.py中间一有不对劲就得加日志、重新跑调试效率低太多了。而且 Notebook 天然是分段式的每一段代码的大小刚好对应 RAG 链路里的一个步骤这本身就是一种很好的教学分解。我当时用的就是 Jupyter Notebook 环境顺手把环境里没装好的依赖补了补然后一个单元格一个单元格地执行下来。那种“眼睁睁看着每一步输出逐步拼出完整链路”的体验比读十篇架构图都管用。1.3 一套完整的 RAG Notebook 应该包含哪些环节这里先给大家一个全局图景方便后面我们一一对照。我跑的那套 Notebook主线流程如下环节核心任务关键依赖/工具典型产出文档加载读取本地文档内容PyPDF2、python-docx、txt 读取纯文本字符串文本切分把长文本切成有语义边界的片段字符切分、递归字符切分、句级切分Chunk 列表向量化将每个文本片段转成向量OpenAI Embedding、HuggingFace Embedding向量列表索引构建把向量存入数据库并建立索引Chroma、FAISS、Elasticsearch向量索引用户查询处理把问题转成向量与文档向量化同一模型查询向量相似度检索找出最相关的 Top-K 个 Chunk向量相似度计算余弦/点积/L2相关文档片段提示词组装把问题和检索结果拼为 PromptPrompt 模板完整 Prompt生成调用 LLM 生成答案OpenAI、智谱、Ollama 等最终回答我当时看着这个表格最大的感受就是RAG 并不神秘它就是一个典型的流水线作业每一个环节都有明确的输入、输出和衡量标准。下面我就按这个链路把每一步实际跑通时的细节和思考展开聊。2. 检索Retrieval环节的实战拆解你的知识库到底是怎么被“查”出来的检索是整个 RAG 里最核心、也是最容易翻车的地方。原因在于你如果查出来的片段本身就不对后面 Prompt 拼得再花哨、模型再聪明也只能基于错误材料作答属于“垃圾进垃圾出”。2.1 切分文本切分直接影响后续所有环节很多人上手 RAG第一个忽略的关键环节就是“切分”觉得无非就是把长文本按固定长度截断。这个想法害人不浅。我当时跑的第一版切分用的是最简单的按字符数硬切每 500 个字符切一段段与段之间重叠 50 个字符。结果检索效果惨不忍睹。为什么因为硬切会把一个完整的句子甚至一个完整的术语拦腰截断。比如一个句子的语义到后半段才展开但前半段里恰好含有用户问的关键词那这个片段即使被检索出来了也是残缺的模型很难基于它作答。正确的做法是使用递归字符文本切分器它本质上是一个“有层次的切分策略”先尝试用最粗的分隔符比如段落\n\n切如果切出来的块还是太大就用下一级分隔符比如句号、问号继续切直到块大小满足要求。这样做的好处是最大程度上保证每个 Chunk 是一个相对完整的语义单元。我后来在 Notebook 里手动调整了几个关键参数记录如下参数作用我的经验值chunk_size每个块的理想大小字符数300-800取决于文档类型和模型上下文窗口chunk_overlap相邻块之间的重叠部分通常为 chunk_size 的 10%-20%separators切分时按优先级使用的分隔符列表[\n\n, \n, 。, , , . , ]为什么一定要有 overlap因为很多情况下一个概念的完整表述可能恰好跨越两个 Chunk 的边界。有了重叠检索时无论是命中了前一段还是后一段都不至于丢失掉边界附近的上下文信息。这里分享一个我在实际使用中的判断技巧切分粒度需要根据你的问题类型做权衡。如果你的问题是“某某概念的定义是什么”那稍微偏小一点的 Chunk300-500字往往效果更好因为它是直接命中目标如果你的问题是“对比一下 A 方案和 B 方案的优劣势”那需要跨多个段落的上下文Chunk 就要偏大一点800-1000字甚至要考虑用摘要、父子分块这类进阶手段。Notebook 的好处在此刻就体现出来了——我可以把切分参数调一遍重新跑一遍马上对比检索结果来回几次就能找到最适合当前数据集的参数。2.2 向量化Embedding 的本质是把文本变成可计算的位置切分完下一步是把每个文本片段做向量化。这一步很多人直接调用现成的 Embedding API 就完事了但有一点值得想清楚Embedding 模型把文本映射到一个高维向量空间里语义相近的文本在这个空间里的距离也更近。这才是“语义检索”能成立的基础。我当时在 Notebook 里用的是 OpenAI 的text-embedding-3-small其实换别的也同理。调用逻辑非常简单from openai import OpenAI client OpenAI() texts [RAG 是检索增强生成, 向量数据库用于存储和检索向量] embeddings client.embeddings.create(modeltext-embedding-3-small, inputtexts) for i, data in enumerate(embeddings.data): print(f文本 {i} 的向量维度{len(data.embedding)})这里有一个我在学习过程中踩过的坑Embedding 模型必须保持前后一致。也就是说你建索引时用的是什么模型查询时也必须用同一个模型。如果你建索引时用text-embedding-3-small查询时换成了text-embedding-3-large那么就算两个模型名字很接近它们的向量空间分布也不一样检索效果会急剧下降。这个错误初看不明显因为代码不会报错只有检索质量异常差会让你感到蹊跷。另外如果你们是企业内网场景没法调用外部 API也可以用 HuggingFace 上的开源模型跑本地向量化。比如BAAI/bge-small-zh-v1.5或者moka-ai/m3e-small在中文场景下表现都不错。用开源模型的好处是数据不出域坏处是中文语义理解的上限通常比商业 API 差一截这个需要结合自己的数据体量来选。2.3 向量检索Top-K 怎么选Dense 和 Sparse 怎么配合查Retrieval这一步目标是“给定一个问题从向量库里找出最相关的 K 个 Chunk”。常见的做法是把用户问题用同一个 Embedding 模型转成向量然后在向量数据库里做相似度搜索返回最相似的 Top-K 条。Top-K 的选择是一个有意思的权衡。K 太小的缺点是容易漏——比如你的问题需要跨 3 个 Chunk 才能回答K2 就怎么都不够。K 太大的缺点是容易“噪声干扰”——检索结果里的第 8、第 10 条可能跟问题关联度很低这些低质量的片段混进 Prompt 里反而会干扰大模型做出正确的回答。我的经验是如果切的 Chunk 是 300-500 字Top-K 设置在 3-6 之间是一个比较稳妥的区间既保证有足够的参考信息又不至于给模型输入太多无关内容。不过“只靠向量相似度”其实有一个天然的盲区关键词的精确匹配。向量检索是语义层面的匹配它理解“苹果好吃”和“这种水果口感不错”意思相近但对于专有名词、编号、代码变量名这类必须逐字匹配的信息向量检索反而可能不够可靠。比如你去检索一段文档里某个函数的完整签名向量召回的结果可能包含了很多“函数”相关的泛泛而谈却没有把那个精确的函数定义捞回来。这就要提到混合检索的概念了。我跑的 Notebook 里后期有对比实验就是把向量检索Dense Retrieval和基于关键词的稀疏检索Sparse Retrieval比如 BM25结合起来最后用加权融合RRFReciprocal Rank Fusion对两组结果做合并排序。用公式解释 RRF 就是对每个文档它在不同检索结果中的排名取倒数把所有倒数加起来作为最终得分排名越靠前的文档融合后得分越高。我自己的体会是如果你们的知识库以技术文档、产品手册、代码注释为主强烈建议在向量检索之上叠加一层 BM25。加和不加在有精确术语的查询上效果差距很明显。纯粹的向量检索更适合处理“用大白话问专业问题”的场景比如“文档里提到了哪些处理并发的手段”这种问题用关键词可能很难覆盖全。2.4 关键实操相似度阈值与打分排序的经验值在 Notebook 里我习惯把每次检索出来的结果片段文本 相似度分值都打印出来肉眼检查一遍。这一步看似笨拙却帮我建立起了对“什么算相关”的直觉。当我打印出相似度分数时经常会看到排第一的片段得分 0.82排第二的 0.78这两个可以认为是“比较稳的相关结果”到第 5 名以后分数可能就只有 0.6 甚至更低这时候的内容就很容易跟问题跑偏了。所以后来我在自己的代码里加了一个简单的硬性阈值相似度低于 0.55 的 Chunk 直接过滤掉不回传给大模型。这个阈值当然不是通用的而是跟你选的 Embedding 模型强相关不同模型的分数分布完全不一样。关键是你要建立“用自己的模型在自有数据上跑出来的分数分布”这个基线。还有一个小技巧在相似度计算方式上大部分向量数据库默认返回的是余弦相似度但如果你用的是某个中文专用 Embedding 模型它训练时可能推荐的是内积或者 L2 距离这个一定要看模型的文档说明。选错了距离度量分数分布会变怪但更麻烦的是你可能会错误地调整相似度阈值。这一阶段的实际体会是检索质量决定了 RAG 的上限生成质量只是逼近这个上限。后面 Prompt 写得再精妙也无法弥补检索到的片段就是不对的缺陷。所以在时间分配上建议大家把至少一半的调试精力花在检索环节别急着去调 Prompt。3. 增强Augmented环节的实战拆解上下文是怎么“补”给模型的检索完拿到一堆相关片段下一步并不是把它们直接扔给大模型而是要做一个“组装”动作。这个环节在 RAG 论文里叫 Augmented中文可以理解为“增强”——把原始问题和检索到的片段融合成一条更有信息量的指令。3.1 怎么把检索结果拼装成有效的 Prompt很多人第一次写 RAG Prompt就是一句话“请根据以下资料回答问题{context}。问题{question}”。跑通是能跑通但效果往往很一般。因为模型缺少足够的“行为约束”它有可能会脑补出资料里没有的信息或者对资料中的内容过度发挥。我后来在 Notebook 里用的 Prompt 模板大概是这样的你是一个知识库问答助手。 请仅基于以下资料片段回答问题。如果资料中没有足够信息请直接回答“根据现有资料无法回答”。 资料片段 {context} 用户问题 {question}这里面有两个关键设计值得展开说一下“仅基于以下资料”这个约束。这一句话至关重要它告诉模型你的知识背景已经被限制了不要尝试回忆训练数据里的内容只需要看上下文里有什么。这能在很大程度上抑制“幻觉”问题当然不是百分之百但比完全没有约束要可靠得多。“没有足够信息就坦承不知道”这个兜底选项。如果检索到的片段确实跟问题不相关模型有权利说“我不知道”而不是强行生成一个看似合理但实际错误的答案。对生产级知识库系统来说“正确说不懂”比“自信地胡说”要重要得多。把检索结果填充到{context}里时我建议加上来源编号比如用 [1]、[2]、[3] 这样的标号对应每个片段并在 Prompt 里要求模型在引用某个片段的信息时标注来源编号。这样做有两个好处一是用户可以看到答案是参考了哪几段资料溯源更方便二是模型在标注来源的过程中会更倾向于严格贴近对应片段的内容间接提升答案的准确性。3.2 引用片段要不要、怎么给模型关于引用业内有一个常见辩论是把检索到的 Top-K 个片段全部拼在 Prompt 里还是只挑选其中最相关的部分我早期的 Notebook 是“全给”策略检索出 6 个片段全部塞进上下文每个片段前面标注 [1] 到 [6]。但很快我发现当检索质量不完美时这 6 个片段里总有一两个跟问题只是“沾亲带故”。模型面对这些无关片段时有时候会强行把它们编织进答案里导致答案变得啰嗦甚至跑偏。后来我调整了一下改成两段式筛选先用向量检索取回 Top-10 候选。再用一条轻量级的规则或者模型重新精排只保留分数最高的 Top-4或者按相似度阈值过滤掉明显不相关的片段。这种做法的本质是“先生成候选再二次筛选”效果比我之前“一次性 Top-6 全塞进去”要好不少。代价是增加了一步调用的延迟但对于回答质量要求高的知识库场景来说这个取舍非常划算。3.3 上下文窗口不够用怎么办滑动窗口和摘要融合做大模型应用的人绕不开上下文窗口的物理限制。如果知识库里的内容特别长比如一个 20 页的产品手册你很难把整本书都塞进 Prompt 里。即使塞得下大模型也会被海量无关信息干扰注意力被稀释。解决思路有两个方向我在 Notebook 里各跑了一遍滑动窗口切分前面讲的文本切分本质上就是为了应对这个问题。把一个长文本切成多个 Chunk每次只取其中 Top-K 个最相关的就是最朴素有效的窗口方案。摘要融合Map-Reduce如果问题需要理解文档的整体结构或跨多个章节的综合信息只靠局部 Chunk 是不够的。Map-Reduce 的做法是先把每章或每个大段落让模型各生成一段摘要再把所有摘要汇总成一个全局摘要把全局摘要和必要的局部 Chunk 一起作为上下文输入。代价是理解更全面、更耗时还会丢失一些具体细节。我当时遇到的一个场景是用户问“这个产品的故障排查步骤都能怎么走”但单个 Chunk 只覆盖了某一个具体故障的排查步骤根本没法形成整体方案。后来我用了摘要融合先生成各章摘要再让模型结合摘要和几个命中的局部 Chunk 综合回答效果才像样。“补”这个环节很多人以为拖个模板就行其实它是 RAG 链路里最体现工程经验的地方之一。你给出的上下文长什么样、以什么顺序排列、包含哪些约束都会直接影响最终答案的质量。4. 生成Generation环节的实战拆解别让输出环节拖垮整个链路当 Prompt 组装好后最后一步就是交给大模型生成。这个环节看似只是“调一个接口”但其实有不少细节值得琢磨。从我的经验看生成阶段的问题主要来自三个方面参数设置不合理、模型约束不到位、输出后处理缺失。4.1 生成前要确定的几个关键参数调用大模型时有四个参数跟 RAG 场景强相关temperature、top_p、max_tokens和presence_penalty部分 API 支持。我的建议是在知识库问答场景下温度要调低。temperature控制随机性取 0-1 之间的值。对 RAG 场景我一般设成 0.1 或 0.2甚至 0。因为我们希望模型尽量忠实于检索到的资料不需要太多创造性发挥。设太高比如 0.7 以上模型很可能会在资料基础上“添油加醋”产生幻觉。top_p核采样与温度类似。实践中一般跟 temperature 一起调我习惯保持默认 0.9 左右或者干脆设为 1只靠 temperature 控制。max_tokens控制生成长度。要结合你预期的答案长度来设太短会被截断太长会增加延迟和成本。presence_penalty控制话题重复度。在知识库问答里一般设 0 就好不需要模型发散新话题。我见过不少初学者包括我自己早期在 RAG 场景里把 temperature 调到 0.7模型生成时经常跑偏到“我知道你想问这个但是让我先给你介绍一下相关的背景知识……”这种无意义的开头。设置低温度是 RAG 最基本的一条经验。4.2 怎么让模型“不瞎编”提示词约束和事实校验除了调参数Prompt 层面的约束也非常重要。我习惯在 Prompt 里同时加入三个“防御性”设计格式约束明确要求“直接回答问题不要输出多余解释”“不要提及‘根据资料显示’这类客套话”。因为模型如果输出了“根据资料显示”不仅在引用格式上不好看还容易把它后续生成的推测也包装成“资料显示”的权威口吻。态度约束明确要求“在没有明确证据的情况下不要做推测”“对信息不足的问题说不知道”。事实校验可选如果你们的场景对事实准确性要求极高可以在第一次生成之后再让模型对答案里的每个核心陈述回到原始资料片段里找依据找得到就保留找不到就删掉或者标注为推断。这相当于加了一层“自我质检”。在 Notebook 里可以很轻松地用两个单元格实现第一个生成第二个用一条校验 Prompt 二次处理。有一种情况值得注意大模型可能会“过度依赖资料”比如资料里有一句“苹果是一种水果”用户问“苹果是什么”模型可能会把资料原文完整复制出来而不是组织成更自然的语言。这在技术文档问答里问题不大但在客户服务类的场景里就会显得生硬。可以接受的折中方案是Prompt 里加一句“用自己的话组织语言但不得偏离资料内容”这看起来简单实际能明显改善回答的可读性。4.3 常见生成质量问题与排查思路我在跑通 Notebook 后整理了一张排查对照表分享给大家这张表在后续实际项目中帮了我很多现象可能原因排查方向回答中出现资料里没有的信息temperature 过高 / 检索内容不够相关 / Prompt 约束不足降低 temperature检查检索 Top-K 结果的相关性强化“仅基于资料回答”的 Prompt 约束回答过于简短信息量不足max_tokens 设置过小 / Top-K 太小 / Chunk 太碎调大 max_tokens增加 Top-K调整切分参数增大 Chunk 大小回答答非所问检索出来的片段本身不相关检查 Embedding 模型是否一致检查切分边界尝试混合检索回答风格生硬像在念资料缺少“用自己的话组织”约束 / 模型能力有限Prompt 里加入表达方式要求考虑换更强的生成模型回答引用了不存在的来源编号模型幻觉导致生成了错误的 [1][2] 标记在 Prompt 里明确“只能引用标记为 [1] 到 [K] 的资料片段”生成后程序化校验编号合法性这套排查表的价值在于你不用一遇到生成质量差就盲目去调 Prompt 或者换模型而是先判断问题出在“生成”这个环节还是前面的“检索”环节。判断方法很简单把中间检索到的片段打印出来自己读一遍如果片段都不对那后面生成再怎么高端也救不回来。5. RAG 效果怎么衡量知识库指标拆解与实测方法把链路跑通后下一个自然而然的问题就是我的 RAG 到底做得好不好这个问题看着简单实际挺棘手。很多人——包括当时的我——会陷入一种“好像还行”的模糊感觉里。但做了几个测试问题之后才发现不同问题的效果参差不齐却说不清楚到底哪里差了。这就必须回到指标上来。5.1 你以为好的 RAG 到底是什么样子好的 RAG不是“回答得漂亮”而是“回答得准确、有据可依”。我对知识库 RAG 的效果判断一般从三个维度出发回答的忠实度Faithfulness答案里的每一个关键论断是否能在检索到的资料片段里找到支持依据。不能凭空捏造。回答的相关性Relevance答案是否准确回应了用户的问题而不是答非所问或者只沾了个边。检索的完整性Recall回答这个问题的必要信息是否都被检索到并放进了上下文。这对应的是检索环节的召回率。这三个维度是层层递进的。如果你检索出来的片段不完整哪怕生成得再流畅也不可能覆盖到正确答案这是第一条链路的问题。如果你检索到了但生成时没用上那就是生成环节的忠实度问题。5.2 指标背后的两层检索质量与生成质量知识库 RAG 的指标本质上是两个评价对象的指标检索质量和生成质量。检索质量层面核心指标是召回率RecallK和精确率PrecisionK。它们的含义是针对一个标注好的测试问题我们事先知道答案应该来自哪几个文档片段然后跑一遍检索看看 Top-K 结果里是否包含这些“正确答案片段”。召回率是“正确答案被捞回来的比例”精确率是“捞回来的结果里有多少是对的”。RAG 场景里更看重召回率一些因为如果正确的片段根本没进上下文后面生成环节再神也回答不了。生成质量层面核心指标是忠实度Faithfulness和答案相关性Answer Relevance现在也有直接用大模型做裁判来打分的做法。这里要吐槽一个很多人容易忽略的点指标不是只看一个数就行要让指标可解释。当时我在 Notebook 里加载了几个测试问答题集跑完后没有只看平均分而是逐个查看“未通过”的样本发现有一类问题特别容易挂当用户的问题包含精确的数字或型号时比如“X 型号的待机功耗是多少”向量检索很容易被语义近义词带偏召回不到那个精确型号。这个发现直接推动我去实验了混合检索。指标的价值在于定位问题而不只是打分。5.3 一套可落地的评测流程如果你也想快速评估自己的 RAG 系统我分享一个我在 Notebook 里实现的轻量评测流程不需要引入复杂的评测框架准备测试集整理 20-50 个真实高频问题覆盖简单查询、复杂推理、精确匹配等不同类型。每个问题人工标出在知识库中对应的标准答案片段或参考文档范围。评估检索质量写一个循环对每个问题做向量检索统计 Top-5 结果里包含标准片段的个数算出 Recall5。评估生成质量写一个循环用组装好的 Prompt 让大模型生成答案然后人工或者再用一条“裁判 Prompt”对答案打分主要看是否忠实于资料、是否相关。分类汇总把每个问题的各项打分结果放在一个 DataFrame 里按问题类型做分组汇总。这个过程在 Notebook 里跑起来非常顺滑而且可以反复迭代。每次改完切分参数、Embedding 或者 Prompt 模板就重跑一遍肉眼可见评分曲线的变化。6. 把 Notebook 从“能跑”升级到“能用”进阶方向与个人体会跑通一套基础 RAG Notebook 是一个里程碑但离“能用”还有一段距离。随着对链路理解的加深我开始关注 RAG 生态里的各种进阶方向比如 Graph RAG、Agentic RAG以及生产环境里的那些“脏活累活”。这节我聊点实在的讲讲我对这些概念的理解以及实际跑代码时积累的避坑经验。6.1 Graph RAG 与 Agentic RAG 到底是什么Graph RAG基于知识图谱的 RAG。传统 RAG 把文档切块后块与块之间是相互独立的向量空间里它们只是位置不同。但真实世界的知识是有关联的比如一份公司制度文档里“请假流程”和“考勤管理”和“加班补偿”其实是互相引用的概念。Graph RAG 的思路是先把文档里的实体比如“请假”“考勤”和关系比如“属于”“关联”抽取出来构建一个知识图谱检索时不仅做向量相似度匹配还能沿着图谱结构展开“一跳、两跳”的关联查询。我自己的理解Graph RAG 不是要替代向量检索而是补充关联关系层面的召回能力。当问题涉及“A 影响了哪些环节”这种多跳关联时传统 RAG 可能只能召回提到 A 的局部片段而 Graph RAG 能顺着关系把 A 触达的其他节点一起拉回来。代价是构建图谱的成本很高需要调用 LLM 做实体抽取、关系抽取而且图谱质量直接影响检索效果。Agentic RAG智能体式 RAG。如果说传统 RAG 是一条固定的流水线查-补-写Agentic RAG 就是把这套流程交给了 AI Agent 来自主决策。Agent 可以根据用户问题决定是否需要查询知识库、查询哪部分知识库、用一次查询还是多次查询、如果第一次查询效果不好是否需要改写问题再查一次。它的本质是把 RAG 从“一套固定流程”升级为“一套动态策略”。理解 Agentic RAG 的前提是先把基础 RAG 的每一步吃透——这个前提恰恰是跑通基础 Notebook 带给我们的最大价值。我在实际体验 Agentic RAG 时最大的感受是能力确实更强但调试复杂度也上了一个量级。固定的流程出问题出错点就那么几个Agent 自主决策时你很难判断它在哪个决策节点上偏了。所以我的建议是先别急着上 Agent先把基础 RAG 的效果做到稳定再逐步引入动态决策能力。6.2 从简单 RAG 到生产级 RAG 要做哪些事Notebook 里跑通的链路是“可用”而非“生产可用”。从 Notebook 里的实验代码到能线上服务真实用户的知识库系统中间还隔着很多工程问题。我根据自己的项目经验列几个最常见的差距索引更新策略Notebook 里是一股脑把文档全部灌进向量库但生产环境里文档是持续更新的。你需要考虑增量索引新增文档怎么进来、过期文档怎么删除、更新文档怎么替换。如果文档更新频繁向量库里的旧向量清理不及时检索质量会持续劣化。多用户与权限隔离不同角色看到的文档范围可能不同。这要求检索阶段就要根据用户身份做范围过滤而不是所有用户共用同一个向量库。缓存设计高频问题的高质量回答应该加缓存否则每次都走完整链路延迟和成本都吃不消。监控与回滚线上的 RAG 服务需要记录每次检索和生成的日志定期抽取样本评估效果一旦指标下滑能定位到是切分、Embedding 还是 Prompt 变化导致的。很多团队上线 RAG 之后没有这套监控出了问题基本靠用户反馈这是拖延战。多路召回与精排之前提到过混合检索生产环境中更复杂可能还会加一些规则过滤比如时间过滤、标签过滤再经过精排模型重新排序。Notebook 里可以用简单的 RRF 融合线上则可以引入更大的重排模型比如 bge-reranker。6.3 我在跑这套 Notebook 时踩过的五个坑最后分享几个我在实际跑通和调试过程中踩过的坑这些属于“代码能跑但效果不对”的类型不亲自踩一遍很难意识到坑一Embedding 模型不一致。前面提过建索引和查询用的 Embedding 模型必须一致。我曾经在两个不同的 Notebook 单元格里一个用的 OpenAI Embedding另一个用的是本地模型结果检索基本是“玄学召见”查出来的结果跟问题一点不搭。那次排查花了很长时间最终打印出两个向量维度才发现不一致。坑二切分时把代码块和表格切碎了。如果知识库里包含 Markdown 格式的文档里面经常有代码块、表格这类结构化内容。如果按普通文本切分经常会把一段代码从中间切开或者把一个表格的行散到不同 Chunk 里。后来我做了自定义切分逻辑代码块内部尽量整体保留表格按行切但每一行要带上表头信息。这类自定义规则对检索质量提升极其明显。坑三Prompt 里给资料但没有给“边界”。早期我在 Prompt 里放了{context}后没有明确告诉模型这个 context 的边界在哪里。模型有时会把资料里的内容和自己训练时学到的东西混在一起。后来我改成用明确的 XML 标签包裹资料内容比如context/context同时告诉模型“资料内容在两个标签之间超出标签的信息不得使用”。这个做法看似简单实际效果提升很明显。坑四Top-K 里混进了太多低分片段。我之前觉得 K 越大越好结果 K8 时检索结果中的第 6、7、8 名都是低分噪声。这些噪声进入 Prompt 后经常把答案带偏。后来我加了两道防线一是相似度阈值过滤低于阈值直接丢弃二是从 8 个候选里再精排挑出前 4 个。这两道防线加上之后回答质量稳定了不少。坑五对“空检索结果”没有预案。如果用户问的问题完全在知识库范围之外检索结果可能是空的或者相似度分数极低。早期我的 Notebook 在这种情况下仍然会把一堆不相关的片段拼进 Prompt 里让模型硬答。模型只能硬着头皮从无关内容里“强行提炼答案”效果当然是灾难性的。后来我加了判断逻辑如果最高相似度低于阈值就不调用大模型而是直接返回“未找到相关资料”。让 RAG 学会说“不知道”是让它变可靠的关键一步。总的来说跑通这套 Notebook 让我受益最大的不是掌握了某个具体的框架调用而是建立起对 RAG 整条流水线的“体感”。每一个环节的输入输出、常见故障、调优方向都在代码的调试过程中变成了肌肉记忆。如果你也想真正搞懂 RAG 在做什么我的建议很简单不要只在文档里看概念拿起一套 Notebook 实测一下尤其是要动手调一调切分参数、换一换 Embedding、观察一下检索分数的分布这些“动手”带来的认知比任何架构图都来得深刻。