引用、生成与拒答
本节目标
- 把回答拆成可独立核查的 claim;
- 区分“引用存在”“引用可访问”“引用支持主张”;
- 用结构化契约限制生成结果并做确定性校验;
- 为证据不足、冲突、无权限和依赖故障设计不同状态。
先定义生成契约
生成器不应只返回一段字符串。本库有两个相邻但不同的可执行教学 schema:第 8 课验证在线回答阶段,公共响应使用顶层 citations,claim 内保存较短的 document_id + fact_id 引用;第 9 课验证来源到引用的 Layer B 链,claim 内嵌完整 source/span citation。下面是采用第 9 课 citation 形状的通用目标结构,用于说明字段职责;它既不是第 8 课,也不是第 9 课 CLI 的逐字段 exact schema:
{
"status": "answered",
"answer": "退款审核通过后通常在一至三个工作日原路返回。",
"claims": [
{
"claim_id": "C1",
"text": "退款审核通过后通常在一至三个工作日原路返回。",
"citations": [
{
"document_id": "refund-policy",
"source_uri": "kb://tenant-a/refund-policy",
"source_version": "refund-2026-01",
"raw_sha256": "<64 hex>",
"canonical_revision_id": "can_<64 hex>",
"parse_revision_id": "par_<64 hex>",
"element_id": "el_<64 hex>",
"chunk_id": "chk_<64 hex>",
"index_entry_id": "idx_<64 hex>",
"coordinate_space": "canonical-text-lf-nfc-char-v1",
"char_start": 120,
"char_end": 144,
"span_sha256": "<64 hex>"
}
]
}
]
}为保持这段能被 JSON 解析器读取,逐字段说明放在块外:顶层 status 选择回答状态,answer 是面向用户的确定性渲染文本,claims 将事实拆成可审查单元;每个 citation 的 document_id/source_uri/source_version 说明来源,哈希与 revision 字段串起原始、规范化、解析、chunk 和索引身份,coordinate_space + char_start/char_end + span_sha256 精确定位并校验被引用片段。实际项目必须使用对应项目的 exact schema,而不是只复制此概念示例。
生产结构会按业务变化,但至少应表达:
- 回答状态;
- 用户可读答案;
- 可核查 claim;
- claim 与 source/span/revision 的映射;
- 不确定、冲突或拒答原因。
JSON Schema 只能证明结构正确,不能证明语义得到支持。
若 citation 或评测 artifact 要跨服务、跨语言传递并参与签名/验签,必须另外约定精确字节、版本和消费者验证规则。json.dumps(sort_keys=True) 一类本地序列化习惯不是跨实现的规范化保证;若选择 RFC 8785 JCS,应同时遵守它对重复键、Unicode 与 IEEE-754 数值的限制并用独立实现互测。SHA-256 只有在消费者拿到可信预期摘要并实际比较时才可检测不一致;它本身不证明 producer 身份、内容事实或读取权限。
第 9 课把全局 index_generation_id 留在受保护审计投影,而不放进公共 citation:否则一篇未授权文档引起的全局 generation 变化也可能让公共响应发生变化,成为语料存在性侧信道。验证器用公共 index_entry_id 与本次受保护审计的 selected entry set 关联,再检查它指向的 generation。若业务明确选择公开快照版本,应把该信息泄露取舍写进威胁模型。
两种 schema 如何使用
第 8 课的
privileged_audit与第 9 课的protected_audit都属于“受保护审计”概念,但它们是两个独立 schema 的固定 enum。第 8 课只能证明 fixture fact/revision 关联;只有第 9 课声明 canonical character span 与派生身份复算。不要把字段从一个项目复制到另一个项目后跳过相应 validator。
Claim 为什么重要
一句话“退款三天到账,而且一定免手续费”包含两个主张。一个引用可能只支持前半句。把长回答拆成 claim 后,才能逐项检查:
- claim 是否需要证据;
- 引用是否来自本次 selected context;
- source 的具体 span 是否支持这个 claim;
- source 是否当前有效且用户可访问;
- 多来源是否一致或冲突。
一般建议、价值判断和推断也要标明性质,不能伪装成来源中的事实。
引用校验的四层
1. 结构与 ID
- 字段完整且类型正确;
- document/chunk/span ID 存在;
- ID 唯一、无未知或重复项;
- source revision 与本次上下文一致。
2. Provenance
- 引用必须来自本次 selected context;
- 不能引用召回过但未进入上下文的文档;
- 不能引用被 ACL、tenant 或有效期过滤的资料。
- source locator、raw/canonical hash、parse/chunk/entry 身份和 coordinate space 必须能逐层复算;
- 受保护审计必须把 selected entry 绑定到本次 published generation、authorization revision、snapshot 与 tombstone state。
3. Entailment / 支持关系
- 引用片段是否真的支持 claim;
- claim 中的每一条 citation 是否都支持该 claim,且没有用一条正确引用掩护其他无关或重复引用;
- 条件、否定、数字、时间和适用范围是否一致;
- 推断是否超过证据。
第 8 课用“claim 必须逐字等于 fixture fact statement”建立在线管线的确定性下界;第 9 课进一步让抽取式 claim 必须逐字等于 canonical source span,并重算所有派生身份。真实生成更灵活,需要人工 rubric、规则、NLI 或 LLM judge 辅助,但高风险场景仍需抽样人工核查。
还必须检查 answer 对 claims 的覆盖。只验证隐藏的 claims/citations,却允许用户可见 answer 额外写“保证当天到账且免手续费”,并没有实现 grounding。本库离线项目因此让 answer 由已验证的 status + claims 确定性渲染;真实生成若允许自由措辞,则要把答案重新拆成原子 claim,拒绝没有支持映射的新增事实,并单独评估“答案正确”与“引用忠实”。
4. 用户可核查性
- 用户能否打开来源;
- 链接是否定位到正确页/段;
- 展示的标题和版本是否明确;
- 私有来源是否按权限渲染。
用户无法打开的“神秘 S1”不能提供完整可核查体验。
citation 的显示与跳转也要重新授权
一次回答时可访问,不保证用户稍后仍可访问同一 revision。citation 的详情页、下载链接和验证 API 都应按当前主体、资源生命周期和产品允许的快照语义重新做对象级授权;撤权或删除后不能因为旧回答、缓存或引用 URL 继续提供正文。若展示层无法安全地确认可访问性,返回不泄露其它资源存在性的通用状态,而不是暴露“该文档刚被撤权”、替换成镜像副本,或根据私有候选重新生成解释。
这也说明三种说法不可混同:citation locator 说明“系统声称引用哪一段”;完整派生链说明“该段如何从某 revision 产生”;可信来源准入、签名/attestation 与授权决定“能否信任、显示或依赖这条链”。前两者都不能单独担保来源的事实正确性。
拒答不是一个状态
| 状态 | 含义 | 用户信息 | 不应做 |
|---|---|---|---|
| insufficient_evidence | 可访问资料不能支持答案 | 说明资料不足、建议补充或人工核验 | 暗示私有资料存在 |
| conflict | 当前有效来源互相冲突 | 展示冲突边界与来源 | 擅自选一个 |
| tool_required | 问的是实时状态或动作 | 转到鉴权工具/确认流程 | 用知识快照冒充实时值 |
| dependency_unavailable | 检索依赖失败 | 说明暂不可检索 | 让模型凭记忆答内部事实 |
| generation_unavailable | 已取证据但生成失败 | 可按策略返回原文或稍后重试 | 输出未校验草稿 |
| policy_denied | 安全/合规规则拒绝 | 给安全替代路径 | 泄露检测细节 |
“无权访问”与“没有资料”在内部诊断上不同;对外信息要防止通过标题、ID、候选数或错误差异枚举私有内容。
参数记忆与证据边界
即使提示写“只依据上下文”,模型仍可能使用参数记忆。对内部制度、医学、法律或财务等可追溯场景:
- 要求所有事实 claim 有引用;
- 删除或拒绝无法对齐证据的 claim;
- 把一般建议单独标明,不混入制度事实;
- 对关键数字和否定做确定性检查;
- 设置人工升级或二次核验。
“模型很自信”不是证据。
冲突回答示例
如果两个有效来源分别写“每晚 500 元”和“每晚 600 元”,合格结果不是取平均 550,也不是默认选 top-1:
状态:conflict
结论:现有有效资料不一致,暂不能给出唯一标准。
证据 A:每晚 500 元(来源 A,revision ...)
证据 B:每晚 600 元(来源 B,revision ...)
下一步:请制度负责人确认适用范围或修正文档。若权威层级、地区或生效时间已有确定性规则,可以先按规则消解;规则及版本同样要进入 trace。
动手实践
先运行第 8 课项目,用它的公共边界检查顶层 status、claims 与 citations。这些命令不输出上面的第 9 课完整 span citation:
$env:PYTHONDONTWRITEBYTECODE = '1' # 禁止为这次练习写入 Python bytecode 缓存。
$script = '.\docs\RAG\examples\offline_cited_qa.py' # 保存第 8 课离线可引用问答脚本路径。
$fixture = '.\docs\RAG\examples\rag-fixture.json' # 保存该脚本要校验的严格 fixture 路径。
python -B $script --fixture $fixture ask --query-id Q-refund # 查看有充分证据时的公共 answered 响应。
python -B $script --fixture $fixture ask --query-id Q-conflict # 查看两份有效来源冲突时的公共 conflict 响应。
python -B $script --fixture $fixture ask --query-id Q-phone-guest # 查看 guest 无权访问时不泄露私有来源的响应。
python -B $script --fixture $fixture ask --query-id Q-order-live # 查看实时订单问题被路由为 tool_required 的响应。selected 只属于受保护审计面。仅在本地教学环境、确认具备 operator 权限后,再显式查看:
python -B $script --fixture $fixture inspect --query-id Q-refund --operator-view # 在本地教学环境请求退款案例的受保护 audit trace。
python -B $script --fixture $fixture inspect --query-id Q-conflict --operator-view # 在本地教学环境请求冲突案例的受保护 audit trace。真实服务不能把 --operator-view 这类声明当作认证;host 必须在调用前完成身份与审计授权。
然后在测试的副本中做三次篡改:
- 把 citation 改成未选中的 document ID;
- 把 claim 改成“保证当天到账”;
- 把 source_revision 改成
wrong。
说明每次应在哪一层被拒绝。
常见错误
- 只用正则确认回答里有
[S1]; - 一个段落只有一个引用,却包含多个独立 claim;
- 引用来自 retrieved 而非 selected context;
- 生成器能自行编造 source ID;
- 无答案时悄悄切换成无引用自由回答;
- 拒答内容暴露被过滤文档的标题或 ID。
自测
- 引用 ID 存在为何仍不足以证明回答有据?
- Claim-level citation 比段落末尾统一引用解决什么问题?
- 结构化输出校验和语义支持校验有何区别?
- 为什么实时订单问题应该返回 tool_required?
- 权限不足时,用户可见结果为何不能包含被过滤 source ID?
- 为什么旧回答中的 citation URL 在用户点击时仍需对象级授权?
小结与下一步
可靠回答需要“主张—证据—版本”链和明确拒答语义。下一节从错答反向定位数据、召回、上下文、生成或引用层:失败分类与系统排查。
参考资料
- Es et al., RAGAS: Automated Evaluation of Retrieval Augmented Generation
- Saad-Falcon et al., ARES: An Automated Evaluation Framework for RAG Systems
- W3C PROV Overview 与 PROV-O:citation lineage 的实体、活动与派生词汇。
- OWASP LLM08:2025 Vector and Embedding Weaknesses:permission-aware retrieval、多租户隔离与向量数据风险。
- OWASP RAG Security Cheat Sheet:来源归因、验证端点、chunk 级 ACL 与缓存失效的生产控制建议。
- RFC 8785: JSON Canonicalization Scheme:跨实现哈希/签名的 JCS 边界;采用它前需处理 I-JSON、数字和 Unicode 限制。
来源获取日期:2026-07-22。自动 judge 是测量工具,不是无误真值;应固定 rubric/版本并与人工标注对齐。