00-RAG系列开篇:从“接个向量库”到一套证据系统
这个系列是重新梳理RAG流程与在每一个流程中的问题与解决,对于具体的技术实现不会写的很细。
00-RAG系列开篇:从“接个向量库”到一套证据系统
这个系列是重新梳理RAG流程与在每一个流程中的问题与解决,对于具体的技术实现不会写的很细。
第一次接触 RAG,很容易把它理解成一件很简单的事:
把文档切一切,转成向量,丢进向量数据库,用户提问时检索一下,再把结果塞给大模型。
这个理解不能算错。它确实能跑通一个最小 demo,也能解释 RAG 最表层的工作方式。但如果把 RAG 只理解到这一步,后面很快就会遇到一串更真实的问题:
- 文档明明在知识库里,系统却检索不到。
- 检索结果看起来相关,大模型还是答非所问。
- topK 塞得越多,答案反而越乱。
- 业务文档已经更新,旧答案却仍然被引用。
- 明明接了 RAG,模型还是会编。
这些现象都指向同一个事实:
RAG 更准确地说,是一套围绕证据构建的工程系统。“向量数据库 + 大模型”只能解释它的最小 demo,解释不了真实系统里的稳定性问题。
如果说大模型负责表达、推理和生成,那么 RAG 要负责的是证据。证据从哪里来,怎样进入知识库,怎样被检索出来,怎样排序,怎样组织成上下文,怎样约束模型基于证据回答,怎样评测效果,怎样随业务知识更新而更新,这些才是 RAG 真正难的地方。
RAG 的最小定义
RAG 是 Retrieval-Augmented Generation,通常翻译为检索增强生成。
它的基本思路并不复杂:
- 用户提出问题。
- 系统先从外部知识库中检索相关资料。
- 把用户问题和检索到的证据一起交给大模型。
- 大模型基于这些证据生成答案。
用一条链路表示,大概是这样:
用户问题
-> 查询理解 / 查询改写
-> 向量检索 / 关键词检索 / 元数据过滤
-> 多路召回 / 排序 / Rerank
-> 上下文整理 / 去重 / 压缩 / 引用编号
-> 大模型基于证据生成答案
-> 返回答案、引用来源、日志和反馈
这个流程里,大模型会在回答前拿到一批外部证据。所以,RAG 解决的核心问题可以理解为:让模型在回答时拿到正确知识,而不是把所有知识都写进模型参数。
这个区别很重要。微调是把某些能力、风格或任务习惯写进模型参数里;RAG 是在推理时动态补充外部知识。前者更像改模型本身,后者更像给模型配一套可检索、可更新、可追溯的资料系统。
| 方式 | 更像是在做什么 | 适合解决什么 |
|---|---|---|
| 微调 | 改模型本身 | 能力、风格、任务习惯 |
| RAG | 给模型配资料系统 | 外部知识、引用来源、动态更新 |
也正因为如此,RAG 更适合那些知识变化快、来源多、权限复杂、需要引用来源的场景,比如企业知识库、产品文档问答、客服知识库、制度查询、代码库问答、论文资料检索。它们的共同点是:知识不适合一次性塞进模型参数里,而应该保留在外部系统中,按需检索、按权限使用、按版本更新。
RAG 难的不是调用模型
很多 RAG demo 看起来很顺:
加载文档 -> 切分 chunk -> 生成 embedding -> 存入向量库 -> 检索 topK -> 调用大模型
但真实系统的问题不会这么规整。一个可用的 RAG 系统,难点往往分布在模型调用前后,而不是模型调用本身。
更准确地说,RAG 的难点会分布在几层:入库前要关心文档是否干净、结构是否保留、metadata 是否完整;检索时要关心正确证据能不能被召回、能不能排到前面;生成前要关心上下文是否去重、压缩、排序、处理冲突;生成后还要关心答案是否忠实证据、是否可引用、是否可排查。
文档进入知识库之前,质量就已经被决定了一半
RAG 的第一步更应该放在文档处理上,而不是急着进入向量化。
真实文档往往并不干净。PDF 可能有多栏、页眉页脚、脚注和表格;扫描件需要 OCR,而 OCR 可能带来错字和断行;网页里可能混着导航、广告和推荐内容;代码文档需要保留函数、类、模块之间的结构;企业文档还经常带有版本、部门、权限、发布时间和适用范围。
如果文档解析阶段已经把标题层级弄乱、把表格结构打散、把无关噪声混进正文,后面的 embedding 和检索很难完全补救。
所以 RAG 的第一层能力首先体现在:
能不能把原始资料整理成干净、结构清晰、带有元数据的知识单元。
这里的 metadata 很关键。它不只是附属字段,而是后面做过滤、权限控制、排序、引用、版本管理的重要依据。
| 信息 | 在 RAG 里的作用 |
|---|---|
| 原文 | 负责给模型读 |
| 向量 | 负责让系统找 |
| metadata | 负责让系统知道内容来自哪里、适用于谁、是否过期、能不能被当前用户看到 |
Chunking 不是随便切文本
文档不能整篇直接塞进向量库。一方面,embedding 模型有输入长度限制;另一方面,整篇文档压成一个向量后,细节语义会被稀释,检索粒度也会变得太粗。
所以需要 chunking,也就是把文档切成更小的知识块。
但 chunking 不是简单按字数切开。它的几个典型取舍可以放在一起看:
| 取舍 | 常见问题 |
|---|---|
| chunk 太大 | 混入多个主题,向量表达不够聚焦,召回后噪声更多 |
| chunk 太小 | 语义不完整,模型拿到的是片段,不知道前因后果 |
| overlap 太大 | 索引膨胀,重复召回变多,成本上升 |
这也解释了实际项目里为什么会出现固定长度切分、标题层级切分、语义边界切分、父子 chunk、Late Chunking 等不同策略。表格要尽量保留结构,代码更适合按函数、类或模块切分。所有这些取舍背后的问题,其实都是同一个:
如何在检索粒度和语义完整性之间取得平衡。
向量检索不是万能搜索
RAG 里最容易被神化的是向量检索。
向量检索很强。它能把文本映射到语义空间里,让表达不同但含义接近的内容能够互相匹配。比如用户问“怎么重置密码”,文档里写的是“忘记登录凭证时的账户恢复流程”,向量检索就可能比关键词检索更容易找到。
但向量检索并不万能。精确编号、产品型号、人名地名、专有名词、短查询、强关键词匹配,以及需要版本、时间、权限等结构化过滤的查询,都可能让纯向量检索不够稳定。
所以生产系统里经常不会只查一次向量库,而是把 BM25 关键词检索、metadata filter、Hybrid Search、Query Rewrite、多路召回、RRF 结果融合和 Rerank 精排组合起来。RAG 从 demo 走向生产时,一个明显变化就是:检索不再是一次查询,而是一套召回、融合、排序和过滤策略。
检索到了,不代表模型就能用好
即使正确文档已经被召回,答案也未必正确。
正确 chunk 已经被召回以后,仍然可能排名太靠后,被上下文截断;topK 里可能有重复内容,占用了窗口;多个 chunk 之间可能互相冲突;过期文档和新文档可能同时出现;上下文太长时,模型还可能忽略中间位置的关键证据。更常见的是,Prompt 没有明确要求模型基于证据回答,于是模型开始补全缺失信息。
所以 RAG 里还有一层很关键的工作:上下文工程。
检索结果不能机械地塞给模型,而是要经过去重、排序、压缩、截断、引用编号、冲突处理和证据匹配检查。Rerank 也通常出现在这一层:召回阶段更重视“别漏掉”,Rerank 阶段更重视“排得准”。
这时可以把 RAG 的在线链路拆成三句话:
召回决定正确证据有没有到场。
Rerank 决定正确证据能不能排到前面。
上下文工程决定正确证据能不能被模型有效使用。
这比简单说“RAG 就是检索增强”更接近真实系统。
RAG 不能自动消灭幻觉
RAG 经常被用来减少大模型幻觉,但它不能保证幻觉消失。
幻觉可能发生在不同层。检索层没有找到正确证据,排序层把错误证据排在前面,上下文里混入噪声或冲突信息,模型没有严格基于证据回答,或者问题本身超出了知识库覆盖范围但系统没有拒答,都会导致最终答案出错。
所以,减少幻觉不能只靠一句 Prompt。更完整的做法是把召回质量、Rerank、上下文过滤、引用来源、低置信度拒答、答案一致性检查、评测集和失败样本回流放在一起看。
RAG 的价值不在于让系统永远不犯错,而在于让错误有链路可查。如果回答错了,可以沿着“文档是否入库、chunk 是否切坏、embedding 是否召回、topK 是否包含正确证据、Rerank 是否排上来、上下文是否被污染、模型是否按证据回答”这条链路逐层排查。
能这样定位问题,RAG 才从“魔法问答”变成了可调试的工程系统。
生产级 RAG 还要面对更新、权限和评测
demo 里的知识库通常是静态的,真实业务不是。
文档会新增、修改、删除。制度会更新,产品会迭代,接口会废弃,FAQ 会变化。知识库如果不能动态更新,就会持续输出过期答案。
更新本身也不只是“重新入库”这么简单。系统需要识别文档变化,删除旧 chunk,处理 embedding 模型升级后的向量空间变化,应对 chunk 策略调整带来的重建成本,还要支持索引版本、灰度切换、回滚、权限过滤、日志和审计。
同时,RAG 效果也不能靠感觉判断:
| 维度 | 常见关注点 |
|---|---|
| 检索层 | Hit@K、Recall@K、MRR、NDCG |
| 生成层 | Faithfulness、Answer Relevancy、Context Precision、Context Recall |
| 线上体验 | 点踩率、追问率、转人工率、引用点击率 |
| 工程成本 | 延迟、资源消耗、调用成本 |
失败样本应该沉淀为 Golden Set,持续回放,持续优化。
这些内容听起来离“写一个 RAG demo”有点远,但它们决定了 RAG 能不能在真实场景里持续工作。
这个系列怎么写
这个系列会按 RAG 的工程链路往下拆。
它会提到 LangChain、LlamaIndex 或某个向量数据库的 API,但框架和工具不会成为主线。主线是理解 RAG 背后的工程问题:适用边界、文档入库、chunk 策略、embedding 和向量索引、在线检索链路、Query Rewrite、Hybrid Search、多路召回、Rerank、上下文工程、幻觉治理、效果评测、知识库更新,以及 GraphRAG、Self-RAG、CRAG、Agentic RAG 这些范式出现的原因。
每篇尽量围绕一个核心判断展开,而不是堆概念。
更重要的是,每篇都要把一个问题放回完整链路里看。因为 RAG 的很多问题不能单点解决。检索效果差,可能是 chunk 问题,也可能是 query 或索引问题;答案不忠实,可能是上下文组织问题,也可能是生成约束问题;系统延迟高,可能是召回源过多、Rerank 成本过高,也可能是索引参数不合理。
真正理解 RAG,应该能沿着链路定位问题。
小结
RAG 看起来是大模型应用里最常见的一类方案,但它并不简单。
一个可用的 RAG 系统,最终依赖整条证据链,而不只是某一次模型调用:
文档治理
-> chunk 与 metadata
-> embedding 与索引
-> 检索与召回
-> Rerank 与上下文工程
-> 证据约束下的生成
-> 评测、更新、权限和回滚
所以,RAG 的核心在于让模型回答时拿到正确、干净、可追溯、权限合规的证据。
后面的文章,就围绕这条证据链逐层拆开。