上一章 Trace、Replay 与线上闭环 出了问题查不到原因,是因为没有 trace;改了一版不敢上线,是因为没有 replay。这一章把"线上 badcase → 评测集 → 回归门禁 → 灰度"的闭环接起来。 III · 评测工程 · 第 05 章 · 进阶 · 约 28 分钟
Agent 工程学习站 做棵大树 出品 主站 beatree.cn 免费 · 无需登录 · 进度存本机
IV 版 · 知识引擎 ◆ 第 01 章 ◆ Entity, Fact, Inference
IV · 知识引擎 01 / 22 进阶

知识建模:实体、事实、推断

Entity, Fact, Inference
预计阅读 30 分钟
难度 进阶
关键词 实体抽取 · 事实层
本机状态 未读

把业务知识塞进向量库就完事了?不是。检索找不到、找到了不敢信、信了发现过时——这三个问题的根因都相同:知识没有被建模。这一章讲清实体、事实、推断这三层为什么必须分开,混在一起会出什么事。

编辑部注 · 本章的「三层知识结构」是知识引擎部分的地基,后面三章(RAG、Embedding、混合检索)都建立在它之上。

先看一个典型的知识库事故:用户问「上个季度华东区的转化率是多少」。检索命中了一段文档,内容是「华东区转化率偏低,建议关注」。模型据此回答「华东区转化率偏低」。

问题出在哪?文档里那句话是半年前的某个人的判断,不是数据。而在向量库里,它和一条真实的季度数据看起来没有任何区别——都是「一段和华东区、转化率相关的文本」。

一、三层知识:为什么必须分

知识的三个层次:各自的来源、特征与用途
层定义来源可验证性用途
实体层
Entity
可锚定的对象:人、部门、项目、指标、系统、文档 主数据、组织架构、元数据 高(有唯一标识) 解决「说的是同一个东西吗」——如「华东」和「华东区」是不是一个地区
事实层
Fact
可溯源的关系与数值:谁在什么时候是什么、某指标某期等于多少 数据库、系统记录、正式文档 最高(能回溯到源系统) 回答「是什么」——这是唯一可以直接作为结论依据的层
推断层
Inference
带依据链的衍生结论:分析、建议、判断、预测 人的分析、模型的生成 低(依赖依据链是否成立) 提供视角与方向——但必须带依据链,且不能当作事实

三层混在一起的后果,就是开头那个例子:半年前的「判断」被当成了事实(Fact),而模型无从分辨——因为它们在库里长得一模一样。更隐蔽的是:一段推断(Inference)如果没带依据链(Evidence Chain),和一条事实在库里也毫无区别,却可能被当成结论直接给出。

三层知识结构与依据链 ③ 推断层 带依据链的衍生结论 「Q3 华东转化率下滑主要因为新客占比上升」 依据链:fact#1024(Q3 新客占比 42%)+ fact#1025(新客转化率 1.1% vs 老客 4.3%) 规则:没有依据链的推断不允许入库;带推断标记展示,用户可见其证据 ② 事实层 可溯源的关系与数值(唯一可直接作为依据的层) fact#1024 指标=新客占比 维度=华东 期=2025Q3 值=42%    来源:bi.sales.daily_agg 口径版本:v3 更新时间:2025-10-08 fact#1025 指标=转化率 维度=华东·新客 期=2025Q3 值=1.1% 规则:每条事实必须带「来源 + 口径版本 + 更新时间」,三者缺一不可 ① 实体层 可锚定的对象与它们的同一性 ent:region/east 别名:华东、华东区、East China、东区 上级:ent:region/china ent:metric/conversion_rate 别名:转化率、CVR、成交转化率 口径表:v3(2025-09 变更) 作用:把用户的说法映射到系统里的唯一对象——这是检索准确的第一步 冲突消解:不同层产生分歧时,信谁 事实 vs 推断冲突 → 信事实,并把推断标记为「与最新事实不符,可能已过时」 新事实 vs 旧事实冲突 → 信新的,但旧事实保留并标记失效时间(可回溯口径变更历史)
图 1 三层结构自下而上支撑:实体提供「同一性」、事实提供「可溯源依据」、推断提供「视角与方向」。关键规则有两条:事实必须带来源 + 口径版本 + 更新时间;推断必须有依据链、必须带标记、且在与事实冲突时让步。

