ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RAG入门实践:从本地知识库到GraphRAG与Agentic RAG

RAG入门实践:从本地知识库到GraphRAG与Agentic RAG RAG这几年火得一塌糊涂尤其是“RAG入门”这个词几乎成了LLM应用的标配起点。这篇笔记是我对20250715那期wow-rag入门项目的完整复盘把这几天梳理的东西沉淀下来RAG是什么、核心链路怎么拆、本地怎么落地、以及从朴素RAG向GraphRAG、Agentic RAG进阶的路线图。如果你正想搭一个属于自己的RAG知识库或者已经开始动手但被各种细节卡住这篇应该能帮你少走不少弯路。我会把项目里涉及的关键技术点全部展开讲包括文本切分、Embedding选型、检索策略、评估方法最后附一段可以直接跑通的本地RAG代码。文章里所有实操内容都基于常见实践补充工具链选型也尽量偏保守可靠争取看完就能上手。1. RAG入门第一课它到底解决什么问题1.1 “大模型什么都知道”是个错觉先聊一个基础问题我们为什么需要RAG很多刚接触LLM的朋友会天然地认为大模型训练了那么多数据什么知识都应该有了喂个Prompt它就能答上来。但实际上你随便问一个内部流程、产品手册、特定行业规范的问题大模型的回答经常是错的而且错得很流畅。这背后有几个绕不开的硬伤知识截止日期模型训练一次成本极高不可能天天更新所以它掌握的知识永远有“保质期”。私有数据不可见再强的通用模型也没见过你公司内部的文档、你手里的实验记录、你自己整理的语料。事实性幻觉模型本质是在做概率预测遇到不知道的内容它会“编一个最像样的答案”而不是老老实实说不知道。RAG的解决思路也很朴素——别让模型凭空回答先给它看相关的资料再让它基于资料回答。这个过程有点像开卷考试模型依然是那个“聪明学生”但你得先帮它翻到课本的正确页数它才能写出正确答案。微软把RAG称为“给LLM装上外部记忆”这个比喻很准确。RAG的全称是Retrieval-Augmented Generation翻译过来就是检索增强生成。流程上就是把用户的问题先拿去检索一个知识库把最相关的片段捞出来然后连同问题一起塞给大模型做生成。这样一来模型的答案有了事实依据幻觉率会显著下降知识时效性和私有数据的问题也一并解决了。1.2 RAG里最容易被忽略的“四段式”工作流RAG听起来简单但真正落地的时候你会发现它不是一个“输入文档→输出答案”的黑盒而是由四个相对独立的环节组成的流水线索引阶段把原始文档切分成小块chunk每块向量化存入向量数据库。检索阶段把用户问题向量化在库里做相似度搜索捞出Top-K个候选片段。重排与过滤对候选片段做精排去掉冗余和噪声挑出真正有用的部分。生成阶段把检索结果和用户问题组装成Prompt交给LLM生成最终答案。很多初学者会把精力全放在第四步Prompt工程上结果发现效果不好就开始怀疑大模型不给力。实际上RAG的效果瓶颈往往出在前三步——文档没切好、向量化质量差、检索结果不准后面再怎么调Prompt都是事倍功半。这也是我在wow-rag项目里体会最深的一点RAG真正的难点不是“怎么调用大模型”而是“怎么把知识库整理到机器能准确找到的程度”。接下来的几个章节我会把每一步的关键细节拆开讲。1.3 本地能不能玩RAG资源门槛比你想的低项目开始前很多人会问做RAG是不是必须要高性能显卡要不要调用付费API答案取决于你选哪条路。RAG的完整链路里Embedding模型和向量检索这对组合并不吃显存普通CPU机器也能跑起来真正吃资源的是生成阶段的LLM。所以本地玩法通常有两种全本地方案用Ollama跑一个小尺寸LLM如Qwen2.5 7B、Llama 3.1 8B加上BGE或nomic的Embedding模型整条链路完全离线。适合个人笔记、小团队知识库隐私性也最好。混合方案Embedding和向量检索在本地做生成阶段调用云端API。适合想要更高答案质量、但又不希望把文档内容完全交给第三方的场景。wow-rag项目走的是全本地方案我的实际感受是只要语料规模在几万篇以内、文档不是超长PDF一台16G内存的笔记本完全够用。先跑通全本地理解每个环节之后再往更重的架构上走是不踩坑的正确路径。2. 核心技术拆解从文档到检索的完整链路2.1 文本切分chunk的颗粒度决定了RAG的上限索引阶段最重要、最容易被忽视的步骤是文本切分chunking。我见过不少新手直接把整本PDF喂给Embedding模型结果向量库里塞满了“四不像”的长向量检索时捞出来的是一大段跨主题的内容——这本质上等于没切。为什么切分这么重要因为Embedding模型处理的文本长度是有限的绝大多数模型的序列上限在512到2048个token之间。超出模型上限的文本会被截断丢了语义比这个短太狠又容易让每个片段缺乏上下文。切分策略本质上是在“语义完整性”和“检索精准度”之间找平衡。实践中常用的切分方式有几种固定长度切分按固定字符数切割配合一定比例的重叠overlap。这是最省事的方案写代码也最简单。但缺点明显——容易把段落、句子拦腰截断导致语义割裂。比如一段讨论“模型训练”的文字被切成两半前一半讲数据清洗后一半讲损失函数检索时两边都不完整。结构感知切分按Markdown标题、章节、段落来切这是处理结构化文档技术文档、博客、Wiki最推荐的方式。先按文档大纲拆出章节再在章节内按段落切分能够最大程度保留语义结构。LangChain里的MarkdownHeaderTextSplitter、RecursiveCharacterTextSplitter都是干这个的。语义切分利用Embedding计算段落间的语义相似度相似度高就合并低就切开。这种方式效果最好但计算量也最大。像LlamaIndex里的SemanticSplitterNodeParser就是典型实现适合对质量要求高、语料量不太大的场景。我的经验是先用结构感知切分打底再补充固定长度和重叠作为兜底。chunk大小可以从500到1000字符之间试起overlap设置在10%到20%。这个参数直接决定后续检索hit rate值得多花时间调。2.2 Embedding把语义变成向量的是什么模型切完文档下一步是把每个chunk转成向量。Embedding模型做的事情就是把一段文字映射到高维向量空间——语义相近的文本在向量空间里距离也近。选Embedding模型有几个硬指标要关注向量维度常见的有384维nomic-embed-text、768维bge-large、1024维bge-m3。维度越高表达能力越强但存储和计算开销也越大。上下文长度老牌模型可能只有512 token新模型普遍支持到1024甚至8192。中文支持如果你的知识库以中文为主首选中文语料优化过的模型。我实际测试过几个常见模型简单总结如下模型维度上下文长度中文表现适用场景bge-m310248192优秀中长文本、混合语言知识库bge-small-zh512512良好轻量场景、CPU推理nomic-embed-text7688192中等Ollama生态集成方便text2vec-large-chinese1024512优秀中文短文本本地部署时Ollama上直接能拉bge-m3或nomic-embed-text集成最省事如果想追求更高中文精度可以单独用FlagEmbedding跑bge系列。坦白说Embedding模型之间的差距在实际RAG效果上通常比LLM之间的差距更明显——因为Embedding决定了你能把哪些内容检索出来而LLM只决定拿到这些内容后怎么组织答案。2.3 向量数据库与检索策略别迷信近似搜索向量数据库是整个RAG的“存储层”。市面上选项很多从Chroma、Qdrant、Milvus到Elasticsearch自带的向量检索能力各有侧重。如果你只是做本地学习或小规模知识库Chroma是我优先推荐的——它够轻量一条pip命令装好代码里直接当普通库用不需要额外起服务非常适合跑通流程。等到数据量上来了再考虑Qdrant这种以服务方式运行的方案或者视频里的Milvus轻量版Milvus Lite。另一个容易被忽视的点是不要只做纯向量检索。向量相似度适合捕捉语义层面的相近但它对“关键词精确匹配”反而钝感。比如用户搜“PID控制”如果库里只索引了“比例积分微分控制”向量检索可能捞不到——但BM25这类关键词检索却能精确命中。所以实战里做混合检索是非常有必要的向量检索和BM25各跑一遍拿到两路候选再合并去重。合并以后还有一个关键步骤——重排序Rerank。重排序通常用交叉编码器Cross-Encoder模型把问题和每个候选片段拼在一起打分比单纯算两个向量的相似度精确得多。通过Rerank可以明显把“看起来很相关但其实不对路”的片段往下压把真正有用的内容顶到前面。效果上向量粗排交叉编码器精排命中质量通常比单靠向量检索高出20%以上。3. wow-rag本地实践Ollama加向量库零基础复现3.1 环境准备四样东西一次搞定下面是当时wow-rag项目里完整跑通本地RAG全链路的方法从零开始一步步来。先把环境备好安装Ollama访问官网下载对应系统版本装好后终端执行ollama --version验证。拉取Embedding模型ollama pull nomic-embed-text或者换成bge-m3。拉取LLMollama pull qwen2.5:7b。如果你的机器只有CPU没有GPU可以拉qwen2.5:3b速度更快效果也够学习用。安装Python依赖pip install chromadb langchain langchain-community langchain-ollama这个套装里Chroma负责向量存储LangChain负责编排Ollama的Python集成负责调用本地模型。需要说明的是LangChain并不是RAG的必要条件——直接用Chroma、Ollama的Python SDK也可以但LangChain把切分、检索、Prompt组装这些重复劳动封装得比较顺手入门阶段用它能少写很多胶水代码。3.2 核心代码加载文档到本地问答环境备好后开始跑RAG的完整流程。这里我用的示例是几个Markdown格式的技术笔记文档你可以换成自己的TXT、Word或网页导出的文件。第一步加载并切分文档from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 加载目录下所有.md文件 loader DirectoryLoader(./docs/, glob**/*.md, loader_clsTextLoader) docs loader.load() # 切分按结构感知策略拆块块大小600字符重叠100字符 text_splitter RecursiveCharacterTextSplitter( chunk_size600, chunk_overlap100, separators[\n## , \n### , \n\n, \n, 。, , ] ) chunks text_splitter.split_documents(docs) print(f共切成 {len(chunks)} 个文本块)separators是个容易被忽略的细节。我按“章节标题→段落→句子”的优先级给了分隔符列表这样切分时能尽量先切在结构完整的地方而不是简单粗暴地数着字符切。这套参数的设定逻辑比代码本身更值得记住。第二步向量化并写入向量库from langchain_ollama import OllamaEmbeddings from langchain_community.vectorstores import Chroma embeddings OllamaEmbeddings(modelnomic-embed-text) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db ) print(向量库构建完成数据已持久化到 ./chroma_db)这里我用的nomic-embed-text好处是Ollama集成零配置缺点是对中文长文本的表现不如bge-m3。如果你的语料是中文为主建议改成modelbge-m3代价是首次使用需要多拉一个模型。第三步检索器加上混合检索和重排序# 基础向量检索 vector_retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 10} ) # 用BM25做关键词检索 from langchain_community.retrievers import BM25Retriever bm25_retriever BM25Retriever.from_documents(chunks) bm25_retriever.k 10 # 用EnsembleRetriever把两路结果合并 from langchain.retrievers import EnsembleRetriever hybrid_retriever EnsembleRetriever( retrievers[vector_retriever, bm25_retriever], weights[0.7, 0.3] )混合检索的权重weights我在项目里试过[0.7, 0.3]和[0.5, 0.5]。语义问题偏多时向量权重调高一点专业术语多、用户习惯用精确关键词搜索时BM25权重可以提到0.4以上。这个比例没有绝对最优要根据你的语料特征来调。第四步组装Prompt并生成答案from langchain_ollama import OllamaLLM from langchain.prompts import PromptTemplate from langchain.schema import Document llm OllamaLLM(modelqwen2.5:7b, temperature0.2) template 基于以下参考资料回答用户的问题。 如果资料中没有相关信息请直接说明“据现有资料无法确认”不要编造。 参考资料 {context} 问题{question} 回答 prompt PromptTemplate.from_template(template) def ask(question): docs hybrid_retriever.invoke(question) context \n\n.join([d.page_content for d in docs]) final_prompt prompt.format(contextcontext, questionquestion) return llm.invoke(final_prompt) print(ask(什么是PID控制中的积分饱和))这一步有两个关键细节。第一个是temperature0.2问答场景要尽可能严谨temperature太高会让模型自由发挥产生幻觉。第二个是Prompt里明确写了“没有资料就直说不知道”这句约束能大幅减少“一本正经地瞎编”的情况也是RAG项目里最容易偷懒但最不该省略的环节。3.3 当时跑出来的效果观察我用一批大约80篇技术笔记做了测试语料涉及控制理论、嵌入式开发和Python编程。比较有代表性的几个查询结果问“STM32的DMA环形缓冲区怎么配置”能准确给出代码片段并指出注意事项。问“增益调度和自适应控制的区别”能综合两篇不同文章的内容做对比。问一个语料里完全不存在的主题模型会回答“据现有资料无法确认”没有胡编。全本地跑下来qwen2.5:7b在16G内存的MacBook上生成速度大约每秒15到20个token7b模型可以接受如果换3b模型速度翻倍但答案深度明显变浅。整体链路从提问到出答案大约3到5秒作为本地知识库的交互体验是可以接受的。但这只是最基础的朴素RAG。随着语料规模扩大我逐渐遇到了新的问题——这就引出了下一节的内容。4. RAG的进阶方向GraphRAG、Ontology RAG与Agentic RAG4.1 朴素RAG的瓶颈为什么知识库越大越难用wow-rag项目跑通之后我把语料从80篇扩展到500篇问题就来了检索准确率明显下降很多东西明明在库里就是查不到。这个现象不是个例几乎是所有朴素RAG的共同瓶颈。深入排查后主要有三个原因知识割裂。文档被切成小块后单看每一块都是对的但它们之间的关联信息丢掉了。比如A文档讲了某个算法的原理B文档讲了它的缺陷C文档讲了改进方案——三块内容各自独立检索时单独捞出一块根本拼不出完整图景。这也是热词里反复出现的“解决了知识割裂”背后真正指向的问题。语义重叠导致命中浑浊。当库里有大量相似内容时Top-K检索结果里可能全是同一个主题的重复片段而更细节、更关键的内容被挤出了候选区。跨文档推理困难。有些问题需要综合多个文档的信息才能回答朴素RAG本质上只会“复制粘贴”不会“推理串联”。这几个问题单靠调chunk size、换Embedding模型已经难以根治这也是GraphRAG、Ontology RAG这些方案出现的根本原因。4.2 GraphRAG与Ontology RAG用知识结构对抗知识割裂GraphRAG的核心思路是在向量化之外额外构建一张“实体-关系图”从文档里抽取实体人名、产品名、专业术语、概念再抽取实体之间的关系“A依赖B”“A是B的改进版”最终形成一张知识图谱。回答问题时不仅做向量检索还能沿着图的边做多跳推理。比如用户问“我们的控制器里哪些模块依赖了已经过时的驱动库”朴素RAG需要恰好有某篇文档提到这个结论GraphRAG则可以沿着“模块→依赖→驱动库→状态”的路径在图上推理出答案。Ontology RAG是GraphRAG的近亲。区别在于GraphRAG的图结构是从文档里自动抽取的Ontology RAG则会让领域专家先定义一套“本体”——也就是明确概念、分类、关系的模式——再让文档里的内容去对齐这套本体。带本体的检索约束更强准确率更高但也需要更多的领域设计投入。这个方向在热词里出现的“wiki和rag”“ontology rag”“langchain4j easy rag”都指向同一类实践。微软的GraphRAG和开源的LightRAG是目前最常被提到的两个实现。LightRAG的特点是结构更轻对中小团队更友好。如果想深入这个方向我的建议是先不要急着上先想清楚你的语料里到底存不存在需要跨文档推理的问题。如果只是做问答机器人朴素RAG加Rerank完全够用如果你要回答的是“多个子系统之间如何互相影响”这种层次的问题GraphRAG就值得研究了。4.3 Agentic RAG与RAG as a Service把检索交给智能体如果说GraphRAG解决的是“知识结构”问题Agentic RAG解决的是“检索策略”问题。传统的RAG是“问一次检一次答一次”Agentic RAG则把检索变成了一个可规划、可迭代的过程。举个例子用户问“对比一下我们团队这半年各项目的资源投入效率”。这个问题本身需要分解成几个子任务先找出所有项目文档再抽取投入数据再找相关会议纪要最后综合计算。Agentic RAG里大模型作为Agent会自己规划这些步骤决定先检索什么、用什么工具检索、拿到结果后是否需要进一步追问甚至能自己决定调用哪个子RAG系统。这也是热词里“agentic rag”“rag智能体”“agentscope 2.0 rag as service”这些关键词背后的大趋势。AgentScope 2.0提出的“RAG as a Service”更进一步把RAG能力服务化——不同团队、不同系统之间可以通过标准接口调用各自的RAG能力知识库不再是一个个孤岛。我个人对Agentic RAG的态度是它确实是方向但目前还不是入门阶段该碰的东西。Agent的规划能力依赖更强的LLM也会显著增加响应延迟和调试难度。先把朴素RAG做到极致理解了检索的基本逻辑再在它之上引入Agent决策这条路才走得稳。5. RAG评估与常见问题排查5.1 hit rate与答案质量不能只靠感觉调参进入调优阶段最忌讳的就是“凭感觉”试。今天觉得效果好一点明天又变差了说不清是哪个环节的问题。所以评估是RAG项目必不可少的一环。热词里的“rag hit rate”“rag框架”都指向评估问题。Hit Rate命中率是RAG最核心的指标之一它衡量的是针对一组测试问题系统检索出来的Top-K片段里是否包含能够回答该问题的正确片段。我用的评估流程分三步第一步构造评估集。准备50到100个测试问题每个问题标注出“标准答案”和“关键上下文所在的文档块ID”。刚开始可以用GPT或自己人工标注后续可以做负样本扩充。第二步测量检索质量。逐个问题跑检索看标准答案所在的chunk是否出现在Top-5、Top-10里。记录两个指标HitRateKTop-K检索结果中包含正确chunk的问题占比。MRRMean Reciprocal Rank正确chunk在结果中排得越靠前分数越高。第三步测量答案质量。这一层比较难自动化常见做法是让另一个LLM做裁判LLM-as-a-judge从“忠实度”是否忠于参考材料、“完整性”是否覆盖问题所有方面、“相关性”是否直接回答问题三个维度打分。这个评估集一旦建好后续调整任何参数chunk大小、Embedding模型、retriever权重、Rerank开关都能立刻看出效果变化。我强烈建议评估集必须在项目早期就建不要等到调不动了再回头补。5.2 常见问题速查表这些坑我基本都踩过整理一份我在RAG实操里遇到过的问题和对应解法做成速查表现象可能原因排查方向与解法问什么都答“没有相关信息”检索命中率低chunk切太碎调大chunk_size增加重叠比例启用混合检索答案答非所问和检索结果无关生成阶段Prompt里的context权重太低或LLM忽略了检索内容检查Prompt模板顺序把context放在前面强化“只能基于资料回答”的约束降低temperature检索结果里塞满了重复内容语义重叠严重向量检索排名过于集中加入MMR最大边际相关性检索策略降低冗余专业术语查不到向量模型对精确术语不敏感启用BM25关键词检索或提高混合检索里BM25的权重答案语言生硬、不像人话LLM上下文太长导致输出质量下降限制Top-K数量到3-5个chunk或加大chunk_size减少总片段数知识库更新后结果没变化向量库没重建或增量更新失效确认persist目录被正确覆盖设计增量索引流程中文处理效果差Embedding模型对中文支持不足换bge-m3或text2vec注意上下文长度限制表格里的每一个问题我在不同项目里都亲自撞到过。最典型的还是第一条——“答不上来”的问题90%出在检索环节而不是生成环节。排查的时候可以先把检索结果直接打印出来人工看一遍如果检索结果本身都不相关那不管怎么调Prompt都没用。5.3 几个让RAG更稳的接地气小技巧评估和排查之外再分享几个实测下来很管用的优化手段。给检索结果加上文元数据。把每个chunk所在文档的标题、章节路径、页码一并存进向量库检索时将它们拼在chunk内容的前面。LLM拿到这些上下文后能更容易理解片段之间的结构关系也有助于给出更精确的答案。这个改动极其廉价但收益明显。用“压缩提示词”减少上下文浪费。当检索结果很长时可以直接让LLM对候选chunk做一次压缩——要求它提取与问题相关的关键信息过滤无关内容。相当于在生成最终答案之前先让模型做一轮“总结过滤”能有效降低最终输入的token量也能缓解上下文过长带来的注意力稀释。将重复性FAQ单独建库。对于用户频繁问到的高频问题直接建立一个“问题→标准答案”的映射表检索时优先匹配FAQ库。命中就直接返回不经过大模型生成。这样既省算力又能保证高频问题答案的绝对一致。知识库越做越大以后这个小优化会显著提升用户体验。日志记录是隐形的救星。每个查询都记录下检索向量结果、实际返回的chunk ID、LLM的原始输出。事后查问题时你才能知道是因为哪一步丢了信息。没有这套日志出问题就只能靠猜效率极低。这些技巧单独看都不起眼但组合起来效果比我调一个月的Embedding参数来得更明显。RAG的优化思路其实和写代码一样——先抓住可控因素再谈模型和参数的精细调优。最后分享一个自己实操后的体会RAG入门阶段最忌贪多求全。今天看到GraphRAG火就上手图谱明天看到Agentic RAG就去搭智能体结果哪个都没跑透。我踩过几次坑之后的结论是把最基础的“文档→切分→Embedding→向量检索→Rerank→生成”这一步做到足够扎实比盲目追逐任何一个新概念都更有价值。这篇笔记是wow-rag项目留给自己的复盘也希望能帮你把RAG这条路上最难的那几步走得顺一点。
返回列表