
这两年聊RAG最常听到的一句话是“RAG已经烂大街了”。随便一个人都能用向量数据库加LangChain在三十分钟内拼出一条“上传文档-切块-向量化-检索-拼接-回答”的知识库流水线跑通给老板看个效果。但等你把它接到真实业务里通常第一周就会被问崩溃为什么PDF里的表格被切得七零八落为什么用户问一个跨文档的多跳问题模型就开始扯为什么明明检索到的内容是对的生成阶段却不用为什么旧版本制度和新版本制度同时存在回答左右摇摆这些都是流水线之外的深水区。我自己的理解是烂大街的只是那条流水线真正拉开团队差距的是流水线之外六个很少有人认真讲的环节。这篇文章不教你怎么三分钟跑demo我想把六个真正决定RAG能不能落地的分水岭拆开聊多模态预处理、检索策略、知识库形态选型、生成阶段冲突消解、智能体编排、工程评测。不管是刚入门的新手还是已经跑通流水线但被效果卡住的开发者应该都能拿走一些能立刻用的东西。1. 文本拆解与多模态预处理知识进得来答案才出得去1.1 切块不是越细越好先搞清楚“知识原子”是什么很多项目默认用固定字符切块比如每500字符切一块overlap设50。这种方式看起来简单实际上一刀下去经常把完整结论切成两半。举个例子产品说明书里“保修期为一年”和“保修范围不包括人为损坏”是两个独立知识点如果被切到不同块里用户问“保修范围是什么”系统只检索到第一块回答自然缺胳膊少腿。我现在的做法是先定义“知识原子”一块文本应该能独立表达一个完整信息点。切块时优先按标题、段落、列表、表格的边界切而不是纯按字数。可以用递归字符拆分做兜底但当文档结构明确时结构边界的优先级应当高于字符数。实测下来把chunk_size从500调到300配合合适的overlap检索的集中度会有明显提升但也不能切得太碎否则上下文信息不足模型拼不出完整答案。本地文本拆解这块我常用的工具是Unstructured、Docling和markitdown。Unstructured功能全但依赖多Mac上装起来偶尔会踩编译坑Docling对PDF和Word的处理更稳markitdown是微软出的转Markdown工具适合快速把各种格式转纯文本。如果你只是临时处理扫描件PyMuPDF加OCRmyPDF的组合也够用。需要提醒的是不管用哪个工具切块结果一定要肉眼抽查。把随机几十个块打印出来看一眼比调十次参数都管用。1.2 图片到底能不能放进RAG知识库“RAG知识库能存储图片嘛”这个问题被问过无数次先给结论能存但存图片不等于能被检索。如果你的知识库里只有一堆图片文件而用户输入的是自然语言问题向量库拿文本query去匹配图片向量效果大概率是灾难。原因是大部分RAG链路索引的是文本图片本身不是一个可以被语义检索的自然单位。要让图片真正“进”知识库有两条路第一条把图片转成文本影子。扫描件先OCR然后让多模态大模型给图片生成一段包含关键参数的描述比如“产品参数图型号A310额定功率2200W保修期一年”再把这句描述和原图路径一起存进知识库。用户检索到这段描述回复时把原图路径附上。这是目前性价比最高的做法本地的Qwen-VL或者云端的GPT-4系列都能干这活。第二条用多模态Embedding模型比如CLIP这类把图片和文本映射到同一个向量空间。这套方案能直接做图搜文、文搜图但对模型和工程要求更高小项目没必要一上来就上。所以下次再纠结“能不能存图片”真正要想清楚的是图片里的信息有没有被转成文本形态并且作为检索的入口。1.3 表格、扫描件和多级标题的坑表格是RAG预处理里最大的坑之一。普通文本切块会把行列关系拦腰切断比如“3月销售额120万”可能被切到两个块里。正确做法是整表抽取把表格转成Markdown或JSON结构让模型能理解行列对应关系。Docling和Unstructured都有表格解析能力但解析质量因PDF而异需要每类模板做验证。扫描件必须先过OCROCR错字会影响检索命中所以要把OCR后的文本和原文页码绑定方便后面溯源。多级标题也是麻烦点很多长文档有章节嵌套平铺切块会把“1.2.3”这种层级的上下文丢掉。建议先构建文档树采用父子块策略用小块去匹配query命中后取它对应的父块或整节送去生成保证信息完整。一句话总结预处理决定RAG的上限模型只是在下限之内发挥。真正的分水岭在文档还没进向量库之前就已经开始分开了。2. 检索策略才是召回质量的分水岭2.1 纯向量检索为什么总差一口气向量检索这个技术本身没问题但它有一个天然短板擅长语义相似不擅长精确匹配。用户问“编号A310的保修条款”向量检索可能召回一堆“B310”“C310”的类似文本而精确的A310条目反而被埋在后面。这不是模型笨而是稠密向量对特定词、数字、型号这些精确标识不敏感。很多项目的RAG瓶颈不在生成而在召回这一步。你召回的Top 5里只有1条是真正有用的后面接入任何大模型都很难给你满意的回答。我见过好些团队把问题归咎于“模型不行”换了更大的模型效果还是上不去最后回头检查才发现是检索阶段就漏了瓜。解法其实不复杂混合检索。向量检索跑一遍语义相关内容BM25全文检索跑一遍精确关键词匹配再用RRF或加权分数融合排序。LangChain里可以用QueryFusionDify里直接在检索设置里选“混合检索”。我个人的建议是不管用什么框架第一时间先把混合检索接上别裸用向量。2.2 重排把“像”变成“是”混合检索召回的Top 20里可能确实有5条是相关材料但排序乱成一团。这时如果直接把Top 20全部给模型模型会淹没在噪声里如果只取Top 3又可能把真正有用的内容漏掉。所以需要第二步重排。向量模型通常是双塔结构query和文档各自编码再算相似度快但精度有限。重排器是cross-encoder把query和每条文档拼在一起过一遍模型打分更准但慢。工程上的通用做法是两段式第一级用混合检索取回Top 20到50条第二级用重排器取Top 3到5条进入生成。我在一个产品文档库上做过对比加了重排之后答案正确率从48%提到71%。推荐先用开源模型比如bge-reranker-base本地Mac也能跑预算充足再考虑商业重排服务。注意重排器的计算量和文档条数成正比所以一定要先截断到“候选集”再重排否则延迟扛不住。2.3 查询改写、元数据过滤与父子块用户的原始问题通常不适合直接拿去检索。比如用户问“那个新政策对加班怎么规定”你拿“新政策”去向量库里捞大概率捞到一堆无关内容。要先做查询改写用LLM把问题扩展成“加班 规定 最新政策”或者生成多个不同角度的查询并行检索再合并结果。这个步骤简单但对召回帮助特别大。元数据过滤同样重要。给每个文档打上时间、部门、文档类型标签检索时加filter。问“去年的报销制度”直接过滤掉今年没生效的旧文档噪声立刻少很多。很多平台如Dify在知识库配置里就支持元数据字段只是被大多数人忽略了。父子块策略我强烈推荐。具体做法是小chunk用来匹配query比如200字命中后取出这个块所在的父块或整个章节比如2000字送去给LLM生成。这样既保持了检索的精准度又保持了上下文的完整性。检索策略做到这一步才算把“能搜到”变成了“能答好”。3. 知识库形态选型文本库、知识图谱与结构化数据的取舍3.1 三类知识库到底有什么不同“kg知识库、rag知识库和结构知识库区分以及应用场景”这个问题几乎每次聊RAG都会被翻出来。我把它们放到一张表里看清楚类型数据形态适用问题优点代价文本RAG库非结构化文档“怎么做X”“X是什么”“包含哪些内容”搭建快、成本低、语义检索强多跳推理弱、精确统计弱知识图谱(KG)实体/关系/属性“谁负责X”“A和B什么关系”“跨文档多跳”推理链路清楚、关系明确构建成本高、维护复杂结构化数据库表格/数仓“第三季度销售额多少”“各区域排名”精确统计、聚合查询强需要NL2SQL不支持模糊语义做任何RAG项目之前先问自己你的知识到底属于哪一类企业内部制度问答文本RAG库就够了“某个项目负责人是谁参与过哪些项目和谁有关系”这种问题才值得上知识图谱“今年各季度各产品线销售额对比”这类问题直接查SQL库更快不要把文本检索硬扛。我见过很多团队一上来就想做知识图谱结果文档里连实体关系都不清晰建出来的图谱全是噪声。九成场景先把文本RAG库做好再谈其他。3.2 图谱RAG与Ontology RAG什么时候值得上GraphRAG和Ontology RAG最近很热但热不代表你得跟。它们的核心是用LLM从文档中抽取实体、关系、属性建一张知识图谱检索时顺着实体关系扩展上下文从而回答跨文档多跳问题。听起来很美好但代价很高。图谱构建要用大量token文档更新频繁时图谱容易出现“实体还在文档已删”的过期问题。我的判断标准很简单如果你的100个问题里少于20个需要跨文档多跳老老实实用文本库加重排只有当提问里频繁出现“谁”“哪个”“与什么相关”并且答案需要跨多个段落拼接时才考虑上图谱。折衷方案是混合架构文本库负责常规检索知识图谱只对高频实体建一个轻量索引由路由判断“多跳问题”时再启图谱。这样既能覆盖多跳场景又不至于让全量图谱成为维护负担。3.3 Wiki类知识库的特殊处理Wiki类型的知识库是RAG的经典难题因为它是网状的条目之间互相链接信息分布在很多页面里。直接把每个页面切块扔进向量库会丢失跨条目的关系。用户问“RAG和Agent的区别”答案经常一半在RAG页面、一半在Agent页面单条检索根本拿不全。我的做法是两层索引第一层是条目级索引抽取每个页面的标题和摘要建立条目关系第二层是章节级索引对具体内容做细粒度切块。检索时先通过条目索引定位到可能相关的两三个页面再进入这些页面取相关章节。必要的时候顺着一跳出链把邻居条目的内容也带进来相当于在文本检索之上加了一层Wiki路由。这套做法的成本比全量知识图谱低很多但对Wiki场景的提升非常明显。4. 生成阶段上下文管理与冲突消解4.1 检索结果不是越多越好上下文压缩与去重很多流水线习惯把Top 5全部塞给模型以为信息越多越稳。但检索结果里常常有内容互相重复、甚至互相矛盾。模型不是人它不会自动判断哪条可信你说“资料里这么写”它就照着说矛盾越多越容易胡说。生成阶段的第一个动作是压缩。重排取回3到5条就够不要贪多。如果同一来源有多个块优先合并成一段连续内容。还可以用LLM压缩器对每块做一个摘要只保留与query相关的部分。这个步骤能显著减少上下文噪声尤其当文档很长、默认切块很多的时候。“流水线及流水线中的冲突”这个热词正好点在要害上检索结果之间的冲突、多文档之间的版本冲突本质上是数据治理问题不是模型问题。我处理过一个案例旧版制度写“请假提前3天申请”新版写“提前1天”两个版本同时入库模型回答就一会儿3天一会儿1天。后来在文档里增加“生效日期”字段检索时只取最新版本问题直接消失。4.2 引用和溯源企业级RAG的生死线企业里用RAG最怕的不是回答不够精彩而是回答没有出处。一个没有引用的回答哪怕再正确业务方也不敢拿出去用。所以在提示词里必须强制要求“回答结束后标注来源”并让生成内容跟随检索结果里的文档编号。具体实现也不复杂检索结果里有文档ID和段落号把它传给LLM提示词里要求“在答案末尾用[1][2]标注依据来源”然后解析输出时的编号映射回真实文档链接。即使模型偶尔标错编号你也必须把这条链路做起来因为这是人工复核的唯一抓手。没有引用的RAG在正式场景里基本等于不可用。4.3 提示词不是万能但至少要管住“不知道”有些人反复磨提示词试图让模型“更会作答”。但提示词只能做一件事约束模型的行为边界提高不了检索质量。我自己会用这样一套要求只基于检索内容回答不调用内部知识补全。如果检索内容不足以回答明确说“资料中未找到”禁止编造。回答必须带引用编号。涉及多个来源时如果冲突优先采用生效日期最新、权重最高的来源。模板本身很简单但不要指望靠一行“请基于上下文回答”就能解决所有问题。提示词是安全带不是发动机。发现问题时先去看召回质量而不是急着改提示词。5. RAG智能体从一次性检索到多轮协同5.1 什么时候该从RAG升级成智能体单次RAG适合“一个明确问题一个直接答案”。但当问题里包含多个子问题或者需要对比多个方案时一次检索无论如何都搞不定。比如“对比A和B产品的售后政策并给出选择建议”你很难在第一次检索里同时拿到A、B两套政策并完成对比。这时候需要的是RAG智能体。RAG智能体的典型架构是规划器拆解问题路由器决定查哪个知识库检索器分步获取材料阅读器汇总答案再加上记忆模块记录已经拿到的信息。它不是在RAG外面套一层壳而是把检索变成Agent可调用的工具配合多轮决策来回答复杂问题。但注意不要为了Agent而Agent。判断标准有三个问题是否能拆成多个子问题是否需要结合多个数据源是否需要在过程中做取舍决策如果三个里有两个“否”那一次RAG就够了。给简单的问答接上Agent只会换来更高的延迟和更贵的账单。5.2 用工作流而不是全自动Agent全自动Agent看着很酷但在真实企业交付里非常不可控。我建议团队优先用可编排的工作流把RAG步骤设计成固定节点节点之间用LLM做条件判断比如“这个意图要不要走知识库A”“已经检索到的信息是否足够回答”。Dify、Coze、LangGraph这类平台都能做。Dify知识库流水线有一个高频坑检索节点放在了循环外。用户每轮提问都带着新的问题变量但检索节点还是第一次运行时的问题导致第二次起答案完全对不上。正确做法是把检索节点放进循环内在每次LLM判断后重新触发检索并把当前用户query绑定到检索节点的输入。我实测下来工作流比全自动LangChain Agent稳定很多。给客户交付时工作流也能把过程讲清楚出了问题能定位到具体节点而不是在一个黑盒Agent里瞎猜。5.3 防“检索风暴”给Agent装上刹车Agent的检索不是越多越好。曾经有个客服Agent用户问“苹果保修政策”它连续检索了五次每次拿回来的文章都差不多第五次还是一年前的内容最后生成答案反而更混乱。问题不在检索能力而是Agent没有“信息足够就停下”的判断机制。给Agent装刹车有这么几件事可以做限制最大检索次数比如最多3次对相同query做缓存避免重复检索增加“信息充分度”判断节点模型判断已有材料足够时直接进入回答给工具调用加超时控制防止某个外部工具卡死。加了这些限制之后那个客服Agent一次检索就能稳定答题延迟和成本都下降了一大截。工程化的Agent从来不是工具越多越好而是越有节制越好。6. 工程落地与效果评估没有评测就没有调优6.1 本地RAG环境Mac上也能跑通全套不少人在“怎么在mac上搭建rag知识库”上踩过坑。其实本地跑一套完整RAG不难我常用的组合是Ollama负责本地生成模型和Embedding模型向量库用Chroma或LanceDB编排层用LlamaIndex或LangChain。先装Ollama拉一个嵌入模型比如nomic-embed-text或bge-m3再拉一个生成模型比如qwen2.5-7b然后在Python里用LlamaIndex几行代码就能建索引做问答。文档解析这块推荐Docling解析PDF和Wordmarkitdown轻量转MarkdownPyMuPDF做快速页面抽取配合OCRmyPDF处理扫描件。Mac上有一个很实际的痛点部分Python包没有预编译的Mac wheel安装时卡在编译环节。建议先建一个conda独立环境不要把包直接装到系统Python里遇到编译报错换Python小版本或者用conda的wheel源往往能解决。还有一个容易被忽略的点Embedding模型和生成模型是两回事。很多人只拉了一个生成模型忘记Embedding也要本地跑结果走默认配置去调云端API隐私和稳定性都受影响。6.2 评估指标与自建评测集RAGAS怎么用没有评测的RAG优化就是瞎子摸象。我今天改了chunk_size明天换了重排器效果到底变好还是变坏全靠“感觉”这不行。推荐用RAGAS这类开源评估工具。它关注两组指标检索质量里的召回率Recallk、上下文精确度Context Precision以及生成质量里的忠实度Faithfulness和答案相关度Answer Relevancy。忠实度衡量的是“回答有没有忠实于检索内容”这个指标特别能抓幻觉。实操方法是先整理50到100条真实问答作为评测集跑一个基线得分然后只改一个变量重新评估。比如把chunk_size从500改成300重排器从无到有都单独记录一次得分。最后形成一张实验表版本chunk_size检索方式重排Faithfulness召回率结论v1500纯向量无0.620.71基线v2300混合检索无0.700.82提升明显v3300混合检索bge-reranker0.780.85最终方案RAGAS依赖LLM打分打分模型本身会有偏差所以建议关键节点保留人工抽检。评测集不必大但必须覆盖真实高频提问否则测出来的分数只是自我安慰。6.3 我排查RAG问题的固定顺序项目里遇到效果不好我一般按这个顺序排查大部分问题都在前三步解决现象优先排查方向常见手段检索结果明显不相关切块、Embedding模型、索引结构改用混合检索检查切块边界检索结果相关但答案不对提示词、上下文压缩强制“只基于检索内容回答”裁剪上下文回答总是编造召回完整性、引用要求增强召回质量启用更严格引用提示表格/报销类问题总是错预处理阶段表格解析表格转Markdown/JSON保留结构同一问题多次结果不一致版本冲突、数据去重加生效日期过滤统一数据源很多人上来就想换更大的生成模型结果往往是浪费钱。绝大多数问题出在“知识准备”这一层切块不合理、检索召回低、数据冲突没治理。把这套顺序记在心里下次踩坑时就知道不是模型的锅。最后说句不该放在文档里的话。我见过太多团队在模型和框架上卷生卷死却不愿意花时间去看知识库里的原始数据。真正的分水岭从来不是谁用了最新的大模型而是谁愿意把PDF、Excel、扫描件、Wiki页面一条条处理干净谁愿意为了一个召回率的提升蹲在命令行前面看半天日志。RAG确实没有秘密但它也没有捷径。希望这篇文章里讲的六处细节能让你下次跑通流水线时心里多一根弦demo只是起点工程化才是战场。