Semantica · 专题 03
Technical deep-dive · 03

Provenance 证据链

Semantica 的来源追踪不是给实体附加一个来源 URL,而是把实体、来源、活动、Agent、版本、派生、作废和摘要校验组织成可查询记录。该模型与“证据从哪里来、谁处理过、为何发生变化”的需求高度匹配。

版本 0.6.6 证据基线 5c6b40f36 分析日期 2026-08-24
Recommendation
优先参照数据模型并隔离验证 SQLite 实现;生产接入必须强制写入、统一事务、外部锚定并限制物理修改。

专题结论

Semantica 的来源追踪不是给实体附加一个来源 URL,而是把实体、来源、活动、Agent、版本、派生、作废和摘要校验组织成可查询记录。该模型与“证据从哪里来、谁处理过、为何发生变化”的需求高度匹配。

建议:优先参照数据模型并隔离验证 SQLite 实现;生产接入必须强制写入、统一事务、外部锚定并限制物理修改。

1. 模型与管理边界

技术标识 中文简介 关键判断
semantica.provenance(来源模型、存储、完整性与管理器所在模块) 独立的来源追踪边界 适合从业务模块中抽离复用
ProvenanceEntry(保存实体、活动、Agent、版本、来源、派生和校验信息的核心记录,约第 37 行) 一条实体版本的来源记录 比单一来源字段表达力强
SourceReference(保存文档标识、页节行定位、时间、置信度和元数据的来源引用,本身没有摘要字段,约第 231 行) 指向原始证据 可支持逐字段证据跳转;完整性摘要需由其他来源记录承担
AgentRecord(描述人、系统或 Agent 身份的记录,约第 360 行) 回答谁参与了处理 生产中应绑定统一身份系统
ActivityRecord(保存活动标识、活动类型、起止时间和元数据的记录,本身没有独立输入输出字段,约第 405 行) 回答经过什么过程 输入输出关系需由来源记录关联,并应补充算法与配置版本
ProvenanceManager(协调版本写入、血缘查询、作废、审计、导出和校验的管理器,约第 64 行) 来源能力主入口 值得作为隔离 PoC 对象

原始调用链

以图构建接入为例,GraphBuilderWithProvenance.build()(包装底层图构建并遍历结果追加来源的方法)调用 ProvenanceManager.track_entity()(在来源事务中创建或版本化实体记录的方法);管理器再通过 ProvenanceManager._save_entry()(补齐序列与哈希链后写入存储的方法)进入 ProvenanceStorage.store()(来源存储抽象的写入接口)。输入是图构建结果及来源上下文,输出是图和独立来源记录;包装器被绕过时,这条链不会自动执行。

2. 版本、派生与作废语义

track_entity()(创建实体来源记录并处理版本关系的方法,约第 268 行)会保存来源、活动、Agent 和版本关系。模型明确区分两个重要字段:

  • previous_version_id(指向同一实体上一版本的重要字段)表达版本演进;
  • derived_from_id(指向语义派生来源的重要字段)表达新实体由其他实体计算或抽取得到。

两者不能合并:版本演进回答“它以前是什么”,语义派生回答“它由什么产生”。

invalidate()(追加实体作废信息而保留历史的方法,约第 1032 行)适合审计和撤回传播。生产设计应把作废视为新事件,而不是更新或删除旧行;同时要求作废理由、操作者、审批、时间和受影响下游对象。

3. 血缘查询与审计

方法 中文简介 适合的交互
get_lineage()(汇总单个实体来源、版本和派生关系的方法,约第 753 行) 获取局部血缘 实体详情的来源面板
trace_descendants()(追踪依赖某实体的下游记录的方法,约第 843 行) 评估撤回影响 变更前影响预览
revision_history()(按实体返回版本历史的方法,约第 891 行) 查看演进过程 时间轴和版本差异页
audit_log()(按条件读取审计记录的方法,约第 1172 行) 审计检索 操作追踪和导出
export_prov()(将记录导出为 PROV RDF 表达的方法,约第 1238 行) 跨系统交换 合规导出和证据交换
verify_chain()(验证本地记录链连续性和摘要的方法,约第 1450 行) 发现断链或意外修改 完整性告警,不是不可否认签名

4. 存储与完整性边界

ProvenanceStorage(定义存储、读取、血缘、事务和链头能力的抽象接口,约第 35 行)有内存与 SQLite 两种实现。

SQLiteStorage(把来源记录、版本和链信息持久化到 SQLite 的存储实现,约第 391 行)适合单机 PoC 和小规模审计,但不等同于分布式不可变账本。它的事务边界只覆盖自身存储;若业务数据库先成功而来源写入失败,仍会出现证据缺口。

compute_checksum()(对规范化来源记录计算 SHA-256 摘要的函数,约第 27 行)和 verify_checksum()(验证记录摘要是否匹配的函数,约第 119 行)能够发现意外修改。由于密钥签名、外部可信时间戳和外部锚点不在该实现中,拥有完全写权限的人仍可能重写数据后重算链。

