RAG 工程实战(五):正确知识已经进入 Prompt,为什么大模型还是会答错?

目录

[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 的问题。

类似地,一份生产环境部署文档,未必能直接用于开发环境。

所以我更倾向于按以下顺序处理:

  1. 适用范围: 产品型号、文档版本、部署环境是否匹配用户问题?

  2. 来源权威性: 是正式规范、经过审核的 Wiki,还是个人笔记?

  3. 有效状态: 文档是否已经废弃?是否存在明确的替代关系?

  4. 无法判断: 是否需要保留冲突,交给用户或知识负责人确认?

这里的顺序是推荐的业务决策思路,不是通用的行业固定标准。

比如一份最近更新的个人笔记,与较早发布、但依然有效的官方规范发生冲突,就不能简单按照 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 中猜哪个答案正确,而是让系统先确定知识的适用性,再让模型有依据地回答。


参考资料

  1. Azure AI Search:Vector Query Filters --- 向量检索的元数据过滤与过滤时机。

  2. Anthropic:Prompting Best Practices --- 多文档结构化提示与证据提取。

  3. Amazon Bedrock Knowledge Bases --- 检索生成与来源引用。

  4. FaithfulRAG(ACL 2025) --- 模型参数化知识与检索证据冲突。

  5. Lost in the Middle(TACL 2024) --- 长上下文中证据位置对信息利用的影响。

相关推荐
CoderYanger44 分钟前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
易小尊1 小时前
我的模型在 65% 以上时准得可怕,在 50% 时像在掷硬币
后端
用户2788607285671 小时前
fallback 会盖掉平台提示词:system、空数组和 systemAppend 的差别
前端·后端
iOS开发上架哦1 小时前
iOS应用耗电测试:使用Energy Log、Keymob和Instruments进行性能监控与能源消耗分析
后端·ios
掘金挖土1 小时前
前端手摸手跑路之 AI 应用开发(十一)
前端·后端
用户9888321871741 小时前
从“限流数字”到可维护策略:ASP.NET Core 固定窗口限流的落地边界
后端
IT_陈寒1 小时前
Vue动态组件缓存的坑你踩过了吗?
前端·人工智能·后端
雾行0x002 小时前
粗排:如何在毫秒级筛出值得精排的内容?
后端·架构
D121382 小时前
从零用 C++17 写一个 API 网关:线程模型、控制面分离,以及三个真实 Bug
后端