上个月我帮一家做行业分析报告的团队调 RAG 检索,他们用最标准的“文档切块 + 向量化 + 相似度检索”流程搭了一套知识库,几百份 PDF 都在里面,表面上一切正常。真正提出需求后立刻露馅:业务方问“2023 版和 2024 版两期报告里,某个客户的营收数据为什么对不上”,系统同时把两份文档的相关段落捞出来,生成器照着拼接,答案里两个数字各说各话。这种问题我见过很多次,它不是模型不够智能,而是 RAG 管道本身没设计到位。也正因为这样,我才策划了《RAG进阶实战》这个专栏。
这个专栏不聊 LangChain 怎么安装,不教 Prompt 模板怎么写,只聚焦一个问题:基础 RAG 在真实业务里跑不动的时候,你到底该怎么升级。这篇文章相当于专栏开篇,我会把策划思路、关键技术判断、Mac 上从零搭 RAG 知识库的完整过程,一次性讲清楚。适合刚学完 RAG 教程、一上手复杂业务就蒙圈的开发者,也适合团队里正在纠结要不要上知识图谱、要不要做多模态的负责人。
1. 先从瓶颈说起:进阶实战到底要解决什么问题
很多 RAG 教程最大的问题在于把整个链路讲得太顺了:读文档、切块、embedding、存入向量库,然后 query 进来一检索,答案就出来了。等你真拿业务数据跑一遍,会发现这套流程只在 demo 里成立。所以我先聊聊瓶颈,因为进阶实战本质上就是围绕瓶颈做升级。
基础的“文档切片 + 向量检索 + 生成”只是入门,真实业务场景中几乎必然遇到三类致命问题:召回质量、上下文窗口、生成置信度。只有先把这些瓶颈具象化,后面的知识图谱、结构化知识库、多模态改造才有意义。
1.1 基础 RAG 的三个致命瓶颈
第一个瓶颈是召回质量。向量检索本质上是在算文本语义的相似度,适合处理“意思相近”的模糊匹配。但业务里大量查询是需要精确匹配或者逻辑推理的,比如“订单号为 ABC-123 的物流轨迹”“与 A 公司存在供应关系的所有二级供应商”,这种查询里实体和关系才是关键,单纯靠相似度排序很容易把不相关的段落排进来,却把真正包含答案的段落漏掉。
第二个瓶颈是上下文窗口。模型输入有长度限制,你不可能把所有检索结果都塞进去。检索一堆段落之后,还得做筛选、压缩、重排,这个过程做得不好,正确答案会被淹没在不相关信息里。更现实的是成本问题,窗口越用越大,API 费用也飞快上涨,业务部门可不会因为你“用了长上下文”就给你加预算。
第三个瓶颈是生成端的置信度问题。大模型在生成时可能忽略检索到的内容,也可能把不同来源的冲突信息“混编”成一段看起来合理的话。开头那个营收口径不一致的问题就是这么来的。这个问题用户感知很强,因为答案只要出过一次错,他们对整个知识库的信任就崩了。
1.2 我在项目里见到的瓶颈“真面目”
我参与过的项目里,最典型的是多跳查询。比如“客户 A 的项目使用了哪些由供应商 B 提供的设备型号”,答案散落在订单表、项目文档和产品手册三个地方,分别检索能捞到一堆片段,但没法把它们按逻辑关系串起来。基础 RAG 对单点事实查询还行,对这类需要跨文档推理的多跳问题,基本无能为力。
还有术语对齐问题。同一家公司在不同年份的报告里可能叫“A 公司”“A 集团”“AAA”,不同的叫法在向量空间里虽然有一部分相似,但很难稳定对齐。尤其是中文材料里,简写、全称、英文名交替出现是常态。再往下是结构化数据读取,财报里的表格、ERP 导出的明细,一旦被切成文档块,行列关系就丢了,“第三行第二列是多少”这种问题怎么可能答得对。
这三个现象合在一起,会让团队得出一个焦虑结论:是不是模型不行,是不是得换个更大的模型。我的经验是,大多数情况下先别急着换模型,先把知识组织方式改对,效果提升往往比换模型更明显。
1.3 为什么知识图谱是进阶的第一站
因为 RAG 的瓶颈本质上都是“知识组织方式”的问题,所以知识图谱(KG)才会成为进阶的第一站。这里说的 KG 不是简单的关系表,而是把实体、属性、关系显式建模成一个图,例如“客户 A——采购——设备 B”。这个结构天然支持精确匹配和路径查询,多跳问题在图上就是一次路径搜索,根本不需要模型去“猜”。
但我要强调一点:KG 和向量检索不是二选一。向量检索擅长模糊语义匹配,KG 擅长精确关系推理,两者是互补的。比较成熟的方案是混合架构:先用向量召回一批候选文档,再用知识图谱做实体消歧、关系扩展或候选重排。RAG 的热度这几年一直没降,是因为大家都在往这个方向卷,而卷的核心不是模型参数,而是知识怎么组织。
2. 向量知识库、知识图谱、结构化知识库:别再混为一谈
很多同学看着“rag知识库”“kg知识库”“结构知识库”这三个词就发懵。其实它们根本不是一个维度上的东西。先把这个搞明白,后面的技术选型才有意义。
2.1 一张表看懂三类知识库的定位
我直接用表来说明。这能帮你快速判断每个词在别人文章里到底指的是什么。
| 类型 | 存储单元 | 检索方式 | 擅长场景 | 典型局限 |
|---|---|---|---|---|
| 向量知识库 | Embedding 向量 | 相似度检索(Top-K) | 非结构化文本的语义召回 | 精确匹配差,多跳推理弱 |
| 知识图谱 | 实体、关系、属性 | 图查询(路径遍历) | 多跳查询、关系推理、可解释性 | 构建成本高,本体设计复杂 |
| 结构化知识库 | 表格/行列数据 | SQL/索引查询 | 明细查询、聚合统计、精确更新 | 需要事先定义好 schema,灵活性一般 |
所谓“rag知识库”,业界通常默认指向量知识库,因为大多数 RAG 教程就是拿它演示的。但从定义上讲,RAG 的“知识来源”可以是任何一种形态,数据放在 PostgreSQL、MongoDB、图数据库里,只要检索模块能查出来,它就能参与 RAG。所以你不该问“我该用哪种知识库”,而该问“我这个场景下的数据,最适合被哪种检索方式命中”。
2.2 选型判断:什么时候用向量、什么时候用图
我的判断框架是四个问题走一遍。第一,业务问题形态是什么:事实问答、意图匹配,还是关系推理、路径查询?第二,数据本身的结构化程度怎么样:是自由文本、表格,还是带大量外键关联的实体关系?第三,数据更新频率和一致性要求高不高:知识图谱新增实体成本高,结构化库更新最自然。第四,答案需不需要可解释:用户问“为什么是这个结论”,图上的路径能直接展示,向量检索只能给你“因为相似度高”。
按这个框架,客服 FAQ 面向的是用户意图匹配,非结构化文本为主,首选向量知识库。供应链风控、供应商尽调、主数据治理这类场景,关系是关键,知识图谱的价值立刻体现。财务明细、订单查询、价格维护这种行级数据,用结构化库加 SQL 更靠谱,硬塞进 RAG 反而是给自己找麻烦。
还有一个常用套路:同一套数据同时进向量库和图库。向量库负责粗召回,图库负责精排和路径推导。这听起来复杂,但具体落地时只是一条检索引擎里多串一个查询而已,数据量不大的项目,一周内就能搭出原型。
2.3 本体论在 RAG 里的真正作用
最近“ontology rag”这个词出现频率很高,我第一次看到也愣了一下,后来发现它其实解决了一个很实在的问题:给知识库定义了一套共享的概念和关系约束,检索和生成都能在这个框架里对齐。和普通 schema 相比,本体更强调概念层级、关系语义和推理规则。比如“供应商”是一种“组织”,“采购订单”连接“供应商”和“产品”,这些约束会让系统在收到“某某的客户是谁”时,知道去查采购或销售关系,而不是瞎匹配。
但这东西有个前提:构建本体需要领域专家深度参与,不是程序员拍拍脑袋就能定义的。我看到不少团队兴冲冲上 ontology,结果建出来的本体跟业务对不上,反而限制了召回。我的建议是,如果只是想优化精确召回,先把实体识别和关系提取做好,再逐渐补本体的层级约束,不要一上来就全局建模。
3. 多模态内容进 RAG:知识库到底能不能存图片
这个问题我基本每周都会被问一次。我直接说结论:能,而且有几个经过验证的路线,但大部分团队把问题想简单了。
3.1 先回答:图片能不能存进 RAG 知识库
能,但前提是你得想清楚“检索时拿什么去匹配”。向量数据库里存的是向量,不是图片本体。图片本身没有文本语义,你需要先把它转成某种能被检索的形式。如果你只是把图片塞进对象存储、把路径记在文档里,那不算知识库,只是文件归档。RAG 知识库存图片,本质上回答的是“用户用文字提问,系统怎么找到并利用这张图片里的信息”。
所以图片进知识库,核心矛盾是“检索文本”和“图片内容”之间的桥梁怎么搭。选不同的桥梁,就对应了不同的技术路线。
3.2 三种图片入库方案,实测各有取舍
第一种是 OCR 转文字。图片里如果主要是文字,比如扫描件、截图、带批注的表格照片,OCR 提取出的文字可以直接走普通的文本切块和向量化流程。优点是不需要额外引入新的向量模型,缺点是表格类图片经过 OCR 后行列结构会丢,纯图表里的趋势信息也完全提取不出来。
第二种是视觉向量化。用 CLIP 这类图文对齐模型把图片整体编码成向量,存进向量库,查询时把用户文本也编码成同一向量空间。这种方案适合“按内容找图”的场景,比如找“公司年会上有红色背景的合影”,CLIP 的表现明显比 OCR 好。但在 Mac 本地环境跑视觉模型,显存压力比纯文本模型大不少,我建议先评估硬件再动手。
第三种是图像描述生成。让多模态模型先看一遍图,生成一段结构化描述,再把描述文本进向量库。严格来说它走的是文本链路,检索到描述后,你可以选择只返回描述文本,也可以把原图作为附件一起返回给用户。这是我目前最推荐上线起步的方案,因为兼容原有的文本 RAG 管线,检索效果也足够可控。
整个对比我整理成一张表,方便直接抄。
| 方案 | 适用图片 | 成本 | 检索准确度 | 备注 |
|---|---|---|---|---|
| OCR 转文字 | 文字型截图、扫描件 | 低 | 中,容易丢结构 | 表格图片慎用 |
| CLIP 视觉向量 | 需要按语义找原图 | 较高 | 中高 | 本地硬件要求高 |
| 图像描述生成 | 通用内容图片 | 中等 | 高,取决于描述质量 | 描述生成后走文本链路 |
3.3 我的取舍:文本链路优先,多模态别着急
如果你正在做知识库的初期版本,我强烈建议先把文本链路做到稳定,再考虑多模态。我踩过的坑是:为了“显得先进”,短期内把图片、音频、视频全塞进去,最后发现检索模块越来越复杂,效果却不好。真实业务里,高频查询通常还是集中在文本上,先让用户在这些高频场景里获得稳定体验,比什么都强。
图片如果真的重要,就用第三种方案,先让模型批量生成描述,人工抽样检查描述质量,再进向量库。视频和音频也是同理,先抽帧、先转写,再走文本链路。等这套流程稳定了,再尝试视觉向量化做补充召回。这个顺序能帮你少走弯路。
4. Mac 上搭建 RAG 知识库:从选型到跑通第一轮检索
搭一套能在 Mac 上跑的 RAG 知识库,对开发者和产品经理来说都是很有价值的试验田。这篇我直接给出我实测过、可以抄的一套方案。
4.1 选型不纠结:本地模型、API 和框架怎么定
在 Mac 上跑本地模型,首选 Ollama。它基于 llama.cpp,对 Apple Silicon 的 Metal 加速支持很好,M 系列芯片跑 7B、8B 量级的中文模型都很流畅,不用自己折腾编译环境。如果数据比较敏感,或者你就是想离线跑,这条路最省心。如果公司有预算、也不在意数据出内网,直接用云端 API 效果更稳定,但注意敏感数据不要送外。
框架方面,我建议用 LlamaIndex 起步,它对 RAG 概念的抽象更直接:文档加载器、节点解析器、索引结构、检索器,层层分明,很适合新手理解全链路。LangChain 的集成度更高,但组件太多,调试时容易绕晕。向量库我先用了 Chroma,纯本地、零运维,数据量几十万条以内完全够用。
4.2 实操步骤:用 LlamaIndex 在 Mac 上跑通第一轮检索
环境准备。装 Python 3.10,终端里建虚拟环境,避免污染系统 Python。
mkdir rag-demo && cd rag-demo python3 -m venv .venv source .venv/bin/activate pip install llama-index chromadb ollama装好 Ollama 后,拉一个适合中文场景的模型,比如 qwen2.5:7b,然后启动服务:
ollama pull qwen2.5:7b ollama serve准备几篇真实业务文档当作测试数据。我建议用 Markdown 或 PDF,先放十篇以内,控制在几万字,方便定位问题。然后在同一个目录里写一个脚本,把文档加载、切块、向量化、建索引的流程跑通。
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.core.node_parser import SentenceSplitter from llama_index.embeddings.ollama import OllamaEmbedding from llama_index.llms.ollama import Ollama import chromadb Settings.llm = Ollama(model="qwen2.5:7b", request_timeout=120.0) Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text") documents = SimpleDirectoryReader("./data").load_data() parser = SentenceSplitter(chunk_size=512, chunk_overlap=64) nodes = parser.get_nodes_from_documents(documents) chroma_client = chromadb.PersistentClient(path="./chroma_db") collection = chroma_client.get_or_create_collection("demo") vector_store = ChromaVectorStore(chroma_collection=collection) index = VectorStoreIndex(nodes, vector_store=vector_store)查一句试试。比如数据里有一份产品手册,就问“产品的保修期是多少个月”,观察返回内容和答案生成质量。
query_engine = index.as_query_engine(similarity_top_k=5) response = query_engine.query("产品的保修期是多少个月") print(response)这一步跑通,说明 Mac 上的 RAG 最小可行性链路已经成立。第一次跑的时候别急着加功能,先看返回的检索片段是否符合业务直觉,再进入参数调优阶段。
4.3 参数配置表:这些值我建议你直接抄
第一次跑通后,别急着加功能,先理解几个关键参数。我把我常用的一组配置整理成表。
| 参数 | 建议值 | 我的解释 |
|---|---|---|
| chunk_size | 256-512(中文可取 256) | 太小信息割裂,太大会稀释语义 |
| chunk_overlap | 64-128 | 保留跨块上下文,尤其是中文段落 |
| embedding 模型 | nomic-embed-text / bge-small-zh | 中文场景优先试 bge 系列 |
| LLM 温度 | 0.1 左右 | 知识问答追求确定性,调低 |
| similarity_top_k | 5 左右起步 | 太少漏答案,太多噪声多,建议先压到 5 再观察 |
你可能觉得 512 太小,毕竟现在模型上下文都很大了。但注意,切块大小影响的是检索粒度,不是生成上限。块越小,召回时能命中的精细信息越多,但上下文质量也可能变差。所以正确做法不是塞更多,而是让检索器把真正相关的块找出来。建议每次只改一个参数,记录效果,不要同时动好几处再回头看。
4.4 混合检索和重排序:召回率低时先做这两件事
基础链路搭好后,最常遇到的问题就是召回不理想。我的第一反应不是调 embedding 模型,而是先上混合检索。BM25 做关键词精确匹配,向量做语义匹配,两者结果合并去重。LlamaIndex 里可以直接挂 Hybrid 检索,或者用自定义检索器把 Chroma 和本地 BM25 结果加起来。关键词数字、编号这类信息,BM25 命中能力远强于向量。
召回做宽之后,再用重排序模型把关。bge-reranker 这类模型会把检索到的候选逐条打分,和查询的相关性高于普通相似度计算。加一个 rerank 环节,往往能让答案质量有肉眼可见的提升,尤其在候选里混着相似但不相关的段落时。这个模块虽然多花几十毫秒延迟,但在业务系统里值得付这个代价。
5. 进阶 RAG 框架拆解与调试思路
很多人的 RAG 框架认知停在“检索 + 生成”,但在进阶实战里,框架应该被拆成更细的模块,否则出了问题你都不知道去哪个环节排查。
5.1 RAG 框架的五模块拆解
我把一个可维护的 RAG 框架拆成五段:加载器负责解析各类源文件,可能有 PDF、Word、数据库、网页;索引器负责切块、清洗、向量化、存储;检索器负责接收查询、调用向量检索或混合检索、返回候选;后处理器负责去重、重排、压缩、过滤;生成器负责把最终上下文和问题一起交给 LLM 生成答案。
除了这五段,进阶项目基本都会有路由器和查询改写器。路由器按查询意图把请求分发给不同检索源,比如普通问题走向量库,关系型问题走图数据库。查询改写器负责把“它去年采购了哪些”改写为带完整上下文的查询,在多轮对话里必不可少。理解了这些模块,你再看不同框架的代码时会发现,它们无非是在这些环节里做了不同的封装和取舍。
5.2 调试链路:如何快速判断问题出在召回还是生成
我见过太多团队一遇到生成错误,就疯狂调 Prompt。正确的做法是先看召回是否命中了正确答案。调试时我会把检索器单拎出来,打印每个候选的得分和来源,人工判断正确答案在不在 Top 5 里。如果不在,是召回问题,该调 embedding、切块策略或混合检索;如果在,答案还是不对,才是 Prompt 或者生成参数问题。
为了系统化判断,我建议项目一开始就建一个小的评估集,包含 50 到 100 条典型问题,每条标注出参考回答和正确答案所在文档。跑一轮,统计召回命中率和相关度。这个动作成本不高,但能防止你“凭感觉调参”。等量级上来之后,可以再引入 RAGAS 这类自动化评估工具,但我始终认为人工评估集才是地基。
5.3 从 RAG 到 Agent:什么时候值得升级
“RAG 框架”这个词最近常和 Agent 绑在一起。把 RAG 封装成一个工具,塞进 ReAct 循环的 tool 列表里,让模型决定什么时候查、查几轮,这是合理的进阶方向。但我要泼一盆冷水:不是所有业务都需要 Agent 化。单一知识库、单轮事实问答,检索一次就够了,引入 Agent 反而增加延迟和不确定性。
如果业务确实是多工具协作类型,比如“用户的诉求同时涉及知识库查询、日历排期、邮件发送”,Agent 的优势才会显现。此时知识库需要提供两个接口:接受改写后的查询,而不是只能接收原始用户问题;同时返回结构化的来源信息,让 Agent 能追踪证据。我见过不少团队把 RAG 升级成多智能体,最后因为排查链路太长而崩溃,所以在没有明确需求之前,守住“RAG + 工具调用”这个最小边界,比造一个复杂编排系统更稳妥。
6. 踩坑实录:我在 Mac 和线上环境遇过的真实问题
最后一部分,我把这几年最常遇到、也最值得写下来的问题整理一下。这些问题不是教科书里会写的,但你大概率会撞上。
6.1 问题速查表:按现象直接排查
| 现象 | 原因 | 我的解决办法 |
|---|---|---|
| PDF 解析后出现乱码 | 部分扫描件没有文本层 | 先 OCR,再走文本链路;别指望 PDF 库全自动 |
| 检索召不回精确编号 | 向量检索对数字/编号不敏感 | 上 BM25 混合检索,或加一层规则匹配 |
| Mac 跑索引时内存占用暴涨 | Ollama + Chroma + Embedding 同时跑 | 把 embedding 模型换小,限制 Chroma 缓存,跑大索引分批 |
| 中文效果明显差于英文 | 默认 embedding 模型偏英文 | 换成 bge-small-zh 等中文模型,切块策略按中文调 |
| 用户问题带指代,答非所问 | 未做会话记忆和查询改写 | 加 query rewrite,把“它”替换为完整实体 |
| 答案引用了过期信息 | 文档版本未管理 | 导入时记录 source 属性和更新时间,检索时按版本过滤 |
6.2 四条最值得的避坑经验
第一,数据清洗永远比模型调参重要。我在多个项目里验证过,同一套模型,文档质量不同,效果天差地别。去水印、去页眉页脚、修正错误编码、拆分目录和正文,这些事情看着琐碎,但回报率极高。
第二,不要一上来就追求多模态或知识图谱。先把纯文本链路压榨到极限,你才能准确判断瓶颈在哪。很多“必须上 KG”的判断,其实是文本召回没做好造成的误诊。
第三,建立评估集是投资回报率最高的事。哪怕只有几十条问题,只要标注了正确答案所在位置,你每次改动都能快速知道是变好了还是变糟了,这比任何华丽的框架都管用。
第四,在 Mac 上做实验时,注意资源配比。我习惯一个终端跑 Ollama,另一个跑索引脚本,随时查看内存占用。如果索引时崩溃,优先把 embedding 模型切换到小尺寸版本,而不是加内存。
最后说句实在话,做了这么多 RAG 项目,我最大的体会是:RAG 的瓶颈往往不在模型,而在我们对数据的理解和组织方式。别急着上多模态、别急着上知识图谱,先把文本链路调通,把评估集建起来,你就能超过大多数团队。这个专栏策划案的后续,我也会按主题拆成系列文章去写:知识图谱构建、多模态召回、Agent 化改造,现在先有了第一期的完整路线图。如果你正准备做 RAG 知识库,我的建议是从一个小数据集开始,走一遍 4.2 节那条路径,用评估集记录效果,再逐步叠加模块。这条路我替你走过,不会白走。