二、实体层:解决「说的是同一个东西吗」

实体层(Entity)这一层最容易被跳过,但它是检索准确率的第一道关。三个具体的必要性:

第一,别名归一。 用户说「华东」「东区」「East China」,系统里只有 east。不做归一(Alias Normalization),检索会漏掉大部分相关内容。

第二,歧义消解。 「转化率」在不同业务线可能指不同指标。歧义消解(Disambiguation)要能根据上下文确定具体指向哪一个——这正是办事型 Agent 里NL2DSL的核心难点之一。

第三,层级关系。 实体层本质是主数据(Master Data)(组织架构、元数据等权威基础数据)。「华东区的销售额」是否包含「华东区下各城市的销售额」?这依赖实体层的层级定义。没有这层关系,聚合查询会算错。

实体类型必须维护的字段常见坑
地区id、标准名、别名列表、上级、层级深度别名不全导致检索漏召回;层级不清导致聚合范围错
指标id、标准名、别名、口径定义、口径版本、生效时间口径变更无记录——这是数据类争议的主要来源
部门/人id、名称、别名、所属、有效期组织架构调整后旧关系失效但未标记,导致引用错误
项目/系统id、名称、别名、负责人、状态同名不同项目(如多个「增长」项目)未区分

三、事实层:口径版本是灵魂

事实层的设计里,最重要的不是「存了什么值」,而是每个值都带着它被定义时的口径版本。

同一个「转化率」,2025 年 9 月前后可能是两个不同的计算方式(比如是否包含退款订单)。如果系统不记录口径版本,就会出现这种情况:

  • 用户看到 2025Q2 转化率 4.2%、2025Q4 转化率 3.1%,得出「下滑明显」的结论;
  • 实际上 Q4 换了更严格的口径(剔除退款),两个数字不可比。

这不是检索问题,是建模问题。 而它造成的后果比检索错更严重——用户会基于错误的对比做出决策。

同一个「转化率」,两个不可比的口径 两个数值都真实、都出自同一张表,但分母定义不同 → 放在一起比就是错的 口径 v2 · 含退款订单 生效 2025-03 ~ 2025-08 下单数 ÷ 访问数,不剔退款 2025Q2 = 4.2% 在库里,它与右边的数字长得一模一样 口径 v3 · 剔除退款 生效 2025-09 起 剔退款后成交数 ÷ 访问数 2025Q4 = 3.1% 口径变更这件事只写在元数据里 2025-09 口径变更:分母改为「剔除退款订单」——这一点之后,两条曲线的含义不同了 ✗ 界面上看到的:4.2% → 3.1%,一年「下滑 26%」 两个数的分母不同:一个含退款、一个剔退款。数字都是真的,对比是假的。 系统不会报错也不会提示——用户据此排期、复盘、写进汇报,错误一路向下游传播。 ✓ 让「可比性」变成数据可判定的属性 每条数值事实都带「来源 + 口径版本 + 更新时间」;口径版本不同的两个值禁止直接比较。 必须跨口径看趋势时:按旧口径重算一版,或在界面上标出断点并写明「口径变更,不可比」。
图 2 口径版本不同的两个数值,在数据层看起来完全一样,在业务上却是两个指标。把口径版本写进每一条事实,等于把「这两个数能不能比」从一个需要人判断的问题,变成一个代码能判定的问题。
knowledge_model.pypython
from dataclasses import dataclass, field
from typing import Literal
from datetime import date
@dataclass
class Entity:
    """实体层:解决「说的是同一个东西吗」"""
    id: str
    canonical: str                       # 标准名
    aliases: list[str] = field(default_factory=list)
    kind: Literal["region", "metric", "org", "project", "system"] = "region"
    parent: str | None = None            # 上级实体,用于层级聚合
    attrs: dict = field(default_factory=dict)
    def match(self, mention: str) -> bool:
        m = mention.strip().lower()
        return m == self.canonical.lower() or any(m == a.lower() for a in self.aliases)
