目录
[0. 正确知识进入 Prompt,就一定能回答正确吗?](#0. 正确知识进入 Prompt,就一定能回答正确吗? "#0.%20%E6%AD%A3%E7%A1%AE%E7%9F%A5%E8%AF%86%E8%BF%9B%E5%85%A5%20Prompt%EF%BC%8C%E5%B0%B1%E4%B8%80%E5%AE%9A%E8%83%BD%E5%9B%9E%E7%AD%94%E6%AD%A3%E7%A1%AE%E5%90%97%EF%BC%9F")
[1. 知识库内部冲突:新旧文档到底应该信谁?](#1. 知识库内部冲突:新旧文档到底应该信谁? "#1.%20%E7%9F%A5%E8%AF%86%E5%BA%93%E5%86%85%E9%83%A8%E5%86%B2%E7%AA%81%EF%BC%9A%E6%96%B0%E6%97%A7%E6%96%87%E6%A1%A3%E5%88%B0%E5%BA%95%E5%BA%94%E8%AF%A5%E4%BF%A1%E8%B0%81%EF%BC%9F")
[1.1 不是越新的文档就越正确](#1.1 不是越新的文档就越正确 "#1.1%20%E4%B8%8D%E6%98%AF%E8%B6%8A%E6%96%B0%E7%9A%84%E6%96%87%E6%A1%A3%E5%B0%B1%E8%B6%8A%E6%AD%A3%E7%A1%AE")
[1.2 不要只保存 Chunk 文本和向量](#1.2 不要只保存 Chunk 文本和向量 "#1.2%20%E4%B8%8D%E8%A6%81%E5%8F%AA%E4%BF%9D%E5%AD%98%20Chunk%20%E6%96%87%E6%9C%AC%E5%92%8C%E5%90%91%E9%87%8F")
[1.3 解决不了冲突怎么办?](#1.3 解决不了冲突怎么办? "#1.3%20%E8%A7%A3%E5%86%B3%E4%B8%8D%E4%BA%86%E5%86%B2%E7%AA%81%E6%80%8E%E4%B9%88%E5%8A%9E%EF%BC%9F")
[2. 模型自身知识与 RAG 知识发生冲突怎么办?](#2. 模型自身知识与 RAG 知识发生冲突怎么办? "#2.%20%E6%A8%A1%E5%9E%8B%E8%87%AA%E8%BA%AB%E7%9F%A5%E8%AF%86%E4%B8%8E%20RAG%20%E7%9F%A5%E8%AF%86%E5%8F%91%E7%94%9F%E5%86%B2%E7%AA%81%E6%80%8E%E4%B9%88%E5%8A%9E%EF%BC%9F")
[2.1 第一层:明确回答依据](#2.1 第一层:明确回答依据 "#2.1%20%E7%AC%AC%E4%B8%80%E5%B1%82%EF%BC%9A%E6%98%8E%E7%A1%AE%E5%9B%9E%E7%AD%94%E4%BE%9D%E6%8D%AE")
[2.2 第二层:先提取证据,再生成答案](#2.2 第二层:先提取证据,再生成答案 "#2.2%20%E7%AC%AC%E4%BA%8C%E5%B1%82%EF%BC%9A%E5%85%88%E6%8F%90%E5%8F%96%E8%AF%81%E6%8D%AE%EF%BC%8C%E5%86%8D%E7%94%9F%E6%88%90%E7%AD%94%E6%A1%88")
[2.3 第三层:生成后验证关键事实](#2.3 第三层:生成后验证关键事实 "#2.3%20%E7%AC%AC%E4%B8%89%E5%B1%82%EF%BC%9A%E7%94%9F%E6%88%90%E5%90%8E%E9%AA%8C%E8%AF%81%E5%85%B3%E9%94%AE%E4%BA%8B%E5%AE%9E")
[3. Faithfulness 不等于 Answer Correctness](#3. Faithfulness 不等于 Answer Correctness "#3.%20Faithfulness%20%E4%B8%8D%E7%AD%89%E4%BA%8E%20Answer%20Correctness")
[4. 正确证据都在 Prompt 中,为什么还需要整理上下文?](#4. 正确证据都在 Prompt 中,为什么还需要整理上下文? "#4.%20%E6%AD%A3%E7%A1%AE%E8%AF%81%E6%8D%AE%E9%83%BD%E5%9C%A8%20Prompt%20%E4%B8%AD%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%98%E9%9C%80%E8%A6%81%E6%95%B4%E7%90%86%E4%B8%8A%E4%B8%8B%E6%96%87%EF%BC%9F")
[5. 如果让我设计,我会采用怎样的方案?](#5. 如果让我设计,我会采用怎样的方案? "#5.%20%E5%A6%82%E6%9E%9C%E8%AE%A9%E6%88%91%E8%AE%BE%E8%AE%A1%EF%BC%8C%E6%88%91%E4%BC%9A%E9%87%87%E7%94%A8%E6%80%8E%E6%A0%B7%E7%9A%84%E6%96%B9%E6%A1%88%EF%BC%9F")
RAG 检索到了正确知识,也成功把它放进了 Prompt,但 LLM 最终还是给出了错误答案。这一次,问题可能不在检索,而在模型如何理解、选择和使用这些知识。
0. 正确知识进入 Prompt,就一定能回答正确吗?
在上一篇文章中,我们讨论了一个问题:正确 Chunk 明明已经被召回,为什么经过 RRF、Rerank 等检索环节后,最终 Top-K 却没有它?
但如果正确 Chunk 已经完整进入 Prompt,问题就解决了吗?
未必。
假设企业知识库中存在两份接口文档:
| 文档 | 默认请求超时时间 | 状态 |
|---|---|---|
| V1 接口文档 | 60 秒 | 历史有效版本 |
| V2 接口文档 | 30 秒 | 当前有效版本 |
用户提问:
"V2 接口的默认超时时间是多少?"
系统把这两份文档都检索了出来,并且完整地交给 LLM。
理论上,模型应该回答 30 秒。
但它仍然有可能选择 V1 的数据,回答 60 秒。
更值得注意的是,这个错误答案并非凭空捏造。
60 秒确实存在于知识库中,只不过它属于错误的版本。
这就带来了一个比传统幻觉更复杂的问题:
回答能够找到知识库依据,不代表这份依据就适用于当前问题。
本文以企业 Wiki 和技术文档为背景,讨论知识冲突、模型先验知识与检索证据冲突,以及如何通过工程手段提高回答的可靠性。
文中的配置数据均为构造示例,不代表真实线上故障。
1. 知识库内部冲突:新旧文档到底应该信谁?
企业知识库和普通静态文档不同。
同一个接口可能有多个版本,同一项配置可能在测试环境和生产环境使用不同的值,不同团队维护的 Wiki 也可能存在差异。
因此,检索到多份互相矛盾的内容并不罕见。
最直观的想法是:
给知识添加版本号,再按照优先级选择最可信的文档。
这确实是重要的工程手段,但我认为还需要补充一个前提:
优先级判断必须建立在知识适用范围匹配的基础上。
1.1 不是越新的文档就越正确
假设用户明确问 V1 的接口参数。
即使知识库存在更新的 V2 规范,也不能拿 V2 的数据回答 V1 的问题。
类似地,一份生产环境部署文档,未必能直接用于开发环境。
所以我更倾向于按以下顺序处理:
-
适用范围: 产品型号、文档版本、部署环境是否匹配用户问题?
-
来源权威性: 是正式规范、经过审核的 Wiki,还是个人笔记?
-
有效状态: 文档是否已经废弃?是否存在明确的替代关系?
-
无法判断: 是否需要保留冲突,交给用户或知识负责人确认?
这里的顺序是推荐的业务决策思路,不是通用的行业固定标准。
比如一份最近更新的个人笔记,与较早发布、但依然有效的官方规范发生冲突,就不能简单按照 updated_at 选择个人笔记。

1.2 不要只保存 Chunk 文本和向量
如果知识库只存储:
chunk_id + content + embedding
那么很多版本信息就只能依赖模型从正文中自行理解。
我更推荐为 Chunk 保留结构化元数据:
| 字段 | 示例 | 作用 |
|---|---|---|
document_id |
doc_1024 | 关联原始文档 |
product_model |
EVM-RK3588 | 限定产品型号 |
version |
V2 | 区分适用版本 |
environment |
production | 区分部署环境 |
source_type |
official | 标记来源类别 |
status |
active | 标记有效状态 |
updated_at |
2026-10-01 | 辅助判断时效 |
这不是说每个 RAG 系统都必须设计上述所有字段,而是对影响业务正确性的条件,尽可能使用可查询的结构化信息表达。
例如用户明确询问某个产品的 V2 文档,就可以在检索时利用型号和版本字段缩小候选范围。
Azure AI Search 的向量查询支持基于非向量字段的元数据过滤,其中预过滤允许检索在指定范围内寻找候选。
对于使用 PostgreSQL + pgvector 的系统,也可以采用类似的元数据约束思路。
需要注意,如果系统采用的是近似向量检索,过滤发生的阶段可能影响召回效果,不能简单认为先取全局 Top-K、再过滤,与限定范围后检索完全等价。
能够通过确定性规则解决的知识适用性问题,尽量不要完全交给 LLM 猜测。
1.3 解决不了冲突怎么办?
假设两份文档:
-
都属于当前有效版本。
-
都来自正式审核的来源。
-
产品型号、环境也完全相同。
-
但配置值互相矛盾。
这时候就不能靠"文档发布时间更近"强行选择一个。
我更倾向于保留冲突状态,并告诉用户:
"当前存在两份适用范围相同但配置不一致的文档,分别记录为 A 和 B。暂时无法确认哪份为准,请联系知识负责人核实。"
而不是让 LLM 自行生成一个看似确定的答案。
对于企业知识库,能够解释为什么不能确定,有时比给出一个未经验证的答案更重要。
2. 模型自身知识与 RAG 知识发生冲突怎么办?
上一节讨论的是知识库文档之间的冲突。
但还有一种更隐蔽的情况:
检索证据只有一份,而且内容正确,模型仍然可能受到自身已有知识影响。
例如,模型从训练中学到 SSH 通常使用默认端口 22。
但某个企业的服务器明确将 SSH 端口配置为 2222。
如果用户询问的是这台企业服务器的实际配置,那么应该以有效的企业部署文档为准。
这种冲突涉及两个概念:
-
Parametric Knowledge: 模型学习并存储在参数中的知识。
-
Retrieved Knowledge: RAG 在运行时提供的外部检索知识。
模型并不是一个能够简单关闭内部知识、只读取数据库内容的程序。
2025 年 ACL 的 FaithfulRAG 研究就讨论了这种情况:模型可能忽略检索上下文,或不一致地混合模型自身知识与外部证据。
那么工程中该怎么处理?
2.1 第一层:明确回答依据
最简单的方法是在 System Prompt 中增加约束:
回答企业内部配置、接口参数和产品版本问题时,以当前问题适用的有效知识库文档为事实依据。
不得使用通用默认值替代文档中的明确配置。
如果证据不足或存在无法判断的冲突,应说明不确定性,不得自行补全事实。
这种方式实现成本低,适合第一版系统。
但问题是:
Prompt 是对模型行为的约束,不是一个绝对可靠的事实验证器。
即使明确要求模型遵守证据,也不能保证它每次都正确执行。
2.2 第二层:先提取证据,再生成答案
我更推荐的一种思路是 Evidence-first Generation(证据先行的生成方式)。
不要直接把几段 Chunk 拼起来,让模型自由组织答案。
可以先让模型完成一个更明确的任务:
从相关 Chunk 中提取回答问题所需要的事实、适用条件和来源。
例如提取出:
bash
{
"attribute": "ssh_port",
"value": 2222,
"environment": "production",
"source_id": "doc_1024_chunk_3"
}
然后再根据这份证据组织自然语言回答。
这不一定需要两次 LLM 调用,也可以通过一次结构化输出来完成"事实提取 + 答案生成"。
它的优势是把隐含的证据选择过程变得更加明确。
Anthropic 的长上下文提示实践也建议,在部分文档问答任务中先提取相关原文,再基于这些内容执行后续任务。
当然,这仍然不能完全杜绝错误,因为事实提取本身也可能出错。
2.3 第三层:生成后验证关键事实
如果知识库明确写着端口是 2222,最终答案却输出 22,那么我们希望在返回用户之前发现这个问题。
可以增加一层答案校验,重点检查:
-
回答中的数字、型号、版本是否与证据一致。
-
引用的
source_id是否真实存在。 -
被引用的原文是否包含对应事实。
-
引用的文档是否适用于当前问题。
对于端口、型号、错误码等结构化信息,能够使用确定性规则校验的部分,可以优先使用程序完成。
对于复杂的自然语言结论,则可以考虑更高级的事实支持性检查。
Amazon Bedrock Knowledge Bases 提供了带来源引用的检索生成接口,可以作为答案可追溯性的工程参考。
但这里还存在一个容易被忽略的问题。
答案有来源,不等于答案一定正确。
3. Faithfulness 不等于 Answer Correctness
回到开头的例子:
用户问 V2 超时时间。
模型回答 60 秒,并引用 V1 文档。
此时:
-
60 秒确实存在于检索上下文中。
-
引用的 V1 文档也真实存在。
-
但用户要求的是 V2,正确答案应该是 30 秒。
因此需要区分:
Faithfulness(忠实性): 回答中的陈述能否从给定上下文中得到支持?
Answer Correctness(答案正确性): 回答是否正确解决了用户提出的问题?
前者不能自动替代后者。
更重要的是,我们还需要检查:
引用的那份证据,是否符合用户要求的版本、型号和环境?
例如,某个校验器只是检查"60 秒是否出现在检索内容中",就可能忽略版本不一致的问题。
所以我认为企业 RAG 的答案校验至少应该覆盖三个维度:
| 校验维度 | 需要回答的问题 |
|---|---|
| 事实支持 | 答案中的关键陈述是否有证据? |
| 证据适用 | 证据的版本、型号和环境是否匹配? |
| 来源可追溯 | 引用是否真实指向支持该结论的原文? |

这里还有一个工程细节:
不能只让模型输出一个 source_id,就认为引用完成了。
如果模型声称引用了 Chunk A,但它实际给出的结论来自 Chunk B,引用仍然不可靠。
因此,最好同时保留模型输出的引用信息和真实检索结果,由后端验证引用关系。
4. 正确证据都在 Prompt 中,为什么还需要整理上下文?
除了知识冲突,证据的组织方式也值得注意。
假设用户询问 RK3588 的配置,但 Top-K 同时包含:
-
RK3588 当前版本的配置。
-
RK3568 的相似配置。
-
某个旧版本的部署说明。
-
通用 Linux 配置教程。
这些 Chunk 可能都与用户问题语义相关,但并不全部适用。
模型需要同时判断产品型号、版本、部署环境等条件,才能选出正确内容。
而在较长上下文中,证据的位置也可能影响模型使用信息的效果。
2024 年 TACL 的 Lost in the Middle 研究发现,在其测试的部分模型和任务中,相关信息位于长上下文中间时,模型表现可能下降。
不过,这不意味着所有模型、所有长度的 Prompt 都会出现同样的问题。
对于普通的非 Agent RAG,如果最终只有少量 Chunk,这种效应未必显著。
所以我认为,比起刻意调整 Chunk 在 Prompt 中的排列位置,更应该优先做好三件事:
第一,过滤明显不适用的知识。
第二,保留清晰的文档来源、版本和内容边界。
第三,避免把相互矛盾的证据不加说明地直接混在一起。
把正确知识组织清楚,往往比单纯增加 Prompt 的长度更有工程价值。
5. 如果让我设计,我会采用怎样的方案?
结合前面的讨论,我不会一开始就引入复杂的 Agent 或多轮模型验证链路。
对于常见的企业 RAG,我更倾向于设计一个分层方案:
bash
用户 Query
↓
提取版本 / 型号 / 环境约束
↓
带元数据约束的知识检索
↓
有效性与来源优先级判断
↓
识别无法消除的知识冲突
↓
组织带来源标识的证据
↓
LLM 生成答案
↓
关键事实与引用校验
↓
返回答案 / 展示冲突并请求确认

这里有一个非常重要的取舍。
并不是每个问题都必须执行所有步骤。
比如一个简单的概念解释问题,模型直接根据一份有效文档回答,可能已经足够。
但如果问题涉及生产环境配置、接口版本、关键设备参数,那么版本校验和事实一致性检查就更值得投入。
工程设计不应该只追求处理链路复杂,而应该根据业务风险选择必要的可靠性机制。
从这个角度看,企业 RAG 的可靠性可以分成三个层面:
知识治理: 决定哪些知识是当前问题适用的。
证据组织: 帮助模型理解和选择正确事实。
生成校验: 确认最终答案没有偏离这些有效证据。
它们相互配合,但没有哪一层能够单独保证回答永远正确。
最后
经过这次对知识冲突问题的梳理,我觉得 RAG 有一个很容易被忽视的事实:
把正确知识检索出来,只是解决了模型能不能接触到答案的问题,并没有解决模型是否正确理解、选择和使用答案的问题。
对于存在多版本、多来源的企业知识库,单纯要求模型"严格根据上下文回答"还不够。
我们应该尽量通过版本管理、适用范围和来源优先级,在知识层先明确哪些证据有效。
对于无法通过规则消除的冲突,应该保留不确定性,而不是强迫模型给出一个确定结论。
在生成阶段,再通过证据提取、来源引用和关键事实校验,减少模型混用自身知识与外部证据的风险。
我认为真正可靠的企业 RAG,不是让 LLM 在一堆互相矛盾的 Chunk 中猜哪个答案正确,而是让系统先确定知识的适用性,再让模型有依据地回答。
参考资料
-
Azure AI Search:Vector Query Filters --- 向量检索的元数据过滤与过滤时机。
-
Anthropic:Prompting Best Practices --- 多文档结构化提示与证据提取。
-
Amazon Bedrock Knowledge Bases --- 检索生成与来源引用。
-
FaithfulRAG(ACL 2025) --- 模型参数化知识与检索证据冲突。
-
Lost in the Middle(TACL 2024) --- 长上下文中证据位置对信息利用的影响。