这两年聊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而异,需要每类模板做验证。
扫描件必须先过OCR,OCR错字会影响检索命中,所以要把OCR后的文本和原文页码绑定,方便后面溯源。多级标题也是麻烦点,很多长文档有章节嵌套,平铺切块会把“1.2.3”这种层级的上下文丢掉。建议先构建文档树,采用父子块策略:用小块去匹配query,命中后取它对应的父块或整节送去生成,保证信息完整。
一句话总结:预处理决定RAG的上限,模型只是在下限之内发挥。真正的分水岭,在文档还没进向量库之前就已经开始分开了。
2. 检索策略才是召回质量的分水岭
2.1 纯向量检索为什么总差一口气
向量检索这个技术本身没问题,但它有一个天然短板:擅长语义相似,不擅长精确匹配。用户问“编号A310的保修条款”,向量检索可能召回一堆“B310”“C310”的类似文本,而精确的A310条目反而被埋在后面。这不是模型笨,而是稠密向量对特定词、数字、型号这些精确标识不敏感。
很多项目的RAG瓶颈不在生成,而在召回这一步。你召回的Top 5里只有1条是真正有用的,后面接入任何大模型都很难给你满意的回答。我见过好些团队把问题归咎于“模型不行”,换了更大的模型效果还是上不去,最后回头检查才发现是检索阶段就漏了瓜。
解法其实不复杂:混合检索。向量检索跑一遍语义相关内容,BM25全文检索跑一遍精确关键词匹配,再用RRF或加权分数融合排序。LangChain里可以用QueryFusion,Dify里直接在检索设置里选“混合检索”。我个人的建议是,不管用什么框架,第一时间先把混合检索接上,别裸用向量。
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和Word,markitdown轻量转Markdown,PyMuPDF做快速页面抽取,配合OCRmyPDF处理扫描件。Mac上有一个很实际的痛点:部分Python包没有预编译的Mac wheel,安装时卡在编译环节。建议先建一个conda独立环境,不要把包直接装到系统Python里;遇到编译报错,换Python小版本或者用conda的wheel源往往能解决。
还有一个容易被忽略的点:Embedding模型和生成模型是两回事。很多人只拉了一个生成模型,忘记Embedding也要本地跑,结果走默认配置去调云端API,隐私和稳定性都受影响。
6.2 评估指标与自建评测集:RAGAS怎么用
没有评测的RAG优化,就是瞎子摸象。我今天改了chunk_size,明天换了重排器,效果到底变好还是变坏,全靠“感觉”,这不行。
推荐用RAGAS这类开源评估工具。它关注两组指标:检索质量里的召回率(Recall@k)、上下文精确度(Context Precision),以及生成质量里的忠实度(Faithfulness)和答案相关度(Answer Relevancy)。忠实度衡量的是“回答有没有忠实于检索内容”,这个指标特别能抓幻觉。
实操方法是先整理50到100条真实问答作为评测集,跑一个基线得分,然后只改一个变量重新评估。比如把chunk_size从500改成300,重排器从无到有,都单独记录一次得分。最后形成一张实验表:
| 版本 | chunk_size | 检索方式 | 重排 | Faithfulness | 召回率 | 结论 |
|---|---|---|---|---|---|---|
| v1 | 500 | 纯向量 | 无 | 0.62 | 0.71 | 基线 |
| v2 | 300 | 混合检索 | 无 | 0.70 | 0.82 | 提升明显 |
| v3 | 300 | 混合检索 | bge-reranker | 0.78 | 0.85 | 最终方案 |
RAGAS依赖LLM打分,打分模型本身会有偏差,所以建议关键节点保留人工抽检。评测集不必大,但必须覆盖真实高频提问,否则测出来的分数只是自我安慰。
6.3 我排查RAG问题的固定顺序
项目里遇到效果不好,我一般按这个顺序排查,大部分问题都在前三步解决:
| 现象 | 优先排查方向 | 常见手段 |
|---|---|---|
| 检索结果明显不相关 | 切块、Embedding模型、索引结构 | 改用混合检索,检查切块边界 |
| 检索结果相关但答案不对 | 提示词、上下文压缩 | 强制“只基于检索内容回答”,裁剪上下文 |
| 回答总是编造 | 召回完整性、引用要求 | 增强召回质量,启用更严格引用提示 |
| 表格/报销类问题总是错 | 预处理阶段表格解析 | 表格转Markdown/JSON,保留结构 |
| 同一问题多次结果不一致 | 版本冲突、数据去重 | 加生效日期过滤,统一数据源 |
很多人上来就想换更大的生成模型,结果往往是浪费钱。绝大多数问题出在“知识准备”这一层:切块不合理、检索召回低、数据冲突没治理。把这套顺序记在心里,下次踩坑时就知道不是模型的锅。
最后说句不该放在文档里的话。我见过太多团队在模型和框架上卷生卷死,却不愿意花时间去看知识库里的原始数据。真正的分水岭从来不是谁用了最新的大模型,而是谁愿意把PDF、Excel、扫描件、Wiki页面一条条处理干净,谁愿意为了一个召回率的提升蹲在命令行前面看半天日志。RAG确实没有秘密,但它也没有捷径。希望这篇文章里讲的六处细节,能让你下次跑通流水线时,心里多一根弦:demo只是起点,工程化才是战场。