@dataclass
class Fact:
    """
    事实层:可溯源的关系与数值。
    三个字段缺一不可 —— 缺来源则不可信,缺口径版本则不可比,缺时间则不知时效。
    """
    id: str
    subject: str                         # 实体 id
    predicate: str                       # 关系/指标名:指标=转化率
    value: str                           # 值
    period: str                          # 期:2025Q3
    source: str                          # 来源系统:bi.sales.daily_agg
    caliber_version: str                 # 口径版本:v3  ← 最容易被漏掉的一个
    updated_at: str                      # 更新时间
    dims: dict = field(default_factory=dict)   # 附加维度:{"客群": "新客"}
    def comparable_with(self, other: "Fact") -> bool:
        """两个事实能不能直接比较:同指标、同口径版本、同维度才可比"""
        return (self.predicate == other.predicate
                and self.caliber_version == other.caliber_version
                and self.dims == other.dims)
    def render(self) -> str:
        dims = "·".join(f"{k}={v}" for k, v in self.dims.items())
        return (f"{self.subject} {self.predicate} {self.value}"
                f"({self.period}{'·' + dims if dims else ''})"
                f" [来源 {self.source}|口径 {self.caliber_version}|更新 {self.updated_at}]")
@dataclass
class Inference:
    """推断层:必须带依据链,且永远不能替代事实"""
    id: str
    conclusion: str
    based_on: list[str]                  # 依据:事实 id 列表 —— 没有它就不允许存在
    producer: str                        # 谁产出的:人 / 模型 + 版本
    produced_at: str
    confidence: float = 0.7
    def is_valid(self) -> bool:
        return len(self.based_on) > 0 and 0.0 <= self.confidence <= 1.0
    def render(self) -> str:
        return (f"[推断·{self.confidence:.1f}] {self.conclusion}\n"
                f"  依据:{', '.join(self.based_on) or '(缺失,不应展示)'}\n"
                f"  产出:{self.producer} {self.produced_at}")
def resolve_conflict(a: Fact, b: Fact) -> tuple[Fact | None, str]:
    """
    两层之间的冲突消解原则。
    返回 (应采用的事实, 说明)。选择 None 表示无法裁决,应暴露冲突。
    """
    if a.predicate != b.predicate:
        return None, "两个事实不是同一指标,不可比较,不应裁决"
    # 口径版本不同 → 不可比,必须显式暴露
    if a.caliber_version != b.caliber_version:
        return None, (f"口径版本不同({a.caliber_version} vs {b.caliber_version}),"
                      f"数值不可直接比较。请确认应使用哪个口径。")
    # 口径相同、期相同、值不同 → 数据源冲突
    if a.period == b.period and a.value != b.value:
        return None, (f"同期同口径出现两个值({a.value} vs {b.value}),"
                      f"来源分别为 {a.source} / {b.source},需要人工确认以哪个为准。")
    # 期不同 → 取更新的
    newer, older = (a, b) if a.updated_at > b.updated_at else (b, a)
    return newer, f"取更新的一条({newer.updated_at} > {older.updated_at}),旧值保留为历史"
def render_for_prompt(facts: list[Fact], inferences: list[Inference],
                      budget_chars: int = 5000) -> str:
    """
    回喂给模型的形态:事实在前、推断在后,推断必须带依据,
    并且整体带「来源/口径/更新」标签 —— 让模型自己判断该信谁。
    """
    blocks = []
    for f in facts:
        blocks.append(f"[事实] {f.render()}")
    for i in inferences:
        if i.is_valid():                 # 无效推断(无依据链)直接不展示
            blocks.append(f"{i.render()}")
    text, used = [], 0
    for b in blocks:
        if used + len(b) > budget_chars:
            break
        text.append(b)
        used += len(b)
    head = ("以下为可核验材料。【事实】可直接作为结论依据;"
            "【推断】仅代表某一时期的分析观点,需判断其依据是否仍然成立。\n\n")
    return head + "\n\n".join(text)
