RAG Grounding / Faithfulness 校验
从 BodySense 早期动作名 substring/alias checker 进化到 production Grounding Eval:先做确定性的 evidence provenance/contract 校验,再判断完整 InterventionClaim 的语义支持关系,最后只在模糊案例中使用 LLM Judge。
[!info] related notes
RAG Grounding / Faithfulness 校验
一句话定义
RAG Grounding / Faithfulness 校验回答的是:
模型最终提出的 material claim,是否真的被本轮允许使用的 Evidence 支持?
它不是简单判断“模型有没有引用来源”,也不是判断“动作名有没有在知识库出现”。
在 BodySense 里尤其要区分:
retrieval success
≠ citation exists
≠ evidence admissible
≠ claim supported
≠ business action authorized
Grounding 只解决“claim supported by evidence”这一层;最终是否可以 AUTO / DELIVER / ACCEPT / EXECUTE,仍由更上层 Safety / DecisionAuthority / Treatment Acceptance policy 决定。
为什么有 RAG 仍然会 Hallucinate
RAG 只是把外部内容放进模型可见上下文,并没有强迫模型只能复述这些内容。
模型仍可能:
- 使用参数知识补充不存在的细节;
- 错读 Evidence;
- 把一个动作存在,推成任意剂量都合理;
- 给正确动作配错误 stop condition;
- 引用同一身体部位但并不支持该 intervention 的文档;
- 使用另一个 run 的旧 evidence ID;
- 把 external knowledge 当成 user fact。
因此:
RAG
= 提供候选证据
Grounding
= 验证最终 claim 是否被合法证据支持
二者是不同阶段。
BodySense v1:Substring / Alias Checker 为什么当时有价值
早期 Treatment checker 的思路:
提取 exercise intervention title
→ 在 RAG result title/body/clips 中 substring match
→ 找不到则查 EXERCISE_ALIASES
→ grounded / ungrounded
例如:
“收下巴”
→ alias “颈部后缩”
→ Evidence content contains “颈部后缩”
→ grounded
这个版本很适合 MVP,因为它:
- deterministic;
- 实现简单;
- 很容易测试;
- 可以拦住“知识库完全没有出现过的动作”;
- 没有引入第二个 LLM Judge。
所以 v1 不是“错误设计”,而是验证范围很窄的第一阶段 guardrail。
v1 真正验证的是“词出现过”,不是“Claim 被支持”
假设 Evidence:
臀桥可以作为基础训练,建议从低负荷开始;
若出现放射痛加重,应停止并重新评估。
模型输出:
臀桥
- 每天 10 组
- 每组 100 次
- 疼痛加重也继续坚持
Substring checker 会看到:
“臀桥” in evidence
然后判 grounded。
但真正会改变用户行动的 material claims 是:
- 10 组;
- 100 次;
- 每天;
- 疼痛加重仍继续。
这些并没有被支持,最后一条甚至被 Evidence 明确反对。
所以 production grounding 的判断单元必须从:
Exercise Name
升级为:
InterventionClaim
InterventionClaim 应该包含什么
一个 intervention 的 material claim 可以概念化为:
InterventionClaim
├─ kind
├─ title / action identity
├─ intended goal
├─ dosage
│ ├─ repetitions
│ ├─ sets
│ ├─ intensity
│ ├─ duration
│ └─ frequency
├─ progression / regression rule
├─ contraindications
├─ stop conditions
└─ supporting evidence IDs
不是每个 intervention 都必须拥有所有字段,但 evaluator 应优先验证真正会改变现实行动的字段。
例如 education 类 intervention 的 material claim 可能更偏:
- 内容事实;
- 风险提示;
- 下一步建议。
而 exercise 类则特别关心 prescription。
Grounding 之前先做 Provenance / Admissibility
在问:
“Evidence 是否支持 claim?”
之前先问:
“这条 Evidence 有没有资格参与这次判断?”
顺序:
retrieved evidence
→ runtime provenance
→ admissibility
→ semantic support
→ grounding verdict
详见 bodysense-targeted-rag-evidence-provenance 与 agent-evidence-admissibility。
Layer 1:Deterministic Provenance / Contract Checks
任何 semantic Judge 之前,先做机器可以确定回答的问题。
Evidence ID 是否真的被本轮观察
claim.supporting_evidence_ids
⊆
this run's observed evidence set
不能只查:
数据库里历史上存在 E31
必须确认:
本轮真的 retrieval/observed E31
Evidence 是否属于正确 Run / Snapshot
防止:
- cross-run contamination;
- stale cache;
- wrong source revision;
- historical replay 偷用 current version。
Source / Version 是否 Admissible
例如:
unpublished draft
withdrawn source
unapproved version
wrong jurisdiction
即使语义支持,也可能无权用于当前决策。
user_fact 来源是否合法
External RAG 不能证明:
“这个用户有/没有某症状”
如果 claim 是 user-specific fact,应验证来源来自:
- user input;
- durable BodyState;
- measurement;
- approved observation。
Acquisition Policy 是否被绕过
如果 EvidenceBudget 只允许两个 targeted search,模型不能在最终 output 中凭空引用十条从未 acquisition 的 Evidence。
Structured Prescription 是否满足最小 Contract
例如:
- title 非空;
- kind 合法;
- required stop condition 存在;
- dosage schema 合法。
这些问题不需要 LLM Judge。
[!important] 机器已经确定知道的事实,不要再交给 LLM 猜。
Layer 2:Structured Semantic Support
通过 Layer 1 只表示:
Evidence identity 合法
还要问:
Evidence 内容是否真的支持这个 material claim?
可以先 canonicalize:
Claim
→ normalized action + dosage + goal + stop condition
Evidence
→ normalized excerpt + metadata
再组合:
- exact structured match;
- alias/synonym;
- canonical action identity;
- semantic similarity;
- contradiction detector;
- structured support rules。
为什么 Embedding Similarity 不能直接等于 Support
例子:
Evidence:
“疼痛加重时停止臀桥”
Claim:
“疼痛加重时继续臀桥”
两句话 embedding 可能非常接近,因为:
- 同一个动作;
- 同一个症状;
- 大量相同词。
但逻辑关系是:
contradiction
所以:
semantic similarity
≠ entailment
≠ support
Embedding 更适合:
candidate support signal
而不是最终 truth gate。
Support 最好按字段/子 Claim 分解
不要只有:
grounded = true/false
可以:
Action supported? yes
Goal supported? yes
Dose supported? partial
Frequency supported? no
Progression supported? unknown
Stop condition? contradicted
这样 evaluator 能准确指出:
“这个动作本身有依据,但处方细节没有依据。”
这比一句 ungrounded 更有诊断价值。
Layer 3:Optional LLM Judge,只处理模糊语义
有些支持关系很难靠简单规则:
Evidence:
“隔日进行,每次 2~3 组”
Claim:
“每周 3 次,每次 2 组”
它们可能相容,但需要上下文推理。
这时可以用固定 rubric 的 LLM Judge:
Input
├─ canonicalized claim
├─ only admissible evidence excerpts
└─ fixed support rubric
Output
├─ supported
├─ partial
├─ unsupported
├─ contradicted
└─ uncertain
Judge 的职责应该限定在语义 support。
不应该让它重新决定:
- evidence ID 是否存在;
- 是否属于本轮;
- source version 是否 approved;
- user fact 是否可以来自 RAG;
- safety override;
- Treatment 是否最终能执行。
这些属于 deterministic policy / authority。
为什么不能“一把梭”全部交给 Judge
如果只问:
“下面 Treatment 是否有依据?YES/NO”
会失去:
- stable reason code;
- deterministic audit;
- 可重复 regression test;
- cross-run evidence hard check;
- evaluator 本身漂移的可见性。
Judge 自己也有:
- nondeterminism;
- prompt sensitivity;
- model revision drift;
- latency/cost。
所以推荐层次:
Hard deterministic facts
→ structured semantic support
→ Judge only uncertain slice
Verdict 不应该只剩 faithful: bool
更丰富:
{
"verdict": "degraded",
"claims": [
{
"intervention": "臀桥",
"support": "partial",
"evidence_ids": ["E31"],
"reasons": [
"action_supported",
"dose_not_supported_by_cited_evidence"
]
}
]
}
至少可以区分:
supported
partial
unsupported
contradicted
uncertain
invalid_provenance
Reason codes:
evidence_id_not_observed
cross_run_evidence
source_not_admissible
action_not_supported
dose_not_supported
frequency_not_supported
progression_not_supported
stop_condition_not_supported
contraindicated_by_evidence
user_fact_wrong_source
这样结果能被:
- qualification;
- dashboard;
- human review;
- failure analysis;
- dataset slicing;
直接消费。
Citation 与 Grounding 不能混为一谈
Citation 回答:
“输出指向哪条来源?”
Grounding 回答:
“这条来源的内容是否支持输出的 material claim?”
完全可能:
citation exists = yes
grounding = unsupported
例如引用一篇“腰痛训练总览”,却提出文中完全没有的高剂量 prescription。
所以 UI 显示引用卡片是透明度能力,不是 correctness proof。
Admissibility 与 Grounding 也不同
一篇 Evidence 可能语义上非常支持 claim,但它是:
- withdrawn;
- unpublished;
- wrong source set;
- historical replay 中版本不匹配。
那么:
semantic support = yes
admissibility = no
它仍不能进入生产决策。
所以顺序必须是:
provenance
→ admissibility
→ support
而不是把所有文档都丢给 Judge 再问“能不能用”。
Grounding 与 Safety 也不同
一个 Treatment 可能 fully grounded,但当前用户状态出现 red flag。
Grounding = supported
Safety = blocked
完全合理。
所以:
Grounding
≠
Safety
≠
DecisionAuthority
更清楚:
Semantic Proposal
→ Evidence admissibility
→ Grounding
→ current safety/freshness/authority policy
→ Authorized Business Result
Grounding 与 Temporal Validity
Proposal 在 T1:
Evidence 支持 ✅
用户在 T2 才接受,BodyState 已变化。
历史 Grounding 仍然可以是真的:
“当时 Evidence 支持这个 proposal”
但:
“现在仍允许执行”
是新的 Acceptance/Temporal Authority 问题。
所以:
grounded at source context
≠
still authorized at current context
这直接连接 treatment-temporal-validity-and-reauthorization。
Grounding Eval v2 为什么不能写完就直接替换 Production Gate
Evaluator 自己也是 behavior-significant system。
如果 v2 太严格:
safe Treatment 大量误判 unsupported
→ automation rate 崩
如果太宽松:
危险 dosage 继续通过
因此更稳的上线流程:
build evaluator dataset
→ run v1
→ run v2
→ collect disagreement
→ manually inspect disagreement slices
→ define thresholds
→ qualification-only first
→ decide promotion to production governance separately
这和 Agent Configuration promotion 思想一致:
Evaluator 也需要证据,而不是因为“看起来更智能”就获得 authority。
v1/v2 Disagreement Dataset 为什么重要
如果两版都对 90% case 同意,真正有价值的是剩下 10%:
v1 pass / v2 fail
v1 fail / v2 pass
人工查看这些 slice 可以回答:
- v1 false positive 在哪里;
- v1 false negative 在哪里;
- v2 是否过度保守;
- semantic matcher/Judge 是否稳定。
比只比较总 pass rate 更有诊断价值。
Required Dataset Slices
1. Exact supported exercise
Evidence 与 action/prescription 一致。
2. Alias / synonym
Evidence 写“颈部后缩”,claim 写“收下巴”。
3. Action supported, dosage unsupported
动作有依据,但组数/频率没有。
4. Contradicted stop condition
Evidence 要求疼痛加重停止,claim 要求继续。
5. Same body part, wrong intervention
都谈肩部,但 Evidence 并没有支持该动作。
6. Multiple evidence, only one supports
明确真正 support 的 evidence identity。
7. No evidence
不得默认相信模型参数知识完成 production grounding。
8. Misleading lexical overlap
大量相同词但逻辑无关/相反。
9. Chinese short-token false positive
单个“臀”不能因为出现在“臀桥/臀肌/臀部”里就算 action match。
10. Progression / stop-condition support
动作正确但 progression/stop condition 不正确。
11. Cross-run evidence
模型引用一个全局存在但本轮未观察的 Evidence。
12. Inadmissible source
语义支持但 source/version 不允许。
中文 Substring 为什么特别危险
中文没有天然空格边界。
例如:
“臀”
会出现在:
臀部
臀肌
臀桥
臀中肌
单字符 substring 几乎没有 discriminative value。
早期 checker 对短 token 做 guard 是合理防御,但无法从根本上完成 semantic grounding。
更成熟:
canonical action identity
+ structured unit type
+ phrase/alias normalization
+ semantic candidate match
+ support/contradiction evaluation
EXERCISE_ALIASES 仍然有价值
v2 不是“删掉所有字符串逻辑”。
Exact/alias match 仍然可以作为:
high-confidence deterministic fast path
合理演进:
v1 reliable local rules
+
provenance
+
structured claims
+
semantic support
+
contradiction
+
reason codes
+
optional Judge
而不是:
all deterministic logic deleted
→ one expensive Judge call
Grounding Result 与 Treatment DecisionTrace 的关系
Grounding 可以成为 Treatment proposal/qualification 的一个 policy fact:
grounding.verdict = supported / partial / ...
但 DecisionTrace 还要结合:
- Safety;
- temporal validity;
- candidate assessment;
- current BodyState;
- policy revision。
所以 Grounding 是 decision input,不是完整 DecisionAuthority。
Grounding Failure 如何进入 Failure Attribution
假设 UI 最终没有显示 Treatment。
不要只写:
faithfulness failed
更精确:
Evidence acquisition success ✅
Evidence provenance valid ✅
Action supported ✅
Dose supported ❌
Grounding verdict = partial
Decision policy → degraded/block
或:
DB timeout ❌
→ no actual evidence
→ grounding unavailable
这样根因可以落在:
- knowledge coverage;
- retrieval;
- async infrastructure;
- claim generation;
- evaluator。
Production Metrics
可以统计:
grounding_verdict_total{verdict=...}
grounding_reason_total{reason=...}
judge_invocation_total
grounding_disagreement_v1_v2
ungrounded_claim_field_total{field=dose|progression|...}
invalid_provenance_total
这些指标能帮助回答:
- v2 是否过严;
- 哪类 Treatment 最常缺依据;
- Judge 调用率是否太高;
- 知识库缺的是动作还是 prescription 细节;
- 某 configuration 是否突然增加 grounding failure。
Testing 不要只断言最终 Bool
除了:
assert result.faithful is False
更重要:
- 哪个 claim 失败;
- 哪个 evidence ID 被拒绝;
- reason code;
- 哪个 field unsupported;
- contradiction;
- Judge 是否只在 uncertain case 被调用;
- deterministic failure 时 Judge 根本不应执行。
例如:
claim action exists
+ evidence ID invalid
应该在 Layer 1 fail,不能把非法 Evidence 交给 Judge 后得到“语义上支持”。
一个完整例子
Treatment proposal:
Intervention: 颈部后缩
Frequency: 每天 5 次
Stop condition: 麻木加重也继续
Supporting IDs: [E31]
Evidence E31:
颈部后缩可作为低负荷练习;
若出现神经症状加重,应停止并重新评估。
Evaluator:
Layer 1
E31 observed this run ✅
E31 admissible ✅
Layer 2
Action = supported
Frequency = not supported
Stop condition = contradicted
Verdict
= contradicted / rejected
Reason codes
= [frequency_not_supported, stop_condition_contradicted]
这里 substring v1 很可能 pass,但 claim-level v2 能发现真正风险。
自测题
- 为什么“臀桥”出现在 Evidence 中,仍不能证明“每天 10 组 × 100 次臀桥” grounded?
- 为什么 supporting evidence ID 的合法性不能交给 LLM Judge?
- Embedding similarity 为什么不能直接等价 support?
- Citation exists 与 Claim grounded 有什么区别?
- Admissibility 与 Grounding 有什么区别?
- 为什么 fully grounded Treatment 仍可能被 Safety/DecisionAuthority block?
- Grounding at T1 为什么不等于 T2 acceptance 仍 authorized?
- v2 evaluator 为什么应该先做 disagreement dataset/qualification?
- 为什么 v1 exact/alias rules 不应该全部删除?
- 为什么测试要断言 reason code/field,而不只
faithful=false?
最终心智
Production Grounding 不应该问:
“知识库里有没有出现这个动作名字?”
而应该问:
“本轮允许使用的、版本正确的 Evidence,是否支持这个具体 Intervention 的关键行动声明;哪些字段被支持、哪些只是部分支持、哪些被 Evidence 否定?”
当系统能结构化回答这个问题时,Faithfulness 才从一个字符串防幻觉补丁升级为 production Agent 的证据质量门。