这个仓库名在 RAG 圈子里最近讨论度很高,我第一眼看到 NirDiamant/RAG_Techniques 的时候,其实有点意外——一个开源仓库能把 RAG 从入门到进阶的路径整理得这么系统,确实少见。它不是那种丢一堆论文链接让你自己啃的收藏夹,也不是只给一个 Demo 就完事的玩具项目,而是把 Naive RAG、Advanced RAG、模块化 RAG、Graph RAG、Agentic RAG 这一整套演进路线,用代码、流程图、实践建议和常见坑位串成了一条完整学习链。如果你正准备系统学 RAG、要做技术选型、或者马上要准备 RAG 相关的面试,这个仓库值得花时间好好过一遍。
我在实际把它跑通、改造成自己的知识库问答系统的过程中,踩了不少坑,也总结了一些自己的经验。这篇就结合我对 RAG_Techniques 的理解和实际落地经历,把 RAG 检索增强生成的核心原理、实战流程、进阶方案、框架选型和评估方法一次性讲清楚。
1. RAG_Techniques到底在讲什么:一次技术全景式拆解
1.1 项目定位:从Naive RAG到Agentic RAG的完整演进路径
NirDiamant/RAG_Techniques 这个仓库的核心定位,是提供一份“可执行”的 RAG 技术路线图。它不满足于给你一个最简单的向量检索问答 Demo,而是把 RAG 技术按照复杂度分成了几个层次:第一层是教科书式的 Naive RAG,也就是索引、检索、生成三步走;第二层是 Advanced RAG,涉及查询重写、HyDE、重排序、上下文压缩等技术;第三层是模块化设计,把 Retriever、Memory、Router 等模块组合成灵活流水线;再往上就是 Graph RAG、Agentic RAG 这种带图结构和智能决策的进阶形态。
这个分层设计非常符合我自己的实际感受。很多人一上来就追 Agentic RAG,但如果不理解基础 RAG 的局限——比如检索召回不准确、上下文窗口塞不下、幻觉没法抑制——你用 Agent 框架也只是把一个坏流程包装得更复杂。仓库把这几层路径按顺序排布,实际上是在帮你建立“先知道痛点,再上方案”的正确认知。
我读完这个仓库第一个感觉是:它比很多付费课程要实在。因为每个章节都有对应的代码实现和 Notion 风格的笔记,不是泛泛而谈。你可以直接 clone 下来跑,然后观察每一步输入输出到底发生了什么。
1.2 内容架构与学习路线:正确打开这个仓库的方式
这个仓库的内容组织方式值得单独夸一下。它的 README 就是一个完整的目录树,每个技术点都有对应的 .py 文件和笔记,章节之间有清晰的递进关系。我推荐的阅读顺序是:先跟着 Naive RAG 的代码把流程跑通,再去看 Advanced RAG 的优化点,然后重点研究 Graph RAG 和 Agentic RAG 的代码,最后再看评估部分——因为评估直接决定你前面做的优化到底有没有效。
仓库里有些细节特别加分。比如它在实现 Dense Vector Search 的时候,不只是调一个现成的向量数据库接口,而是会展示 embedding 模型的选择逻辑、相似度计算的底层实现、索引结构对检索效率的影响。这种“拆开来看内部”的写法,比单纯教你怎么调用 API 有价值得多。
如果你时间有限,我的建议是只精读三块:Advanced RAG 的优化手段、Graph RAG 的图谱构建代码、以及评估部分的测试集设计。这三块基本覆盖了 80% 的面试考点和实际落地难点。
2. 核心技术原理拆解:索引、检索、生成三块基石
2.1 向量化流程与文本切分的细节
RAG 的基础是“把文本变成向量再检索”。第一次跑通的人很容易忽略文本切分这个环节,觉得无非是按长度切开。但实际做下来,切分策略对检索效果的影响非常大。
我在仓库的代码基础上做过一组对比实验:同一份技术文档,分别用固定 500 字符切分、按段落切分、按语义切分三种方式建索引,检索同一组测试问题。结果按固定长度切分时,召回 Top5 里出现了大量跨主题的无关片段,因为很多句子被硬生生切断了;按段落切分效果稍好,但遇到超长段落时上下文又过载;最后用带 overlap 的滑动窗口切分,并且窗口大小控制在 300-500 token,检索质量才明显改观。
关于 chunk size 的选择,没有银弹。我一般会看两个指标:文档的平均段落长度,以及你用的 embedding 模型的最大输入 token。比如你选的是 bge-large-zh,最大输入是 512 token,那 chunk size 就不能超过这个值。另一个经验是 overlap 设置在 chunk_size 的 10%-15% 左右比较合理——太少了边界语义接不上,太多了索引冗余浪费存储。
向量化流程完整的链路是:文档加载、清洗(去页眉页脚、去噪声)、切分、embedding、写入向量库。很多人会忽略清洗这一步,实际生产环境里 PDF 解析出来的内容往往带很多乱码和重复字符,不洗直接向量化会让检索质量雪崩。
2.2 Dense Vector Search的检索原理与参数调优
Dense Vector Search 可以说是整个 RAG 的地基。它的核心思路是把 Query 和 Document 都映射到同一个语义向量空间,然后用向量距离度量相关性。仓库里对这块的讲解很细,包括常见距离函数的选择:余弦相似度、点积相似度、欧氏距离。
我自己的实践结论是:对短文本匹配、FAQ 场景,点积和余弦相似度表现差异不大;但如果你用了归一化后的 embedding,很多向量库内部默认用点积其实等价于余弦。真正影响检索效果的往往不是距离函数,而是“向量维度”和“索引策略”。维度越高,能表达的信息越丰富,但检索开销也越大,一般开源的中文 embedding 模型都是 768 或 1024 维,这个不用太纠结。
另一个调优重点是 top_k 的选择。很多初学同学直接把 top_k 设成 3,结果上下文不够,大模型答得很干。我建议先设 10-20,让召回更充分,然后用重排序模型压缩到 3-5 条高质量片段。RAG_Techniques 里也专门有 Reranking 相关的内容,这个思路本质上是“先宽进、再严出”,避免第一步检索就把正确答案漏掉。
在实际生产环境里,Dense Vector Search 不能只看向量相似度,最好结合元数据过滤。比如你检索的是多租户文档库,一定要先按租户 ID 过滤,再按向量相似度排序,否则跨租户的信息泄露会很严重。这是很容易被忽略的安全隐患。
2.3 生成环节的上下文注入与Prompt组织
检索只是手段,生成才是用户能感知到的结果。RAG 生成环节的核心问题只有一个:如何把检索回来的文本块,组织成让大模型可靠回答问题的上下文。
最简单的做法是把所有检索结果拼接成一段长文本塞进 system prompt 或 user prompt。但直接拼接有个问题:相关的内容可能被无关内容稀释,模型会被噪声带偏。仓库里给出的优化方向是“重写后注入”,也就是先让 LLM 对检索结果做去重、压缩、提取关键信息,再送进生成模块。这个做法实测下来能显著减少幻觉,代价是多一次模型调用,延迟会高一些。
Prompt 模板的细节也很关键。我会在模板里明确告诉模型:只能基于给定上下文回答,如果上下文没有提到相关内容,直接回答“我无法从提供的信息中找到答案”,不要编造。这个约束看似简单,实际是抑制幻觉最直接有效的手段。还有一个小技巧:在上下文段落前面加上来源标识,比如【来源3:数据安全法第二章】,模型回答时引用了哪个片段,你就能对应溯源。
3. 进阶技术实战:Graph RAG、Ontology RAG与Agentic RAG
3.1 Graph RAG的图检索逻辑与落地条件
Graph RAG 是最近热度一路走高的方向,核心思路是在纯文本向量化之外,额外构建知识图谱结构。它解决的核心痛点是:传统向量检索只关注“字面相似”和“语义相近”,但处理“多个实体之间的复杂关系”时,比如“A 公司收购了 B 公司,B 公司与 C 公司有专利纠纷,请问 A 公司是否面临专利风险”,向量检索往往答得很零散,而图结构可以把实体和关系的路径串联起来。
我在看 RAG_Techniques 的 Graph RAG 章节时,印象最深的是它把图谱构建流程拆得很清楚:先用 LLM 从文档里抽取实体和关系,写入图数据库(比如 Neo4j),然后采用社区检测算法把节点划分成不同的社区,再对每个社区生成摘要,最后在问答阶段结合社区摘要和局部检索结果回答。这套流程本质上是在做“先全局理解,再局部检索”。
但 Graph RAG 不是银弹,落地成本相当高。我的经验是:如果你的文档是强结构化的(比如企业规章制度、行业研报、法律条文),图结构的收益会很明显;但如果文档是松散的问答对话、聊天记录,强行抽图谱往往是浪费算力。另一个坑是实体抽取的准确性,LLM 抽出来的关系经常有一半是噪声,所以需要设计人工校验或规则过滤的环节,这里实际工作量比想象中大很多。
3.2 Ontology RAG:当图谱和本体遇到大模型
Ontology RAG 相比 Graph RAG 又往前走了一步。Graph RAG 构建的图往往是一个扁平的知识图谱——实体和关系都摆在节点和边上;Ontology RAG 则是在这个图之上引入了一套语义体系:比如“人”是“动物”的子类,“公司”有“创始人”属性,“收购”有“交易金额”属性。有了本体层,检索时就能借助类目体系做更精准的推理,也能约束 LLM 生成的内容不要偏离业务定义。
实际操作中,Ontology RAG 的价值主要体现在召回阶段。比如用户问“有哪些上市药企在研发肺癌靶向药”,如果没有本体层,向量检索可能只会召回“药企”或“靶向药”相关文档;如果本体里定义了“上市药企 ⊂ 药企”且“肺癌 ⊂ 实体瘤”,就可以先通过图谱路径找到候选集,再结合向量相似度排序,召回质量会显著提升。
不过 Ontology 的构建成本比 Graph 还高,因为它需要领域专家参与定义概念和关系。我自己的建议是:先建立最小的本体骨架(5-10 个核心概念、10 来个关系),跑通流程后再逐步扩展,不要一上来就建一个巨大无比的知识体系,否则光是维护都会累死人。
3.3 Agentic RAG:从固定流水线到自主决策
Agentic RAG 是今年最热的方向之一,相关热词里频繁出现“agentic rag”。它的本质变化是:从“固定流程”变成“自主决策”。传统 RAG 是“用户提问 -> 检索 -> 生成”,Agentic RAG 里,大模型变成一个 Agent,可以自己决定“这个问题要不要检索”、“是查向量库还是查图数据库”、“检索一次不够要不要再换个 Query 查一次”、“查到的内容不够连续要不要多跳几轮”。
仓库里对 Agentic RAG 的实现,是基于 ReAct 模式:Agent 先推理(Thought),再决定动作(Action),观察结果(Observation)后继续推理,直到能给出答案。这个过程中,Agent 可以自主选择调用不同的工具,比如向量数据库工具、搜索引擎工具、SQL 查询工具,甚至其他 Agent。
我在实际部署 Agentic RAG 时,最大的体会是:延迟和成本会直线上升。一个复杂的多跳问题,Agent 可能要来回调用五六次模型,用户体验会明显变差。所以我的建议是做一个“意图分流”:简单问题走快速 RAG 路径,只有复杂推理问题才路由到 Agentic RAG 流程。这样既保证了体验,又让复杂问题的准确率有提升。
4. 工程落地实操:框架选型、完整案例与RAG测评
4.1 RAG框架选型:LangChain、Spring AI怎么选
聊到 RAG 框架,绕不开 LangChain、LlamaIndex 这些 Python 生态,Java 后端则是 Spring AI 2.0 的 RAG 实例最近讨论度越来越高。怎么选,我的建议非常直接:如果你是 Python 技术栈,LangChain 生态最成熟、文档全、社区案例多,适合快速搭建原型;LlamaIndex 做索引和检索更灵活,适合对检索链路有深度定制需求的场景。如果你团队是 Java 技术栈,想保留 Spring 体系,那 Spring AI 2.0 是值得关注的方案,它在 Java 里提供了一套适配 RAG 的抽象和模板。
RAG_Techniques 里没有绑定某一特定框架,这反而是它的优点。它更多是用贴近原生的方式讲透每一步,所以无论你最后用 LangChain、LlamaIndex 还是 Spring AI,都能把里面的思想迁移过去。我自己在生产环境里其实是一个“混合姿势”:用 LangChain 做流程编排,但检索和重排序部分是用自定义代码实现的,因为 LangChain 封装得太高级,遇到性能问题不好排查,自己写反而更可控。
框架选型还有一个隐藏的坑:版本更新太快。LangChain 早期和现在的 API 差别巨大,很多网上的教程跑不通就是因为版本问题。我的建议是选一个长期维护的版本固定下来,别追新,除非你有明确需求。
4.2 从零实现一个RAG项目:配置与参数细节
这部分我直接把 RAG_Techniques 里给出的思路和我自己的实践结合起来,讲讲一个最小可用 RAG 项目的实现,重点看参数怎么写、为什么这么写。
第一步是项目环境准备。我用的是 Python 3.10,向量数据库选 Chroma(本地轻量、适合学习),Embedding 模型选 bge-base-zh-v1.5(中文效果好、MIT 协议可商用),LLM 用 OpenAI 兼容接口或本地部署的 Qwen。如果要用 Java 生态复现这个流程,Spring AI 2.0 的 RAG 示例里提供了 InMemoryVectorStore 和 OpenAiEmbeddingModel 的装配方式,思路完全一致,只是 API 风格不同。
第二步是文档加载与切分。仓库代码里用到了 LangChain 的 Document Loader 加载 PDF/Markdown,然后通过 RecursiveCharacterTextSplitter 切分。我实际的切分配置是:chunk_size=450,chunk_overlap=50,separators 按“\n\n、\n、。”的顺序,这样既能保住段落边界,又能适配中英文混排。
第三步是构建 embedding 索引。这里注意一个问题:文本切分和 embedding 必须保持同一个 tokenizer 口径,不能先按 450 字符切,然后又用 512 token 的模型去编码。另一个细节是向量库一定要开启持久化存储,否则重启就全部丢失,还会让你误以为是配置问题。
第四步是检索增强生成。代码如下:
# 核心检索生成链路示意 from langchain.vectorstores import Chroma from langchain.embeddings import HuggingFaceEmbeddings # 1. 初始化 embedding 模型 embedding = HuggingFaceEmbeddings(model_name="BAAI/bge-base-zh-v1.5") # 2. 从磁盘加载持久化向量库 vectorstore = Chroma( persist_directory="./data/chroma_db", embedding_function=embedding ) # 3. 检索 TopK 候选 retriever = vectorstore.as_retriever( search_type="similarity", search_kwargs={"k": 10} ) docs = retriever.get_relevant_documents("什么是RAG检索增强生成?") # 4. 送入 LLM 生成回答(此处省略 Prompt 模板构造细节) answer = llm.invoke(build_prompt(query, docs))实际生产里,我会在第三步和第四步之间插入一个重排序过程:用 bge-reranker-base 给 Top10 候选重打分,取 Top3 作为最终上下文。这个操作能让最终回答质量提升一个档次,强烈建议有条件的都加上。
4.3 RAG测评怎么做:评估指标、测试集构建与方案设计
RAG 测评是一个容易被忽视、但实际上决定项目天花板的工作。很多人把项目上线后才发现效果差,就是因为缺少一套客观的评测流程。RAG_Techniques 里对评估部分的整理非常实用,它给出了两个层面:分模块评估和端到端评估。
分模块评估主要是看检索器的召回质量。我用的是 Recall@K 和 MRR 两个指标:对每个测试问题,人工标注出哪些文档片段是正确答案所在;检索器返回 TopK 后,看标注片段有没有被召回、排在第几位。这个环节最容易暴露切分和 embedding 的问题。比如我遇到过 Recall@5 只有 50% 的案例,排查后发现问题出在 chunk_size 太大,正确答案被淹没在一大段无关上下文里。
端到端评估更贴近用户感受。现在比较常用的是 RAGAS 那一套指标,包括 Faithfulness(回答是否忠于给定上下文)、Answer Relevancy(回答是否贴合问题)、Context Precision(检索上下文是否精确命中)等。这些指标如果用 LLM 来打分,成本可控,也能自动化跑回归。我自己的习惯是维护一个 50-100 条问题的测试集,涵盖简单事实问答、多文档综合推理、否定问题、时效性问题等场景,每次改完检索策略或 Prompt 就自动跑一遍回归。
还要多说一句:测评方案不是一次性的。随着索引数据的更新、业务问题的变化,测试集一定要持续扩充,否则“优化过头导致老问题回归”这种情况会反复出现。
5. 常见问题排查与避坑实录
5.1 检索召回差、答非所问怎么排查
在实际跑 RAG 项目时,最常见的现象是“检索召回差”导致大模型胡说八道。我整理了一套排查路径,也是面试时经常会问到的“RAG 效果不好怎么办”的标准回答思路。
首先,检查文档切分是否合理。你可以随便取几条测试 query,把所有检索结果打印出来,看看召回的前几条跟问题是否语义相关。如果相关但答案不全,是切分太碎或 overlap 不够;如果完全不相关,要检查是不是 embedding 模型选错了。中文场景用英文 embedding 模型的效果会非常差,这一点很多人容易踩。其次,检查查询本身是否需要改写。用户口语化的提问和文档里的规范表述往往差异很大,这时候可以做一次查询改写(Query Rewrite),比如把“去年营收多少”改写成“2024年度营业收入金额”,召回效果立竿见影。
答非所问还有一个常见来源:多文档信息冲突。比如文档 A 说某个接口超时时间是 3 秒,文档 B 说是 5 秒,向量检索可能把两段都召回了,模型就会很纠结。这种时候我会在 Prompt 里要求模型标注信息来源,同时在后处理逻辑里做一个置信度判断,冲突严重时直接提示用户“资料库中存在不一致的信息”。
5.2 多文档、复杂推理场景的进阶坑
当 RAG 项目从 Demo 走向生产,会面对复杂的多文档场景。我实际遇到的坑主要有三个:上下文过长导致模型注意力稀释、跨文档信息拼接困难、以及实时更新数据的索引失效。
上下文过长的问题在长文档场景特别明显。我的解决办法是引入“摘要层”:对超长文档先生成一个分层摘要,检索时先查摘要层,定位到相关章节后再深入原文检索。这样既控制了上下文长度,又保证了关键信息不丢失。跨文档拼接困难是 Graph RAG 的典型适用场景,需要把分布在多份文档里的实体关系串成图谱,再把图谱路径作为上下文送给 LLM,全程要设计多跳检索。
还有一个坑:索引更新。生产环境里文档会持续新增和修改,很多人只做增量写入,忘了处理删除和修改。结果旧版本的文档残留在向量库里,检索时频繁召回过期信息。我的建议是给每条数据打上文档版本号和更新时间,检索时强制过滤过期版本,同时建一个离线定时任务做索引一致性校验。
5.3 给新手的实战建议
最后给准备入坑 RAG 的同学几个实战建议:第一,一定要先跑通一个最小闭环,再谈优化。哪怕只是小规模文档、本地向量库、一个开源 LLM,都比你对着论文冥想有效。第二,优化检索永远比调 Prompt 的收益更大。RAG 的上限由检索决定,模型只是把找到的内容组织成答案;如果你发现回答质量差,别急着换更大的模型,先看看召回结果是否满意。第三,重视评估,没有评测的优化就是打空气。哪怕没人要求,也要自己建个 30 条问题的小测试集,每次改动都跑一遍,你会明显感受到有数据支撑和凭感觉优化之间的差别。
我个人在把这个仓库里的技术消化完、落到自己的知识库项目以后,最大的体会是:RAG 不是一种单一技术,而是一套系统工程,从切分、向量化、索引、检索、重排、生成到评估,每个环节都有优化空间,而且它们互相影响。如果你刚开始学 RAG,建议认真跟着 RAG_Techniques 的章节走一遍代码,不要跳步;如果你已经做过基础 RAG,可以重点研究 Graph RAG 和 Agentic RAG 的章节,它们代表的是这个领域未来的竞争力。