/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
知识库里的文档互相矛盾,AI 到底该信谁?我们做了 20 次自建测试
文章目录
- 知识库里的文档互相矛盾,AI 到底该信谁?我们做了 20 次自建测试
-
- 问题背景:知识冲突比「没搜到」更危险
- 一个"看懂了材料"却仍然答错的例子
- 找到"相关材料",不等于找到"当前依据"
- 把判断规则落到系统里:一条最小可用链路
-
- 文档至少要带哪些元数据
- 哪些规则适合直接写进代码
- 回答之前,先走四步判断
-
- 1. 准入:这份材料能不能当依据
- 2. 适用:它是否回答了当前这个人的当前问题
- 3. 冲突:剩下的依据是否仍然互相矛盾
- 4. 输出:回答、追问、拒答或升级
- 20 次自建测试说明了什么
- 企业现在可以检查的 8 件事
-
- 最小回归测试不要只测"答对的问题"
- 哪些决定必须留给人
- 参考资料
摘要:企业知识库同时检索到新旧制度、草案和专项规则时,不能只靠相似度或发布日期选答案。本文用 20 次虚构自建测试,拆解「准入 → 适用 → 冲突 → 输出」四步判断,并给出可直接落地的元数据设计、确定性过滤代码与回归测试清单。
问题背景:知识冲突比「没搜到」更危险
企业知识库最危险的错误,未必是"什么都没搜到",而是同时搜到了几份都很像的材料:旧制度、新制度、未审批草案、群聊通知和某个项目的专项规则。它们各自都能回答问题,却可能给出不同答案。
AI 不该凭文档"更新"、措辞更肯定或者相似度更高就选一份。更稳妥的处理顺序是:先排除没有资格成为依据的材料,再判断日期和对象是否适用;信息不够就追问;仍有同级有效依据冲突,就展示冲突并交给责任人裁定。