两条知识冲突时,按这五个判据依次裁决 顺序不能颠倒:先判层次,再判可比性,最后才比时间——跳过前两步直接比时间,是最常见的错 入口:同一个问题下,检索回了两条互相矛盾的结论 ① 层次不同 事实 vs 推断 信事实,推断让步 推断标记为「与最新事实不符,可能已过时」, 仍可展示,但必须标明它只是视角,不是依据 ② 层内 · 指标不同 如转化率 vs 留存率 不可比 → 不裁决 两个数值分开呈现,都不作为结论依据, 更不要用相似度或时间戳强行选一个 ③ 层内 · 口径版本不同 v2 含退款 vs v3 剔退款 不可比 → 暴露冲突 提示「口径不同,数值不可直接比较」, 请用户确认该按哪个口径回答 ④ 层内 · 同期同口径 期相同、值不同 数据源冲突 → 交给人 两个来源各写各的,系统不静默选边, 把两条的来源与更新时间一起给用户 ⑤ 层内 · 期不同 如 Q2 vs Q4 取更新的,旧值留档 取 updated_at 更大的那条作为当前值, 旧值软删除并记失效时间,保留可解释性 能被自动裁决的只有一部分:①②③④里有两类必须交给人。 所以「同级冲突不能裁决时必须暴露冲突」不是保守,而是唯一不会让错误静默通过的选法。
图 3 裁决顺序本身就是一层信息:先问「是不是同一层」,再问「是不是同一个指标、同一个口径」,只有这两步都过了,才轮到比时间。把顺序写死成代码(见上一节的 resolve_conflict),就不会因为「新的看起来更可信」而误判。

四、推断层:结论必须带着它的依据

实体层讲「同一性」、事实层讲「可溯源」,但真正最容易出错的是推断层——因为它长得最像「有用的答案」,却最不可信。这一节把它单独讲透。

推断是什么:从事实出发、经过推理得到的衍生结论——「华东转化率下滑,主要因为新客占比上升」就是一条推断,它本身不是一个可直接查询的数值,而是对几个事实的解释。

它和事实的本质区别只有一条:事实可以直接作为结论依据(因为它可回溯到源系统),推断必须带着依据链,且永远不能替代事实。这条区别决定了推断层的三条硬规则:

  1. 没有依据链的推断不允许入库。 一条裸结论(「华东转化率偏低,建议关注」)没有任何可验证的锚点,和事实放在一起,模型无从分辨它到底是数据还是某人的判断——这正是开头那个事故的根因。依据链就是把结论钉回它来自哪些事实的那根绳子。
  2. 推断必须带「产出者」和「产出时间」。 依据链只能说明「它从这些事实推出来」,不能说明「这推理现在还成立」。一个 Q3 的分析结论,到了 Q4 可能已经过时;一个模型生成的推断和一个资深分析师写的推断,可信度也完全不同。所以推断要记 producer(人/模型 + 版本)和 produced_at。
  3. 依据链成立 ≠ 结论可信。 依据链只证明「推理有出处」,不证明「推理本身正确」——前提可能选错了、可能遗漏了关键因素。所以推断即使带全了依据,也只能作为视角呈现,不能作为结论呈现。
一条合格推断必须携带的字段
字段作用缺失的后果
based_on(依据链)钉回它来自哪些事实变成无法验证的裸结论,与事实无法区分
producer(产出者)区分人/模型、及版本无法判断可信度等级
produced_at(产出时间)判断是否过时过期推断被当成现行结论
confidence(置信度)给下游一个「可不可信」的量化信号下游只能全信或全不信

推断层的生命周期比事实短得多,所以要单独管「失效」。 事实会因口径变更而「不可比」,推断会因依据失效而「作废」:某条推断引用了 fact#1024(Q3 新客占比 42%),到了 Q4 这条事实更新了、或者口径变了,那条推断的结论就不再成立。所以推断层要有一个「复核时间」字段,并在每次口径版本变更时,批量扫描所有引用了该指标的推断,标记为「依据已变更,待复核」。没有这一步,系统会长期沉淀一批「看起来有依据」的历史结论——它们比没有依据更危险,因为读者会默认「带了依据就是可信的」。

一句话记住三层的关系:实体决定「说的是不是同一个东西」,事实决定「这个值能不能信、能不能比」,推断决定「这个结论有没有出处、还新不新」。 三者各管一段可信度,混在一起就全塌了。