原项目关键片段——ProvenanceManager.verify_chain()(检查来源记录摘要和序列断链的方法片段)。

固定提交片段:来源链断链检查 原项目关键片段

python
broken_links: List[Dict[str, Any]] = []
expected_previous: Optional[str] = None
expected_sequence: Optional[int] = None
for entry in entries:
    if not verify_checksum(entry):
        broken_links.append({
            "entity_id": entry.entity_id,
            "sequence_id": entry.sequence_id,
            "reason": "checksum_mismatch",
        })
    else:
        sequence_gap = (
            expected_sequence is not None
            and entry.sequence_id != expected_sequence + 1
        )
        checksum_break = entry.previous_checksum != expected_previous
        if sequence_gap or checksum_break:
            broken_links.append({
                "entity_id": entry.entity_id,
                "sequence_id": entry.sequence_id,
                "reason": "chain_break",
                "expected_previous_checksum": expected_previous,
                "actual_previous_checksum": entry.previous_checksum,
                "expected_sequence_id": (
                    expected_sequence + 1 if expected_sequence is not None else None
                ),
            })

这段实现同时检查条目自身摘要、全局序列连续性和前序摘要连接,支持“能发现意外修改或删除”的事实判断。可借鉴的是把多种断链信号合并为结构化结果;不能照搬的是把无密钥的本地哈希链解释为抵抗数据库完全写权限攻击者的不可否认证据。

生产增强建议:

  • 业务事件与来源事件在同一事务中写 outbox;
  • 审计存储使用追加权限模型,普通服务账号不能更新历史;
  • 批次摘要签名后锚定到独立审计系统或可信时间戳服务;
  • 定期离线校验链头、版本连续性和来源对象可访问性;
  • 数据保留、删除请求与审计留存规则由合规策略明确协调。

5. 与主链路的接入现状

Semantica 通过包装器把来源能力接入不同子系统:

这种装饰器式接入便于渐进采用,却意味着调用方可以绕过包装器。后两个包装器还导入仓库中不存在的底层模块,因此不能把当前端到端来源链视为已打通。

6. 抽象代码示例

下面是伪代码(不是原项目原样代码),展示生产系统应如何把业务写入与来源事件绑定:

python
with business_transaction() as tx:
    fact_version = fact_repository.append(new_fact, tx=tx)
    outbox.append(
        event_type="provenance.recorded",
        entity_id=fact_version.id,
        source_ids=source_ids,
        activity_id=activity_id,
        agent_id=agent_id,
        tx=tx,
    )

audit_worker.persist_and_anchor(outbox_event)

关键点是:来源写入不是“尽力而为”的日志,而是业务提交不可绕过的组成部分。

7. 可借鉴的交互设计

  1. 实体详情固定展示来源数量、最新来源、处理活动、责任 Agent、版本和完整性状态。
  2. 来源泳道把 Agent、Activity、Entity 分层,并允许从任意节点追上游或下游。
  3. 每个事实字段可直接跳到来源文件、页码、时间片或数据行,而不是只链接文档首页。
  4. 作废前展示所有后代事实、推理结果和决策,支持批量创建重审任务。
  5. 完整性状态区分“摘要匹配”“外部锚定成功”“签名有效”,避免一个绿色图标掩盖不同保证等级。

8. 引入或参照结论

项目 结论 条件
Entity—Activity—Agent 模型 建议仅作设计参照 对接统一身份、算法版本和来源定位规范
来源管理器 建议隔离 PoC 固定版本并验证版本、血缘、作废和导出
SQLite 存储 建议用于单机验证 不承担高并发或强对抗审计
当前可选包装器 不建议作为生产强制链 改为不可绕过的应用服务或事务事件
本地哈希链 仅作完整性检测参照 增加签名、外部锚定和独立权限

9. 源码依据

主题 固定版本官方源码 支持的判断
来源、Agent、活动与作废模型 来源核心记录来源引用与 Agent/Activity 记录作废记录 来源、参与者、处理活动、版本和作废分别建模
写入、血缘、作废、审计与导出 实体来源写入血缘与后代查询作废与审计导出 管理器覆盖来源记录全生命周期,但不保证业务写入同步进入该生命周期
内存与 SQLite 存储 存储抽象与内存实现SQLite 实现 默认内存路径与 SQLite 持久化具有不同运维保证
摘要计算与验证 SHA-256 摘要计算与验证 可检测内容变化,但没有密钥签名和外部可信时间
图构建来源包装器 图构建包装器 来源记录通过可绕过的装饰式包装器接入图构建
上下文与推理包装器 上下文包装器推理包装器 两个包装器引用当前提交中缺失的底层模块,端到端链路需先验证

返回 Semantica 项目分析主报告