为了看看这个顺序能否减少错误,我们构造了 8 份完全虚构的制度文档、10 个问题,用同一个模型各跑了两组,共 20 次调用。结果里出现了一个很值得拆开的错误:模型把日期读对了,结论却判错了。
实验中的公司、项目、制度、日期和金额均为虚构,不代表任何公司制度,也不涉及真实事故。
一个"看懂了材料"却仍然答错的例子
问题很简单:2026 年 6 月 10 日,常规项目的住宿报销上限是多少?
候选资料有三份:
| D01 | 正式批准 | 2025-01-01 至 2026-07-01,不含结束日;上限 300 元 |
| D02 | 正式批准 | 2026-07-01 至 2027-01-01,不含结束日;上限 500 元 |
| D04 | 未批准群聊 | 声称统一按 800 元报销 |
正确答案应当是 300 元。出差日期落在 D01 的有效期内,D02 尚未生效,群聊也不是正式依据。
第一组把三份候选资料全部交给模型。模型回答"依据不足",解释却说 D01 有效至 2026 年 6 月 30 日。它复述对了日期,仍错误地排除了 D01。这不是检索没找到资料,也不是编造了一个新金额,而是多份材料并存时发生的适用性判断错误。
第二组先根据审批状态和有效期过滤,只把 D01 交给模型,模型回答 300 元。一次结果无法证明过滤必然提高准确率,但它说明:能在生成前确定的规则,不必全部留给语言模型临场判断。
找到"相关材料",不等于找到"当前依据"
RAG 会先从外部知识中找出与问题相关的内容,再让模型基于这些内容回答。相关性检索擅长回答"这段文字和问题像不像",却不能单独回答:
- 这份材料是否经过审批?
- 它在提问所指的日期是否生效?
- 它适用于总部、某个地区,还是某个项目?
- 它是否明确替代了旧版?
- 两份同级制度冲突时,谁有权作最终解释?
"最新上传"也不是稳妥的替代规则。2027 年的新制度可以在 2026 年提前发布,但查询 2026 年 10 月的标准时,它仍未生效。某个项目的专项规则可能比通用制度更早发布,却对该项目优先。腾讯云的时效性检索文档也明确区分了"知识有效时间"和文件上传、最后修改时间。
企业知识库需要同时管理两类信号:语义相关性负责找到可能有用的材料,业务适用性负责判断材料是否有资格进入本次回答。向量检索、关键词检索和重排主要解决前一类;审批状态、有效期、适用范围、权限和替代关系属于后一类。
把判断规则落到系统里:一条最小可用链路
下面这条链路把"模型自由判断"拆成可以测试的系统步骤。权限过滤应在检索阶段生效,避免无权访问的内容进入模型上下文;日期、范围和审批状态也尽量在生成前处理。
#mermaid-svg-NA8j9rQukFfLGPo3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NA8j9rQukFfLGPo3 .error-icon{fill:#552222;}#mermaid-svg-NA8j9rQukFfLGPo3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NA8j9rQukFfLGPo3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NA8j9rQukFfLGPo3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NA8j9rQukFfLGPo3 .marker.cross{stroke:#333333;}#mermaid-svg-NA8j9rQukFfLGPo3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NA8j9rQukFfLGPo3 p{margin:0;}#mermaid-svg-NA8j9rQukFfLGPo3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 .cluster-label text{fill:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 .cluster-label span{color:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 .cluster-label span p{background-color:transparent;}#mermaid-svg-NA8j9rQukFfLGPo3 .label text,#mermaid-svg-NA8j9rQukFfLGPo3 span{fill:#333;color:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 .node rect,#mermaid-svg-NA8j9rQukFfLGPo3 .node circle,#mermaid-svg-NA8j9rQukFfLGPo3 .node ellipse,#mermaid-svg-NA8j9rQukFfLGPo3 .node polygon,#mermaid-svg-NA8j9rQukFfLGPo3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NA8j9rQukFfLGPo3 .rough-node .label text,#mermaid-svg-NA8j9rQukFfLGPo3 .node .label text,#mermaid-svg-NA8j9rQukFfLGPo3 .image-shape .label,#mermaid-svg-NA8j9rQukFfLGPo3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-NA8j9rQukFfLGPo3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NA8j9rQukFfLGPo3 .rough-node .label,#mermaid-svg-NA8j9rQukFfLGPo3 .node .label,#mermaid-svg-NA8j9rQukFfLGPo3 .image-shape .label,#mermaid-svg-NA8j9rQukFfLGPo3 .icon-shape .label{text-align:center;}#mermaid-svg-NA8j9rQukFfLGPo3 .node.clickable{cursor:pointer;}#mermaid-svg-NA8j9rQukFfLGPo3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NA8j9rQukFfLGPo3 .arrowheadPath{fill:#333333;}#mermaid-svg-NA8j9rQukFfLGPo3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NA8j9rQukFfLGPo3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NA8j9rQukFfLGPo3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NA8j9rQukFfLGPo3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NA8j9rQukFfLGPo3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NA8j9rQukFfLGPo3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NA8j9rQukFfLGPo3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NA8j9rQukFfLGPo3 .cluster text{fill:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 .cluster span{color:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NA8j9rQukFfLGPo3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NA8j9rQukFfLGPo3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-NA8j9rQukFfLGPo3 .icon-shape,#mermaid-svg-NA8j9rQukFfLGPo3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NA8j9rQukFfLGPo3 .icon-shape p,#mermaid-svg-NA8j9rQukFfLGPo3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NA8j9rQukFfLGPo3 .icon-shape .label rect,#mermaid-svg-NA8j9rQukFfLGPo3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NA8j9rQukFfLGPo3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NA8j9rQukFfLGPo3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NA8j9rQukFfLGPo3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
否
是
否
是
否
是
用户问题
提取身份、日期、项目等业务条件
关键条件是否齐全
clarify:追问缺失条件
带权限与元数据条件检索候选文档
按审批状态、有效期、适用范围过滤
是否还有适用依据
insufficient:限定范围说明依据不足
应用明确的例外与替代规则
同一事项是否仍有不同结论
answer:结论 + 适用条件 + 版本引用
conflict:展示差异并转责任人
记录请求、候选、排除原因与结果
这张图有两个容易忽略的点。第一,clarify 应发生在系统缺少关键条件时,而不是让模型猜一个日期或项目。第二,conflict 是正常产品状态,不是异常兜底;它必须进入接口定义、前端展示和评测指标。
过滤发生在什么时候,也会影响结果。Azure AI Search 的官方文档区分了向量检索的 preFilter、postFilter 和 strictPostFilter:前置过滤先缩小候选范围;后置过滤是在向量 Top-K 之后再排除不符合条件的文档。后两种模式在条件选择性很高或 k 很小时可能出现假阴性——库里明明有符合条件的文档,最终结果却没有返回。因此,权限条件必须可靠执行;有效期、项目等业务过滤还要用真实评测集检查召回率、延迟和吞吐,不能只看最终回答是否顺眼。
文档至少要带哪些元数据
下面是一份最小示例。字段名可以调整,但语义要稳定;valid_to 采用不包含结束日的半开区间,能避免相邻版本在切换日重叠。
{
"document_id": "POLICY-TRAVEL-2026-H2",
"version": "2.1",
"source_type": "formal_policy",
"approval_status": "approved",
"authority": "finance",
"valid_from": "2026-07-01",
"valid_to": "2027-01-01",
"organization_scope": ["all"],
"project_scope": "general",
"region_scope": ["CN"],
"supersedes": ["POLICY-TRAVEL-2025"],
"acl": ["employee"],
"content_hash": "sha256:…",
"owner": "finance-policy-team"
}
published_at 可以保留用于审计,却不应自动代替 valid_from。content_hash 用来判断内容是否真的变化,supersedes 表达明确替代关系,owner 则给冲突升级提供责任人入口。
哪些规则适合直接写进代码
对于结构明确的制度问答,可以先用确定性代码缩小证据集,再把保留下来的正文交给模型解释。下面的 Python 示例对应本次实验里的住宿标准场景:
from datetime import date
APPROVED_TYPES = {"formal_policy", "exception_policy"}
def decide_policy(docs, trip_date: date | None, project: str | None):
if trip_date is None:
return {"status": "clarify", "missing": ["trip_date"]}
if project is None:
return {"status": "clarify", "missing": ["project"]}
applicable = [
d for d in docs
if d["approval_status"] == "approved"
and d["source_type"] in APPROVED_TYPES
and date.fromisoformat(d["valid_from"]) <= trip_date
< date.fromisoformat(d["valid_to"])
and (d["project_scope"] == "general"
or d["project_scope"] == project)
]
if not applicable:
return {"status": "insufficient", "citations": []}
# 明确适用的项目例外优先于通用制度。
exceptions = [d for d in applicable if d["project_scope"] == project]
basis = exceptions or [d for d in applicable
if d["project_scope"] == "general"]
# 只处理文档明确声明的替代关系,不用"发布时间更晚"猜测。
superseded = {old_id for d in basis for old_id in d["supersedes"]}
basis = [d for d in basis if d["document_id"] not in superseded]
if not basis: # 元数据异常或替代链配置错误
return {"status": "insufficient", "citations": []}
amounts = {d["amount"] for d in basis}
citations = [d["document_id"] for d in basis]
if len(amounts) != 1:
return {"status": "conflict", "amount": None,
"citations": citations}
return {"status": "answer", "amount": amounts.pop(),
"citations": citations}
这段代码没有解决所有知识冲突。它假设入库时已经校验必填字段和日期格式,只负责结构化规则能明确判断的部分。自由文本中"同一事项"如何识别、数值与条件如何抽取、两段话是否真的矛盾,仍需要信息抽取、冲突检测和人工复核。但即使后面使用模型,也应该输出结构化结果和引用,而不是直接生成一段无法审计的自然语言。
回答之前,先走四步判断