五、常见误区与追问

这一章的结论很容易被点头同意,然后在工程里被忘掉。下面五条,都是「听起来对、做起来错」的典型。

5.1 误区:把「知识库」当成「文档库 + 向量化」

错在哪:以为把文档切块、嵌入、入库,知识就建好了。为什么自然:几乎所有 RAG 教程都从「切块—嵌入—检索」讲起,看起来那就是全部工作。但向量库只回答「哪段文字语义相近」,不回答「这条信息是不是事实、值不值得信」。 判据:随机抽 10 条检索结果,如果你不能在 10 秒内为每条说出「它是事实还是推断 / 来自哪个源系统 / 口径版本是什么」,那么你缺的是建模,不是更好的嵌入模型。一条不带来源的数值和一条带来源的数值,在上下文里长得完全一样,前者的错误要等到用户拿它做决策时才暴露。

5.2 误区:口径版本是数据团队的事,与检索和 Agent 无关

错在哪:把它当成数仓内部的元数据约定。为什么自然:口径确实由业务方定义,落库时也常常只写在表注释里。但对 Agent 来说,口径版本是判断「两个数能不能比」的唯一依据,必须一路带到上下文里。 判据(可操作):把两个口径不同的季度值同时放进上下文,看模型会不会主动做对比、甚至算出「下滑 26%」——会,就说明 口径版本(Caliber Version) 没有跟着知识块进上下文,或者提示词里没有写「口径不同的数值不可直接比较」这条硬规则。这类错误不需要模型犯错,只需要它足够勤快地做对比。

5.3 误区:有依据链,推断就可以当事实用

错在哪:把「可溯源」直接当成「可信」。为什么自然:依据链确实提升了可验证性,看起来比一条裸结论可靠得多。但它只证明「结论是从这些事实推出来的」,不证明「推理本身成立」。 判据两条:依据链是否覆盖了全部关键前提;前提是否仍然有效(未过期、未因口径变更而失效)。缺任何一条,这条推断就只能作为视角呈现,不能作为结论依据。这也是 可溯源(Provenance) 的边界——它保证你能回到源头,不保证源头支持你的结论。

5.4 误区:别名表一次建好就够

错在哪:把别名归一当成一次性数据清洗。为什么自然:别名看起来是静态词典,建表时穷举一遍就完了。但它会持续增长:新简称、新外文写法、错别字变体、组织改名。 判据可操作:每周从检索日志里捞出「出现过但没有映射到任何实体 id」的名词提及,做成未命中列表;累计超过 50 条就补一次表。同时给每条别名加「生效期」与「上下级」两个字段——改过的别名不要删除,只标记失效时间,否则历史问题会莫名其妙地对不上实体。

5.5 误区:三层分完就一劳永逸

错在哪:以为分好实体、事实、推断,建好表这件事就结束了。为什么自然:结构定下来之后,日常只剩往里写数据。但三层的边界会被时间侵蚀:一份 Q3 的分析报告,到 Q4 变成「过时推断」,新口径发布后又变成「口径不同的事实」。判据:给推断层加一个「复核时间」字段,并在每次口径版本变更时扫描所有引用了该指标的推断,批量标记为「依据已变更,待复核」。没有这一步,系统会长期沉淀一批「看起来有依据」的历史结论,而它们比没有依据更危险。

六、自测

本章自测第 1、3 题是核心考点
Q1为什么知识要分成实体、事实、推断三层?
C。这是知识建模的核心动机。开头那个案例就是典型:半年前的「判断」被当作「事实」使用。三层的本质区别是可信度与可验证性等级不同,而不是存储方式不同。分开之后,系统才能做到「用事实作结论、用推断提供视角、并且始终标注哪个是哪个」。
Q2事实层的三个必备字段是什么?
B。缺来源则不可信,缺口径版本则不可比,缺更新时间则不知时效。其中「口径版本」最容易被漏掉,而它造成的后果最严重——用户会拿两个不同口径的数字做对比,得出错误结论,而这在界面上看起来完全正常。
Q3检索到一条事实和一条推断,两者结论相反,应该怎么处理?
D。这是三层结构存在的直接价值:当层次不同的两条知识冲突时,层级本身就提供了裁决依据——不需要额外判断。C 看起来合理但会出错:一条刚生成的推断可能比事实「更新」,但可信度低得多。

