很多同学在搭建 RAG 知识库的时候都会有一个误区,那就是:只要把公司文档扔进向量数据库,再让大模型根据检索结果回答问题,一个企业知识库就算完成了。
这是完全不对的。
最近有部分同学就遇到了这样的情况。
我总结了一下,大致可以分为以下 4 种:
- 第一:知识库里明确存在的信息,但是模型找不到
- 第二:知识库里不存在的信息,模型会出现幻觉
- 第三:好不容易搜到了信息,但却是旧的规则
- 第四:资料明确需要人工审核的信息,模型却说会自动完成
那么这些问题到底是什么原因导致的呢?
咱们一点点来看。
RAG 并没有让模型学会你的资料
先把 RAG 的基本原理捋一下。
大模型原本不知道公司的内部规则、业务资料和产品文档。
RAG 要做的事情,就是在模型回答问题之前,先从知识库里找出与用户问题相关的资料,再把这些资料放进当前请求的 Context 里。
整个过程大概是这样的:
所以,RAG 本身是没有把公司的资料重新训练到模型里面的。
它只是每次回答问题之前,临时帮模型找几份参考资料。
举个例子,我直接问大模型:
我今天学习了什么知识?大模型肯定不知道。
但是,如果我这样问大模型:
1.我今天学习了 RAG 知识库。 2.我今天学习了什么知识?大模型是不是肯定就知道了。
“我今天学习了 RAG 知识库。” 这段文字,就是给大模型的临时参考资料。
但是这种临时参考资料可能会很多,因此,咱们不能每次都自己输入,对不对。
因此,咱们就得有个「知识库(类似数据库)」的东西,让大模型在这个「知识库」里面进行检索。
这也意味着,一个 RAG 系统想要给出正确答案,至少需要连续完成两件事:
- 找到正确资料
- 根据资料生成正确答案
因此,当大模型回答内容出错的时候,就不能只说一句:"模型不行,换个更强的模型吧。"
模型确实可能有问题。
但是在此之前,还有一长串地方值得检查。
第一:知识库里有,但是模型没有找到
举个例子。
现在咱们给一套企业数据平台搭建了知识库。
最新的数据导出规则中明确写着:
单次导出超过 50 万行的数据,需要由数据管理员进行审批。
然后用户问:
“我这张表有 80 万行,能不能直接拉下来?”
人一看就知道,这两句话讨论的是同一个问题。
但是,对于检索系统来说,两边的表达方式并不完全一样。
文档里写的是:
1.单次导出 2.超过 50 万行 3.数据管理员审批用户说的是:
1.80 万行 2.能不能直接拉下来如果只使用简单的关键词检索,用户的问题里压根没有“导出”和“审批”这两个词,相关资料就可能被漏掉。
这也是为什么 RAG 中经常需要用到向量检索。
什么是向量检索
向量数据库本身并不能理解文字。
真正负责把文字转换成语义数据的,是Embedding模型。
Embedding 模型会把用户问题和知识库里的每一个 Chunk,都转换成一串数字。
比如,用户的问题:
我这张表有 80 万行,能不能直接拉下来?经过 Embedding 模型处理以后,可能会变成:
[0.72, 0.18, -0.35, 0.61, ...]知识库里的规则:
单次导出超过 50 万行的数据,需要由数据管理员审批。也会变成一个向量:
[0.69, 0.21, -0.31, 0.65, ...]真实的向量通常会有几百甚至几千个维度。
这里写四个数字,只是方便大家理解。
接下来,向量数据库会计算这两个向量之间的相似程度。
最常见的一种计算方式,就是余弦相似度。
公式长这样:
复制
Cosine Similarity = A · B / (||A|| × ||B||)看着有点复杂,但是其实很简单,看下图就明白了:
上面的内容就大白话来说,就是:可以把两个向量想象成两根箭头。
两根箭头指向越接近,余弦相似度就越高,也就说明两段文字在语义上越接近。
通常情况下:
- 分数越接近
1,语义越相似 - 分数越接近
0,相关性越弱 - 分数越接近
-1,方向越相反
不过这里要注意一个小细节。
- 有些向量数据库返回的是“相似度”,分数越高越接近。
- 有些返回的是“距离”,数值越低反而越接近。
这个得看清楚对应向量数据库的文档。
完整的向量检索过程大概是这样的:
比如,TopK = 5,就是从知识库里找到最相似的五个 Chunk。
但问题也就出在这里。
余弦相似度高,只能说明两段文字的语义比较接近,不代表这份资料一定可以回答用户的问题。
比如,知识库里可能同时存在:
1.大数据量导出规则 2.普通数据下载规则 3.报表异步生成规则 4.历史数据归档规则 5.管理员权限说明这些资料都和 数据、下载、导出 有关。
它们的向量相似度可能都不低。
但真正能够回答 “80 万行数据能不能直接导出” 的,只有第一份。
余弦相似度并不知道:哪份资料是最新的、哪份资料已经废弃 了
所以,向量检索解决的是:
从大量资料里找出一批可能相关的候选内容。
什么是文档分块
除了向量相似度以外,文档怎样分块,也会直接影响检索结果。
比如原始规则是:
1.单次导出超过 50 万行的数据,需要由数据管理员进行审批。 2.审批通过以后,系统会异步生成下载文件。结果在分块的时候,正好从中间切开了:
Chunk 1:单次导出超过 50 万行的数据 Chunk 2:需要由数据管理员进行审批。审批通过以后……第一块只有限制条件,没有处理方式。
第二块只有处理方式,却不知道什么情况下需要审批。
检索系统即使把其中一块找回来,交给模型的也是残缺的信息。
所以,知识库里明明有答案,模型却没有找到时
应该优先检查:文档是否解析完整,Chunk 有没有被错误切分
什么是 Query Rewrite
Query Rewrite的作用,是:把用户口语化、依赖上下文的问题,改写成一条可以独立检索的查询。
比如,把:
80 万行能直接拉下来吗?改写成:
单次导出 80 万行数据时,是否需要审批?Multi-Query则会把同一个问题扩展成多个检索角度:
大数据量导出是否需要管理员审批? 超过 50 万行的数据应该如何下载? 80 万行报表的导出流程是什么?然后分别检索一次,提高正确资料被召回的概率。
他们俩解决的问题是:应该找到的资料,到底有没有找回来。
第二:知识库里没有,模型开始瞎编
第二种情况正好反过来。
知识库里压根没有相关资料,但是模型依然给出了答案。
继续使用刚才的数据平台举例。
用户问:
“平台支持把数据直接导出成 Parquet 文件吗?”
知识库里只写了 CSV 和 Excel 的导出方式,根本没有提到 Parquet。
但是,向量数据库执行查询以后,通常还是可以返回几份“最相似”的资料。
注意,是最相似。
不代表真的相关。
它可能返回:
- CSV 导出说明
- Excel 下载规则
这些资料都提到了“导出”和“文件”,所以余弦相似度可能不低。
模型拿到这些内容以后,如果系统还强制要求它回答,就可能结合 “自己的常识” 补出一句:“平台支持 Parquet 格式,可以在导出设置中进行选择。”
PS:这种情况现在很多企业的 Agent 项目都会遇到,哪怕是大厂。
但是,问题是,知识库里从来没有这条信息。
这就是典型的生成幻觉。
很多人的解决方式,是在 Prompt 里增加一句:
只能根据知识库内容回答,不允许编造。
这句话可能会有点用,但是说实话:也不大管用。
因为 Prompt 依然只是交给模型的一条要求,不是程序级别的强制约束。
更可靠的方案,是把拒答能力明确设计出来。
第一种情况,完全没有检索到可用 Chunk。
程序可以直接返回:
暂时没有找到能够回答该问题的资料。第二种情况,检索到了资料,但是这些资料不足以支持答案。
这时可以让模型返回结构化结果:
{ "status": "insufficient_evidence", "answer": "", "sourceChunkIds": [] }应用程序识别到insufficient_evidence以后,再进入统一的拒答流程。
而不是继续逼着模型从三份不相关的资料里凑出一个答案。
另外,还可以给检索结果设置最低相关性阈值。
如果所有候选资料的分数都过低,就不继续进入答案生成。
不过,固定阈值也不能解决所有问题。
不同问题、不同资料和不同 Embedding 模型的分数分布并不完全一样。
所以,更稳妥的方案通常是:相似度阈值 + 模型判断证据是否充分 + 程序统一处理拒答
PS:在这里有详细的案例:商用知识库实战
很多知识库演示时看起来特别聪明,就是因为它什么问题都敢回答。
可一旦放到真实业务里,这反而是最危险的地方。
不知道的时候明确说不知道,本身就是系统能力。
第三:资料搜到了,却搜到了旧规则
第三种情况比较麻烦。
资料找到了,内容也能回答问题。
但是,它已经过期了。
假设公司的数据导出规则经历过一次调整。
旧规则是:
单次最多导出 10 万行数据,超过限制需要拆分任务。新规则变成了:
单次最多导出 100 万行数据,超过 50 万行需要管理员审批。如果新旧两份文档同时存在于知识库中,那么它们和“80 万行数据能不能导出”这个问题的语义都非常接近。
余弦相似度不会主动判断哪一份已经过期。
它只知道:这两份资料都在讨论大数据量导出。
如果旧规则的标题、正文与用户问题更加接近,它甚至可能排在新规则前面。
这时候,单纯依靠向量检索或者 Rerank,并不能彻底解决问题。
因为“语义最接近”和“业务上仍然有效”,根本就是两回事。
更靠谱的做法,是在文档入库时就保存完整 Metadata:
{ "documentId": "export-policy", "version": "2026.08", "status": "active", "effectiveFrom": "2026-08-01", "department": "data-platform", "permissionScope": "internal" }检索的时候先通过 Metadata Filter 过滤:
status = active effectiveFrom <= 当前时间 用户拥有对应权限先把已经废弃、尚未生效或者没有权限查看的资料排除掉,再进行向量检索和排序。
这比把新旧规则全部交给模型,再让它自己判断谁更新,要可靠得多。
因为模型可能判断错。
程序里的过滤条件则是确定的。
当然,文档更新时也要处理版本问题:
- 新文档入库以后,旧文档是否要标记为失效
- 原文更新以后,旧 Chunk 是否要删除
- 文档版本变化后,是否需要重新生成 Embedding
- 缓存中的旧答案什么时候失效
- 多份资料冲突时,应该相信哪一个来源
这些才是企业知识库真正麻烦的地方。
第四:资料说需要人工审核,模型却说会自动完成
现在来看第四种情况。
知识库已经正确检索到了最新规则:
单次导出超过 50 万行的数据,需要由数据管理员人工审批。用户问:
“我这张表有 80 万行,帮我导出来。”
结果模型回答:
“好的,导出任务已经自动提交,文件生成后会通知你。”
问题是,系统压根没有提交任何任务。
就算真的接入了导出 Tool,这个操作也不应该绕过人工审批。
这里已经不只是 RAG 检索的问题了。
而是:
模型把“知道业务规则”,误认为了“拥有执行权限”。
RAG 负责提供知识。
它可以告诉模型,超过 50 万行需要人工审核。
但真正控制任务能不能执行的,必须是应用程序。
如果当前系统只是一个知识问答助手,那么它应该回答:“该数据量需要先提交管理员审批,审批通过后才能生成导出任务。”
不能假装自己已经完成了操作。
如果系统已经接入了数据导出 Tool,那么 Runtime 也应该在执行前检查:导出行数是否超过 50 万 + 是否已经获得管理员批准
超过限制时,任务进入Human-in-the-loop流程,暂停执行,等待管理员确认。
模型可以提出:
我建议创建一个数据导出任务。但是,最终能不能执行,不能让模型自己决定。
所以,企业 Agent 里很重要的一条原则就是:
模型可以提出动作,但是动作能不能执行,必须由 Agent 应用控制才可以。
怎么判断问题到底出在哪?
说到这里,大家应该能发现:虽然最终表现都是“模型回答错了”,但背后的原因完全不同。
那么当 Agent 的回答出现一些错误的时候,咱们怎么判断问题到底出在哪里呢?
有几种方式
第一种:Recall@K
Recall@K 关心的是:应该找到的资料,有没有进入前 K 个检索结果?
如果Recall@K很低,说明问题主要发生在召回阶段。
优先检查:文档分块、Embedding、 向量相似度配置
第二种:MRR
它的意思是:第一份正确资料排在第几名?
如果 Recall@K 不低,但是 MRR 很低,说明正确资料已经找到,只是排名太靠后。
这个时候应该检查混合检索权重、RRF 和 Rerank。
Faithfulness
他指的是:模型回答中的结论,有多少能够被检索资料支持?
如果召回和排序都正常,但是 Faithfulness 很低,问题更可能出在答案生成阶段。
最后
所以,一个完整的企业 RAG 知识库,远远不只是:向量数据库 + 大模型
它至少包含下面这条链路:
其中任何一层出错,最后展示给用户的答案都有可能会出错的。