RAG完整链路拆解:从建库、检索到生成,Agent开发必读

发布时间:2026/11/4 4:36:23
RAG完整链路拆解:从建库、检索到生成,Agent开发必读 做Agent开发这半年我最大的感受是Agent的能力边界多半不取决于那个模型有多强而取决于它能不能在正确的时间拿到正确的信息。模型再聪明遇到一个没见过的私有领域问题也只能一本正经地编个答案给你。所以这篇笔记我来把RAGRetrieval-Augmented Generation检索增强生成从建库、检索到生成的完整链路拆开讲一遍。这篇内容适合正在做Agent开发、手头恰好有私有知识想让Agent懂的朋友如果你只是听过RAG这个词、好奇它到底怎么work的也能往下看。我会用大白话讲清楚三个环节里每个关键决策背后的理由——不是简单地告诉你参数是多少而是为什么是这个参数、换掉会怎样。全程没有炫技都是我实际跑过的方案和踩过的坑。RAG本质上就是一个三段式流程先把文档变成可检索的索引建库再针对用户提问捞出最相关的片段检索最后把片段和问题一起交给大模型生成答案生成。听起来简单但每个环节里都藏着足够多的细节任何一个地方做得糙最后出来的答案质量都会打折扣。1. 建库之前先把为什么用RAG想清楚1.1 为什么不是直接微调模型很多人一上来就喜欢问我能不能直接微调一个模型让它记住我的业务知识我的回答通常是如果知识量不大、更新频率低、对可解释性没要求微调确实可以但一旦进入真实生产环境RAG的优势会迅速碾压微调。直接微调至少有三个绕不过去的问题。第一是成本无论用开源模型还是API微调都要准备训练数据、算力资源动辄几万条样本起步小团队根本玩不转。第二是更新业务文档今天改了一版合同模板、明天换了一套产品手册微调模型就得重新训练这个更新周期没人忍得了。第三是幻觉微调本质上是在背知识模型会把背过的内容和它自身预训练的参数搅在一起你很难分清楚它什么时候在引用你的资料、什么时候在自由发挥。RAG把这些问题全部绕开了。文档更新了重建索引就行不用碰模型权重答案生成时每个输出都能追溯到原始文本片段出了问题可以查来源。这套外挂知识库的思路在实际业务里远比让模型记住更可靠。1.2 Agent 为什么需要 RAG 这个外挂放在Agent开发这个语境下RAG更像是一个记忆外挂。Agent的核心能力是感知、决策、行动但它的感知对象通常是用户输入和工具返回结果。如果Agent要处理的是像企业内部的运维文档、商品资料、法规条款这类外部知识它自己是记不住的必须有一个途径去获取这些信息。实际开发里我习惯把RAG封装成一个标准的tool给Agent调用。Agent先判断用户问题里是否涉及私有知识如果需要就走检索-生成这套管线如果不需要直接让模型回答。这比把RAG硬塞进Agent的system prompt里要干净得多——否则一次对话里塞几十篇文档还没开始干活上下文就爆了。2. 建库环节决定检索上限的第一道关卡建库管的是有没有值得检的东西。这一步如果做不好后面检索和生成再怎么调都白费因为它直接决定了信息能不能被有效召回。2.1 文档清洗比你想的更费功夫建库的第一步不是切分更不是embedding而是把原始文档变成干净的纯文本。我实际处理过的文档类型里最省心的是Markdown和纯文本几乎不需要预处理PDF是最麻烦的尤其是扫描件。扫描版PDF必须先过OCR光学字符识别推荐用PaddleOCR或者TesseractPaddleOCR对中文表格和公式的支持更友好实测下来识别准确率能到90%以上。文字的PDF不要盲目OCR先尝试用pdfplumber或PyMuPDF直接提取速度快而且不会引入识别噪声。Word文档用python-docx抽取段落时要注意表格内容建议把每个表格转成一行带分隔符的文本比如字段名:值;字段名:值这种格式否则向量化的时候表格语义容易被冲散。HTML文档要用BeautifulSoup去掉script和style标签只保留正文文本很多网页模板的导航、广告、版权声明都是噪声不清掉会污染后续的向量。还有个容易忽略的点清洗时保留文档结构信息。一级标题、二级标题、列表这些标记建议在切分前保留或者转成带层级标识的文本。这样后面切分时可以把标题一起拼进去检索时能拿到更好的上下文线索。2.2 切分策略chunk size 和 overlap 的取舍清洗完文本接下来就是切分chunking。这一步的目标很简单把长文档切成若干个小片段每个片段语义尽可能完整同时体积要适合embedding和后续检索。切分有三条路线可以选固定长度切分按字符数或token数硬切比如每512个token一段。实现最简单但容易把一个完整段落拦腰截断造成语义不连贯。结构感知切分按标题、段落、句子边界切天然保持语义完整性适合Markdown和结构清晰的文档。语义切分用模型判断句子之间的语义边界质量最高但计算成本也高中文场景下实测效果与结构切分差距不大不推荐优先尝试。关于chunk size的经验我给一个可以直接抄作业的起点中文场景下chunk控制在400到600个token之间比较合适overlap设50到100个token。这里说的token是指模型的tokenizer切词结果中文字和token的换算大致是1.5到2个字符对应1个token不同模型略有出入。为什么要overlap因为相邻的两个chunk如果完全没有重叠一个完整句子的后半句可能落到下一个chunk里检索时只召回前半句信息就是残缺的。我见过因为没设overlap导致问答效果骤降的情况加了overlap之后答案质量明显回升。不过chunk大小不能一概而论。如果文档本身是操作手册、合同条款这种一条是一条的内容小chunk更合适200到300个token因为每一条本身就是一个完整语义单元。如果是技术方案、论文这种大段论述型文档稍大一点的chunk反而效果更好因为检索出的上下文更完整。2.3 向量化embedding 模型选型要慎重切分完成下一步是把每个chunk转成向量。这里有几个关键点要讲清楚。首先是维度。以OpenAI的text-embedding-3-small为例默认维度1536国产的bge-large-zh-v1.5是1024维bge-m3是1024维。维度越高不代表效果越好维度低的模型如果训练质量好检索效果照样能打而且占用存储和计算资源更少。选型时优先看模型在中文语义检索任务上的表现比如C-MTEB榜单再考虑维度。其次是模型一致性。建库时用什么模型做embedding检索时就必须用同一个模型不能建库用bge、检索换OpenAI两种向量分布根本不在一个空间里相似度计算会完全失灵。这个错误我见过不止一次属于最隐蔽的坑。再次是输入长度限制。不同embedding模型的max sequence length不一样bge系列通常支持512个tokenOpenAI的text-embedding-3-small支持8191个token。如果你的chunk超过模型上限需要截断但截断会丢信息所以回头调整chunk size比硬截断更合理。我的选型建议要求数据不出内网用bge-m3想省事且追求中文效果用OpenAI text-embedding-3-small对多语言有要求也优先bge-m3。如果跑本地方案我实测bge-large-zh-v1.5的中文效果很稳配合FlagEmbedding框架加载也很方便。2.4 向量数据库选型与元数据设计向量数据库的作用就是存向量、算相似度。市面选择很多Chroma、Milvus、Qdrant、pgvector、Elasticsearch 8.x。我的建议是按部署场景来选。个人项目、快速验证用Chroma它就是一个嵌入式库pip install完直接能用Python端到端跑通非常快生产环境、数据量大用Milvus或QdrantMilvus在百万级向量上的检索性能很稳Qdrant的Rust底层单机部署也很轻量如果你的公司本来就有PostgreSQL直接用pgvector省一套新组件但要评估并发和索引性能。元数据设计这块很多人不重视但我强烈建议在建库时就把每条chunk的元数据字段想清楚。最少要有四个字段来源文档IDdoc_id、文档标题title、原始章节路径section_path、页码或段落编号chunk_index。这些字段在检索后有大用生成阶段可以让模型把答案关联到具体章节标题和页码用于引用排查问题的时候也能精确回溯到是哪个文档哪一段带偏了答案。向量索引的配置也有讲究。Milvus和Qdrant默认用的是HNSW算法一种基于图结构的近似最近邻搜索算法建索引时报参数。以HNSW为例核心参数M值控制每个节点的连接数经验值是16到64M越大召回越准但内存占用越高efConstruction影响建索引精度一般取200到500。这些参数在千万级向量以下场景很难感受到差别不用过度调优但M32、efConstruction200是稳妥的起步配置。3. 检索环节召回率与命中率的博弈建库只是把知识存好了真正决定用户体验的是检索环节。检索质量的核心衡量指标有两个召回率Recall和命中率Hit Rate)。召回率要看用户问题相关的文档片段有没有被捞上来命中率更严格它要求相关片段出现在检索结果的前N条里。检索环节的每一个决策本质上都是在提高这两个指标。3.1 相似度计算余弦、内积与欧氏距离向量检索的原理不复杂就是把用户问题的embedding向量和库里所有chunk的向量算距离取最近的N个。距离度量有三种常见方式余弦相似度看两个向量的方向是否一致不考虑长度最常用对文本语义匹配效果好。内积受向量长度影响大适合对向量做完归一化处理的场景很多向量数据库默认用内积。欧氏距离看向量空间里的直线距离对长度敏感维度高时直觉上不如余弦直观。大多数情况下我建议用余弦相似度。但有一个细节要注意如果embedding模型输出的向量模长本身没有意义多数模型都是这样余弦就是最稳的选择如果模型明确做了归一化内积和余弦在数学上是等价的选哪个都一样。在Milvus里建collection时field类型配成VECTOR_FLOAT32metric_type选COSINE就行。3.2 设置合理的 top-k并持续观察命中率top-k代表每次检索返回多少条候选chunk。这个参数需要平衡太小容易漏掉真正相关的片段太大则会把噪声带入上下文既拉低答案精度又浪费上下文窗口。经验起点是top-k5到10。然后根据命中率反过来调如果前5条里经常没有答案就把k调大到10或者15如果前5条每次都能命中可以试着缩小k用更少但更准的上下文换生成质量。我实际跑一个产品FAQ场景时top-k从3调到8之后答案完整度有明显提升但调到15之后答案开始引入无关信息最后落在8。这里要提醒一句top-k是向量召回阶段的粗筛千万不要指望这一步一步到位。更科学的做法是召回多取一些比如20条然后用重排序模型精排取前3到5条进上下文。这套粗召回精排序的组合拳比单纯调小top-k效果稳定得多。3.3 混合检索不用傻乎乎只怼向量纯向量检索有一个天然盲区它擅长语义相关却不擅长精确匹配。用户如果搜VAT税率15%而你文档里写的是增值税税率15%向量大概率能兜住但如果用户搜的是合同编号HT2024001向量检索往往会找出一堆语义相近但完全没有包含这个编号的片段因为embedding会把这种短标识符的含义稀释掉。这时候就要上混合检索。方案是BM25稀疏检索与向量检索稠密检索并行执行BM25负责精确词汇匹配向量负责语义匹配再把两路结果融合。融合算法我推荐RRFReciprocal Rank Fusion倒数排名融合对每路结果按排名给分取倒数求和简单有效实测比加权分数融合更稳。具体来说文档先同时建立两个索引一个是向量索引一个是BM25文本索引。检索时Query先走向量库拿到相近的20条再走BM25拿到精确匹配的20条然后RRF融合TopN进下游。ES 8.x原生支持这种混合检索向量和BM25可以在一个索引里配置非常方便。Elasticsearch如果版本在8.8以上还支持rank_features不过能不能用取决于运维的接受程度。3.4 从意图识别到检索语义Query改写这一步不能省用户真的会把问题问得很随意尤其是多轮对话时。用户上一句说我看了你们的入门指南下一句直接问第二步的那个参数怎么配——这里的那个参数如果不改写直接拿去检索几乎什么都捞不到。所以检索之前要先做一次Query改写Query Rewriting把原Query变成更适合检索的语句。常见做法有两个一是补充历史上下文把这轮问题、上几轮用户问题、Agent的回复拼接让LLM提炼出独立的、语义完整的检索Query。这个方案灵活但多一次LLM调用延迟会增加几百毫秒到一个秒级生产环境要权衡。二是对Query做纯规则清洗去掉语气词和无关表达、识别并抽取关键实体。如果用户问题里带有文档标题、编号等强标识信息要拼接进改写后的Query里保证精确匹配能命中。我建议不要省略这步。用LLM改写一次Query的开销并不高但对召回的提升非常明显。有个经验数据在具体业务里做了Query改写之后hit rate能从65%左右提升到80%以上这个提升幅度相当可观。3.5 重排序让最相关的片段排到最前面重排序Rerank阶段业界主流的做法是用cross-encoder结构的模型。它把Query和每个chunk拼接成一对同时输入模型判断相关性分数相比双塔式的向量检索跨编码器能让Query和文档深度交互相关性判断精确得多。推荐两个模型bge-reranker-v2-m3BAAI出品中文效果稳定以及Cohere RerankAPI方式英文效果很强。重排序模型输入有长度限制通常512个token所以重排序前要先确认chunk没超长超了要截断。重排序策略是向量检索召回20到30条候选重排序后只保留前3到5条进入生成。我实测过不加重排、纯靠向量top-k进生成的效果再用bge-reranker重排对比答案质量提升非常明显——重排后答案内容更聚焦不再出现东拼西凑的缝合感。4. 生成环节把检索片段变成高质量答案建库和检索配合好了最后一步就是让大模型根据检索结果生成答案。很多人的理解是把检索结果拼到Prompt里再问一遍模型但实际做起来细节比这多得多。4.1 Prompt 模板设计先把约束说清楚生成环节的Prompt设计我总结了一个核心原则把检索结果当作论据而不是答案抄写材料。也就是说模板里必须明确告诉模型——只依据提供的上下文回答问题如果上下文里没有相关信息直接说明不知道不要编造。一个经过实战验证的模板骨架是这样你是一个专业助手。请回答用户问题回答时严格遵守以下规则 1. 仅依据提供的【参考文档】回答禁止使用你自身预训练知识中与参考文档矛盾的内容。 2. 如果参考文档中没有足够信息请明确回复根据现有资料无法回答。 3. 回答中涉及的事实性信息必须在句末标注来源编号格式如[1]、[2]。 4. 回答要简明扼要不要复述完整参考文档只提取与问题直接相关的内容。 【参考文档】 [1] 来源: 产品手册.pdf 第2章 3.2节 内容: chunk文本 [2] 来源: 设备配置说明.md 第4节 内容: chunk文本 【用户问题】 改写后的Query这里有一点要注意给模型的参考文档一定要带上元数据前缀来源、章节而不是只给正文。这样模型在生成时能感知到不同片段来自不同地方写引用时可以标注准确来源否则它就只知道引用了某段未知来源的文本引用功能形同虚设。还有个小技巧在模板里把多个chunk用分隔标记隔开比如用编号来源内容的结构化格式。模型对这种再次结构化后输入的内容理解得更好比一坨连续拼接的文本强很多。4.2 上下文窗口管理别把模型撑死RAG系统一个非常常见的崩溃方式是把太多chunk一股脑塞进上下文。窗口再大的模型塞进去几千行文档之后注意力也会被稀释模型开始东看一句西看一句答案质量断崖式下跌。我的上线前自检标准最终进入上下文的文本总量不超过模型上下文窗口的60%到70%。假如你的模型是128K窗口给RAG用的预算大约在80K到90K以内。如果检索返回的chunk总长度已经快顶到窗口上限有两个办法兜底——一是缩小重排序后的保留条数二是对chunk做摘要压缩再放入上下文。还有一个容易忽略的点system prompt本身也是上下文的一部分。如果系统提示词写了几千字再塞入几十个chunk就可能超出窗口。RAG场景下system prompt应该精简只保留角色说明和规则别把公司介绍、操作手册这类的常驻知识写到system prompt里——那是建库该干的事。4.3 引用溯源生成答案的最后一道防线引用溯源不只是为了让用户看到来源更是一个防幻觉的有效手段。在前面Prompt规则的基础上我要求模型每个事实点都标注来源编号然后在代码层面做一道校验如果答案里出现了[3]但[3]对应的chunk内容里根本没有这句话就判定这是一次潜在幻觉需要重新生成或让用户确认。实现起来不复杂核心就是解析输出中的引用编号回到原始的chunk文本里做关键词或语义比对。这套机制在业务场景里极其有价值因为很多用户对AI说的对不对非常敏感有了可溯源的引用整个系统的可信度直接上一个台阶。在Agent场景里引用信息不只是用来展示它还能作为下一步行动的输入。比如用户追问你引用的这个条款是哪个版本的Agent可以根据引用里的版本号字段继续检索这是纯问答做不到的——从这时开始RAG就不是一个静态流程了而是长出了决策的雏形。5. Agentic RAG从单轮检索到多轮决策现在很多项目已经不满足于用户问一次、系统检一次、模型答一次这种固定流水线了于是热词Agentic RAG出现了。它的核心变化是检索这个动作不再是提前写死的流程而是由Agent根据对问题的理解动态发起、动态终止、动态调整。其实Agentic RAG可以用一句话概括把RAG从管道变成工具。传统的RAG是一条流水线Query进、答案出过程不可干预Agentic RAG则是把检索增强拆成了几个原子能力让Agent像人一样判断该不该检索、该先查什么、查到的信息够不够不够再查一轮。5.1 从固定流程到动态决策Agent 怎么调用RAG我把Agentic RAG的决策逻辑拆成几个关键节点意图路由Routing先判断用户问题需不需要检索。比如你好、闲聊寒暄直接由模型回答即可涉及具体事实、参数、流程、规范类问题才走检索。这一步用LLM做意图分类成本低收益大能省下一大堆无意义的检索开销。查询规划Query Planning对于复杂问题拆解成多个子查询。比如用户问怎么部署Nacos集群并配置数据库脚本Agent可以拆成Nacos集群部署步骤和Nacos数据库建库建表脚本两次独立检索再合并回答。这一步比分一次大检索效果更精准。迭代检索Iterative Retrieval第一轮检索结果不够时Agent基于已有信息生成新查询继续检索直到信息充足或达到最大迭代次数。实现时要注意设置轮数上限防止死循环烧钱。5.2 RAG 与其他工具协同检索不是唯一的信息来源在Agent的完整工作流里RAG往往不是唯一的信息来源它还与搜索、API调用、代码执行等工具一起协同。比如Agent先通过RAG检索出某设备型号的参数再通过另一个工具查询该设备的实时库存最后把两路信息合并生成答案。这种多工具并行决策编排才是Agent场景的正解。实际开发中我建议把RAG封装成独立的tool服务对外提供两个接口一个是对文档的写入/更新接口一个是对用户的检索接口。这样Agent侧只关心函数签名和返回格式不需要感知向量库、embedding模型这些底层细节后续替换模型或数据库时也不会影响Agent主流程。5.3 进阶方向GraphRAG、Ontology RAG 与多模态检索多轮检索之外RAG的进阶方向主要集中在两个一个是引入图结构另一个是引入多模态。GraphRAG的思路是先从文档中抽取实体和关系构建知识图谱再结合向量检索进行图遍历。它在处理多跳关系问题上比纯向量检索强比如公司A和公司B共同参与的项目有哪些这类问题纯向量检索往往答不好图结构可以沿着关系边一步步推理。如果你想用可以考虑微软的GraphRAG开源项目但要做好心理准备构建图谱的计算成本很高小规模知识库不太划算。Ontology RAG比GraphRAG更进一步它给知识图谱加了一层语义模型。构建速度更慢、成本更高但检索结果的准确率和推理性更强适合知识结构复杂、关系明确的领域比如医疗药品和金融产品。对大多数团队来说GraphRAG已经到了足够用的程度不建议一开始就上Ontology。多模态检索解决的是文档里既有文字又有图、表、公式的问题。目前成熟方案是双编码器结构分别对图片和文本做embedding用统一向量空间对齐比如CLIP家族模型。但我要实话实说多模态RAG的工程复杂度比纯文本高不少如果你的场景里图片只是配图、文字才是关键信息先把纯文本RAG做好多模态作为二期再考虑别一开始就把摊子铺太大。6. 常见问题与排查技巧实录最后分享一些实际运行RAG系统时遇到的典型问题。这些都是我一条条踩出来的堪称避坑清单。6.1 建库阶段的坑常见问题有这么几个chunk切分破坏了语义单元。症状是检索结果前言不搭后语。排查时看召回出来的片段是不是经常一句话只说了一半。解决办法是先按章节/段落切分再对超长段落做二次细切别只用固定长度硬切。文档清洗不干净。症状是检索结果里频繁出现导航菜单、页眉页脚文字。检查清洗脚本是否把HTML的script、style标签和重复模板文本过滤干净PDF提取后可以先抽样看看文本质量再入库。embedding模型来源混杂。症状是检索结果整体漂移相似度分数普遍偏低。排查全链路是不是混用多个embedding模型确认建库和检索用的是同一个。6.2 检索阶段的坑命中率低但召回率还行。先看是不是top-k设置太小优先重排序而不是盲目扩大top-k扩大top-k通常只会把噪声一起带进来。检索结果太泛化。典型情况是Query太短比如用户只输入服务器这个词。先把Query改写和实体抽取做起来把服务器扩展成服务器配置服务器故障处理这类带意图的检索词。精确ID、编号搜不到。那就是纯向量检索的通病尽快上BM25混合检索别只堆向量。6.3 生成阶段的坑最常见的两个一是幻觉上下文没有相关信息模型硬答。解决办法是Prompt里强调不知道就直说同时在代码里加引用真实性校验不满足就拒绝生成或重新检索。二是答案缝合感重一段话把多个互不相关的chunk拼在一起。排查重排序效果看看是不是recall阶段召回的chunk本身太杂精排没压住。另外检查top-k是否过大千万别把20多条chunk全部塞进上下文3到5条是合理区间。整个RAG链路做得越久越发现建库的底子、检索的取舍、生成的约束每个环节都不能有短板。早期项目里我花了很多时间在调生成部分后来才发现问题出在建库阶段文档没清洗好、或者检索阶段没有用混合检索。先找到短板再发力比盲目优化单点效率高得多。最后分享一个我自己的体会RAG不是万能的它适合的场景是知识可结构化、答案可溯源如果你的问题高度依赖推理和多步骤执行纯RAG会很吃力那就要往Agentic RAG或者GraphRAG的方向去扩展。搭系统的时候先把最简单的闭环跑通——小规模文档、固定流程、单轮问答——再逐步叠加Query改写、重排序、多轮决策这些进阶能力。每叠加一层都回归测试一轮hit rate和答案质量确认有提升再留下没提升就撤掉。这样一步一步做出来的RAG系统才是真正经得起业务检验的。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询