七、小结

层必须带什么用途冲突时
实体id、标准名、别名、层级解决同一性与歧义提供裁决的上位依据
事实来源 + 口径版本 + 更新时间唯一可直接作为依据的层优先于推断
推断依据链 + 产出者 + 时间 + 置信度提供视角与方向与事实冲突时让步并标注

其中三条硬规则:没有依据链的推断不允许入库;口径版本不同的数值不可直接比较;同级冲突不能裁决时必须暴露冲突。

知识建模的本质,是把「可信度」这个属性从人的判断变成数据结构。做成了,系统才可能「有据可查」。本刊编辑部

建模清楚了,下一章看检索的完整链路——以及那条链上六个环节各自能怎样把结果做错。

八、参考与延伸

这一章的方法论没有单一一手论文可读,所以下面按「先对齐概念、再看工业实现、最后读规范」排了三份材料。全站不做原文转载,这里只登记链接与「为什么值得读」。

先看概念(把「指标口径」想清楚)

  • dbt 官方文档 · About MetricFlow —— 工业界怎么把「指标」定义成可版本化、可复用的声明式对象。读本章第三节卡住时来这儿最快:它把「同一个指标名 + 不同定义」当成一等公民处理,而不是把它塞进表注释。

再看实现(别人把校验放在哪一层)

最后读规范(对齐一手定义)

  • W3C · PROV-O: The PROV Ontology —— 「来源(provenance)」这件事的官方本体定义:Entity、Activity、Agent 三类核心对象及其派生关系。只需要看核心类与 prov:wasDerivedFrom 这一个关系——本章说的「依据链」,在规范里就是它的传递闭包。

◇ 面试官会怎么问

共 6 条 · 其中 2 条高频 · 先自己答一遍,再展开对照

为什么要把知识拆成实体、事实、推断三层? 高频
因为三层的可信度与生命周期完全不同,混在一起就无法治理:
实体层(人、项目、组织、产品)——可锚定的对象,有唯一标识,相对稳定,来自主数据,可信度最高。
事实层(参与了某项目、在某时间发生了某事)——可溯源的关系与事件,来自业务系统记录或结构化抽取,每条都能回指来源,可校验。
推断层(基于实体与事实得出的结论,如"该成员适配某类岗位")——由模型生成,必然带不确定性,必须标注依据链与置信度,且可被新事实推翻后重算。
分开的核心价值是:事实层可溯源,所以敢拿去支撑结论;推断层带依据,所以敢展示但知道要谨慎。如果把三者混成一个"知识库",你无法回答"这条结论到底站不站得住"。

追问链

  1. 推断层怎么保证质量?
  2. 实体对齐怎么做?
推断的质量怎么保证?
三道闸,缺一不可:
① 生成时强制给依据——要求推断必须附带它引用了哪些事实(事实 ID 列表),没有依据的推断直接丢弃。这既是质量控制,也是可解释性。
② 置信度与呈现策略——按依据数量、事实新鲜度、以及是否有冲突事实计算置信度;低置信度的推断不以结论性语气呈现,而是作为"可能的观察"提示,避免误导用户做出重要决策。
③ 抽样人审 + 回流——定期抽样人工核验,把误判案例回流入评测集与规则库。审的结果要反哺到生成策略(比如某类推断总是错,就要收紧触发条件)。
还要有失效机制:推断所依赖的事实发生变化时(人员转岗、项目结束),相关推断必须被标记为待重算而不是继续留着——"过期但看起来很确定"的推断比没有推断更危险。
加分点:"过期推断比没有推断更危险"是一句很有分量的话,能体现对知识时效性的理解。
实体对齐是什么?不做会怎样?
实体对齐是把来自不同数据源的"同一个对象"识别并合并成唯一实体——比如 HR 系统里的"张三(工号 001)"、项目系统里的"zhangsan"、邮件签名里的"三哥",需要判定为同一个人。
不做对齐有三类后果:
① 信息碎片化——同一个人被拆成多个实体,各自的记录都不完整,检索时召回不全,看起来像"知识缺失",实际是对齐没做。
② 事实冲突——同一个实体的属性在不同来源里被存成两份,取值不同且无法判断谁新谁旧。
③ 统计口径失真——"参与过几个项目"这类聚合会失真。
常用手段是用强标识优先(工号、唯一 ID)→ 弱标识兜底(姓名 + 部门 + 时间窗)→ 冲突时人工裁决,并且对齐结果要可回溯(记录合并了哪些来源),否则出错了无法拆开。
一条事实里如果缺了「口径版本」这个字段,最严重的后果是什么? 高频
数值本身仍然正确,错误发生在对比的时候:两个不同口径的数字会被放在一起比较。
例如 2025Q2 转化率 4.2%(含退款订单)与 2025Q4 转化率 3.1%(剔除退款),界面上看起来是「一年下滑 26%」,实际两个数字的分母定义不同,根本不可比。
缺来源则不可信,缺更新时间则不知时效,但只有缺口径版本会产生「看起来完全正常的错误结论」——系统不报错,用户据此排期、复盘、写进汇报。
判据:把两个数放进上下文,模型会不会主动算出下降幅度;会,就说明口径版本没有跟着事实进入上下文,或者提示词里没有写「口径不同的数值不可直接比较」。