1. 准入:这份材料能不能当依据
至少区分正式制度、专项规则、草案、会议纪要、群聊记录和个人笔记。草案和聊天记录可以解释背景,但不应自动与正式制度获得同等权重。
对于"未审批草案不得作为最终报销标准"这类确定规则,可以直接在检索或生成前执行,不必让模型给每份材料临时估算可信度。
2. 适用:它是否回答了当前这个人的当前问题
有效期最好用开始时间和结束时间表达,明确边界是否包含。适用范围也要结构化保存,例如组织、地区、项目、产品版本和用户角色。
如果用户没提供必要条件,系统不应猜。实验中有两个问题分别缺少出差日期和项目名,两组都选择追问。对用户来说,"请补充日期"比给出一个条件不完整的数字更有价值。
3. 冲突:剩下的依据是否仍然互相矛盾
过滤不是万能裁判。我们故意设计了两份南桥项目专项制度:审批部门相同、有效期相同、适用范围相同,一份写 600 元,另一份写 650 元,而且都没有声明替代对方。
两组实验都返回冲突,并引用了两份文档。系统可以发现当前证据无法支持唯一答案,但不能凭发布日期晚一天就替组织决定哪份制度有效。腾讯云的产品文档对冲突问答也采用显式提示和人工处理,而不是让模型静默挑选。
4. 输出:回答、追问、拒答或升级
最终输出不应只有"回答成功/失败"两种状态。至少需要四类:
| 回答 | 存在唯一适用的正式依据 | 给出结论、适用条件和引用 |
| 追问 | 日期、项目、地区或角色缺失 | 说明缺少哪项条件 |
| 依据不足 | 当前提供的资料中没有适用依据 | 限定范围,不把"没检索到"说成"事实不存在" |
| 冲突升级 | 同级有效依据给出不同答案 | 展示差异、来源和责任人入口 |
这四类状态比一句"请以实际为准"更有用。用户能知道系统为什么不能直接回答,也知道下一步该补什么信息、找谁处理。
20 次自建测试说明了什么
实验使用 8 份虚构文档和 10 个预设案例,覆盖新旧通用制度、项目例外、未批准群聊、未来草案、未来已批准制度,以及两份同级冲突制度。每个问题跑两个版本:
- A 组把预设候选文档全部交给模型;
- B 组先按批准状态、文档类型、有效期和项目范围做确定性过滤,再交给同一模型。
两组使用相同系统规则、问题和模型参数。预期答案在调用前冻结,模型看不到答案。实际使用阿里云百炼 qwen-plus,温度设为 0;每个案例、每组只运行一次。
在这 10 个预设案例中,A 组的状态与金额匹配 9 个,B 组匹配 10 个。B 组输入的文档总数从 26 份次降到 14 份次,输入 token 也更少。唯一的答案差异,就是前文的日期判断错误。
这些结果不能写成"准确率提升 10%"。样本是人工设计的,没有独立留出集,也没有重复运行;正文还明确提示了审批状态和冲突,难度有限。实验没有测试向量召回、分块、重排、权限控制或真实生产环境。
它能支持的结论更窄:在生成前排除明确不适用的材料,可以减少模型需要同时判断的条件;同级有效依据发生冲突时,过滤仍无法替代业务裁决。
企业现在可以检查的 8 件事
如果你的知识库已经上线,可以先抽查下面八项:
这些字段可以保存在数据库、搜索索引、文档管理系统或其他可查询的知识资产层中。技术选型不是这篇文章的中心,关键是规则必须可表达、可执行、可追溯。只有把"谁发布、何时有效、对谁有效、是否替代"变成系统能读取的数据,模型才不必从文件语气里猜组织规则。
最小回归测试不要只测"答对的问题"
上线前至少固定下面几类测试。每次修改切分、索引、过滤规则、提示词或模型,都重复运行并保存候选文档、排除原因、最终上下文和输出。
| 版本边界 | 旧版结束日与新版开始日同一天 | 只命中正确版本,不出现一天重叠或空档 |
| 未来制度 | 已发布但尚未生效的正式文件 | 历史/当前问题不使用,未来日期可使用 |
| 草案干扰 | 草案内容比正式版更新、措辞更明确 | 不作为最终依据 |
| 专项规则 | 通用制度与匹配项目的例外并存 | 按明确规则选择专项依据 |
| 条件缺失 | 不提供日期、项目或角色 | 返回 clarify,指出缺失字段 |
| 同级冲突 | 两份同级、同范围、同有效期文件结论不同 | 返回 conflict 并列出全部冲突来源 |
| 无答案 | 只有过期、无权或未批准材料 | 返回 insufficient,不得补写答案 |
只统计"最终文字看起来对不对"还不够。至少分别记录:正确依据是否进入候选集、错误依据是否被过滤、状态是否正确、关键字段是否正确、引用是否覆盖必要来源,以及调用失败和格式错误。这样才能区分是检索错、规则错,还是生成错。
哪些决定必须留给人
系统可以自动排除过期材料、未审批草案和范围不匹配的规则,也可以发现两份答案冲突。但"哪份同级制度最终有效"“某部门是否有发布权限”“特殊情况能否例外”,属于组织权责问题。
更可靠的企业知识库,应当在有唯一依据时准确回答,在条件缺失时把问题问完整,在证据不足时限定结论,在权威依据互相冲突时让冲突可见。
知识库接入 AI 以后,资料治理并没有消失。它只是从文件夹里的隐性问题,变成了每一次回答都会暴露的产品问题。
参考资料
- 腾讯云智能体开发平台:时效性检索
- 腾讯云智能体开发平台:问答
- Google Research:(D)RAGged Into a Conflict
- Microsoft Learn:Filters for keyword search in Azure AI Search
- Microsoft Learn:Vector Query Filters
- Pinecone Docs:Filter by metadata