追问链

  1. 历史数据已经按旧口径入库,怎么补口径版本?
  2. 口径变更时,引用过该指标的历史推断应该怎么处理?
加分点:加分点:能说出「口径版本的作用是把可比性从一个需要人判断的问题,变成代码能判定的属性」,而不是只答「方便追溯」。
两条知识冲突:一条是上个月生成的分析结论,一条是本周的事实记录。应该信哪个,为什么不能按时间裁决?
信事实。
裁决顺序不能颠倒:先判层次(事实优先于推断),再判可比性(同指标、同口径版本、同维度),最后才轮到比时间。
按时间裁决会出错,因为推断的「新」只代表它被生成得晚,不代表它更可信——一条刚生成的分析完全可能建立在过时前提上。
正确处理:采用事实作为依据,并把该推断标记为「与最新事实不符,可能已过时」;如果它仍有视角价值,可以呈现,但必须标明它只是推断。

追问链

  1. 同一指标、同一口径、同一期出现两个不同的值,属于哪一类冲突?怎么处理?
  2. 「可溯源」是否足以让一条推断当作事实使用?
加分点:加分点:答出「依据链只证明结论是从这些事实推出来的,不证明推理本身成立」。
业务方说「华东区销售额」时,系统至少要能回答哪两个问题,聚合查询才不会算错?
一是同一性:用户说的「华东」「东区」「East China」是不是同一个实体 id,也就是别名归一。
二是层级范围:「华东区销售额」是否包含其下各城市的销售额,这由实体层的上下级定义决定。
缺别名归一会漏召回;缺层级定义会让聚合范围直接算错——而这类错误很难从结果里看出来,因为数字看起来很正常。
工程做法:实体表同时维护「标准名、别名列表、上级、层级深度」,并给每条别名加生效期;改别名不要删除,只标记失效时间。

追问链

  1. 别名表为什么不能只建一次?你用什么信号判断该补表了?
  2. 「转化率」在不同业务线含义不同,这属于实体层的哪类问题?
加分点:加分点:把实体层讲成「检索准确率的第一道关」,而不是一张静态的别名词典。
答这类题的通用结构

结论先行(一句话给出取舍)→ 机制(为什么是这样,涉及哪条链路)→ 代价或边界(这么做放弃了什么)→ 你的实践或数字(真实场景里怎么落地)。 只讲机制不讲代价,是背题;只讲取舍没有数字,是空谈。

本章收尾 · Wrap up
掌握度自评
点一下给自己打分;低于 3 分建议加入复习队列
个人笔记 · Notes
    下一章 RAG 的链路与失效模式 RAG 不是"检索 + 生成"两句话,它是一条有六个环节的链路,每个环节都能独立地把结果做错。这一章把失效模式逐个拆开,并给出定位手段。 IV · 知识引擎 · 第 02 章 · 进阶 · 约 32 分钟