第 7 章 · 01 PROV-O 溯源管理器


第 7 章 · 01 PROV-O 溯源管理器

本节摘要:第 5—6 章的推理与决策之所以"敢签字",是因为背后有账本。本章装配第一条纵贯①→⑧全管线的能力线:溯源。provenance/ 模块(6 个文件、约 3800 行)以 W3C PROV-O 标准为骨架——**Entity(东西)/Activity(过程)/Agent(责任方)**三元模型,让每个事实都能回答三问:从哪来(source)、谁产生(agent)、怎么产生(activity)。本节精读 1486 行的 ProvenanceManagertrack_entity 的原子事务与版本归档、get_lineage 的 BFS 血缘链与校验和完整性、audit_log 的三种审计格式与 export_prov 的 RDF 导出;最后看它与决策智能的衔接——决策的证据链就是溯源链。

内容来源:semantica/provenance/manager.py 1486 行、schemas.py 495 行、storage.py 1039 行、integrity.py 236 行、bridge_axiom.py 435 行)、semantica/context/decision_recorder.py_track_decision_provenance)、README.md(Recipe: Audit Trail)

⚠️ 注意:PROV-O 是 W3C 的溯源本体标准(PROVENANCE ONTOLOGY),ProvenanceManager 的存储模型与它对齐但并非逐字实现——内存/SQLite 存储存的是扁平 ProvenanceEntry,三元组形态只在 export_prov() 导出时现场构建(需要 rdflib)。读源码时别把存储层当成 RDF 库。

学习目标

  1. 理解 PROV-O 三元模型:Entity/Activity/Agent 及 wasDerivedFrom/used/wasAttributedTo 等核心关系。
  2. 掌握 ProvenanceEntry 的字段分组:PROV 核心、代理类型、审计级源引用、时态与版本。
  3. 读懂 track_entity 的原子事务(#807)、旧版本归档与 previous_version_id/derived_from_id 语义区分。
  4. 会用 get_lineage/trace_lineage/revision_history 追血缘,用 audit_log/export_prov 出审计包。
  5. 理解决策证据链与溯源链的对接点。

一、PROV-O:给每个事实发一张出生证明

溯源要回答的三个问题,恰好对应 PROV-O 的三个核心类:

  • Entity(实体):"东西"——图谱里的一个实体、一个文本块、一条推理结论、一个决策节点。
  • Activity(活动):"过程"——NER 抽取、图谱构建、推理、决策——实体都是被某个活动生成(wasGeneratedBy)的。
  • Agent(代理):"责任方"——某个人、某个软件、某个组织——活动由代理执行(wasAssociatedWith)。

三个类再用几条标准关系缝成网:wasDerivedFrom(此物派生自彼物)、used(活动使用了哪些实体)、wasAttributedTo(实体归于哪个代理)、generatedAtTime(何时生成)。落到 Semantica,这张网有一个统一载体——ProvenanceEntry(schemas.py 第 35 行起,约 60 个字段按组排布):

# W3C PROV-O core entities entity_id: str # prov:Entity entity_type: str # entity / chunk / relationship / property / decision ... activity_id: str # prov:Activity agent_id: str = "semantica" # prov:Agent agent_type: str = "software_agent" # "person" | "software_agent" | "organization" is_automated: bool = True role: Optional[str] = None # prov:hadRole:"generator"/"approver"/"reviewer" # Audit-grade source tracking source_document: str = "" # DOI、文件路径、URL source_location: Optional[str] = None # 页码、图号、字符区间 source_quote: Optional[str] = None # 原文直接引用(审计铁证) confidence: float = 1.0 checksum: str = ... # SHA-256 完整性校验 # Temporal & versioning first_seen / last_updated / valid_from / valid_until parent_entity_id: ... # prov:wasDerivedFrom used_entities: List[str] # prov:used

source_quote 值得单独划线:不只记"来自文档 X 第 3 页",还把原文那句话存下来——监管对质时直接出示引文,不用翻库。agent_type/is_automated/role 三字段则是问责粒度的关键(issue #825):出问题时能区分"算法自动干的"还是"某人审批的"。

二、track_entity:原子事务与版本归档

track_entity(manager.py 第 263—415 行)是全模块的枢纽方法,120 行里装了三重设计。

第一重,原子事务(issue #807):

with self._get_or_create_transaction(_conn) as conn: existing = self.storage._retrieve_with_conn(conn, entity_id) ... self._save_entry(entry, _conn=conn, _raise_on_error=True)

读取现有记录、归档旧版、写入新条目共用一个连接一个事务(BEGIN IMMEDIATE 使并发调用在读取阶段即串行化),任何一步抛异常整体回滚——溯源账本不会出现"归档了但没写入"的半截状态。

第二重,父链自动解析(第 307—320 行):parent_entity_id(对应 wasDerivedFrom)有三条来源——显式 kwarg、metadata["derived_from"],以及一个巧妙的启发式:若 source 参数本身是已登记的实体 ID,就把它当父实体——"从实体 A 抽取出实体 B"这类管线衔接自动成链。

第三重,版本归档而非覆盖(第 325—348 行):实体更新时,旧条目被深拷贝后改挂 "{entity_id}:v:{last_updated}" 的版本化 ID 入库,新条目的 previous_version_id 指向它。源码注释特意解释了归档时为何原样保留校验和:归档只是改名不是篡改,重算校验和反而会让后续哈希链断出"幻影缺口",让 verify_chain() 误报篡改。第 381 行起的注释再划一道语义界线:

# previous_version_id always captures "this corrects a prior # version of the same fact" ... # derived_from_id captures "this fact was derived from a # different source entity" — only set when a parent was # explicitly resolved ...

修正同一事实的旧版本(previous_version_id)与从别的实体派生(derived_from_id)是两种血缘,混为一谈审计就失真。

三、血缘追踪:get_lineage 与完整性

血缘查询是 Manager 的第二序列。get_lineage(第 748—813 行)沿 trace_lineage(storage 层 BFS,entries[0] 恒为被查实体本身,其后是父、祖……)聚合出一份血缘档案:

return { "entity_id": entity_id, "lineage_chain": chain_dicts, # 完整链条(BFS 序) "source_documents": list(set( # 血缘上出现过的全部来源文档 e.source_document for e in lineage_entries if e.source_document)), "first_seen": min(...), "last_updated": max(...), "entity_count": len(lineage_entries), "metadata": aggregated_metadata, # 祖先先铺、自己后盖:当前值胜出 "integrity_verified": all(verify_checksum(e) for e in lineage_entries), }

两处细节:metadata 聚合按 BFS 逆序合并(第 777 行注释)——祖先的属性先铺底、被查实体自己的最后覆盖,冲突时"最新者胜";integrity_verified 对整条链逐条 verify_checksum(integrity.py 的 SHA-256 校验),返回布尔让调用方一眼确认血缘没被篡改。配套查询还有 trace_descendants/get_descendants(血缘反向)、revision_history(版本时间线)、query_recorded_between(时段过滤)、invalidate(无效化而非删除:归档旧态后追记 invalidated/invalidated_at_time/invalidation_reason——"证明一个事实存在过、被审过、又被撤回")。

四、审计轨迹导出:audit_log 与 export_prov

账本记了,还要能交给监管。两个出口对应两种受众:

audit_log(第 1151—1199 行)给人工审阅,三种格式:

if format == "json": return [e.to_dict() for e in entries] elif format == "csv": lines = ["entity_id,entity_type,activity_id,agent_id,timestamp"] ... else: # table:对齐的文本表格,流水对账用

按时间排序、since 参数过滤时段,CSV 表头五列直指审计要素(什么实体/什么类型/什么活动/谁干的/何时)。

export_prov(第 1203 行起)给机器互操作——把全部条目现场构建成 W3C PROV-O 的 RDF 图:

PROV = Namespace("http://www.w3.org/ns/prov#") EX = Namespace(base_uri or DEFAULT_BASE_URI) # https://semantica.dev/ns# for e in self.storage.retrieve_all(): ent_uri = uri(e.entity_id) g.add((ent_uri, RDF.type, PROV.Entity)) g.add((ent_uri, PROV.generatedAtTime, Literal(e.timestamp, datatype=XSD.dateTime))) ...

导出里有两处标准对齐的巧思:_AGENT_TYPE_PROV_CLASS(第 1245 行)把自家代理类型映射到 PROV-O 的规范子类——"person"→prov:Person"software_agent"→prov:SoftwareAgent"organization"→prov:OrganizationDEFAULT_BASE_URI 与 RDFExporter 的命名空间表共用同一 URI 前缀(issue #825),保证图谱导出的实体与溯源导出的实体在 RDF 层同 URI 合流。格式支持 turtle/ntriples/jsonld,README 的监管提交配方用的正是 turtle。

五、衔接决策智能:决策的证据链即溯源链

纵向能力线的价值在与第 6 章的接缝处显现。对接点在 DecisionRecorder._track_decision_provenance(decision_recorder.py 第 587—618 行):决策入库时同步写两条溯源——决策节点登记为 Entity(entity_type="decision"agent_id=decision_makersource_documents 全带),决策活动登记为 Activity(activity_type="decision_making"used_entities=[decision_id]、起止时间取决策时间戳)。于是一笔拒贷决策的完整解释链在账本上闭合:

原始文档(source_document+quote,Entity) ← NER 抽取活动(Activity,software_agent) ← 图谱实体(Entity,wasDerivedFrom 文档) ← 推理结论(Entity,used 推理前提) ← 决策(Entity+Activity,agent=decision_maker) → export_prov() 输出 .ttl 提交监管

README 的 Recipe: Audit Trail 演示了最短接线:ContextGraph 记决策链、ProvenanceManager(storage_path="./audit.db") 记证据、to_kg_dict() 转 KG 字典后 RDFExporter().export(kg, "audit_trail.ttl", format="turtle")——十几行,一个可提交的审计包。进阶件 bridge_axiom.py 还管一种特殊血缘:跨域换算公式的系数出处(如"1% 生物量增长→0.346% 旅游收入"的 DOI+页码+引文),保证"翻译链"每一环都可回查——对 Blue Finance、临床诊断这类跨域高风险场景,这是溯源的最后一块拼图。

💡 装配要点:本阶是与全管线正交的能力层。心智模型:ProvenanceManager = 一张 PROV-O 对齐的追加式账本(Entry 即账页),track_entity/track_relationship/track_chunk/track_property_source 四个记账口,读取侧 get_lineage(BFS 血缘+完整性)、revision_history(版本线)、query_recorded_between(时段),导出侧 audit_log(人读)与 export_prov(机读 RDF)。三个装配纪律:账本只追加不覆盖(更新=归档旧版+新条目)、校验和构成防篡改哈希链、previous_version_id(修正)与 derived_from_id(派生)不可混用。生产必传 storage_path(SQLite),否则内存存储重启即失忆。

本节要点回顾

  • PROV-O 三元模型:Entity/Activity/Agent;核心关系 wasDerivedFrom/used/wasAttributedTo/generatedAtTime;ProvenanceEntry 约 60 字段分四组(PROV 核心/代理类型/审计级源引用/时态版本)。
  • source_quote 存原文引文,agent_type+is_automated+role 支撑问责粒度(自动 vs 人工审批)。
  • track_entity 三重设计:BEGIN IMMEDIATE 原子事务(#807)、父链三级解析(kwarg→derived_from→source 即父的启发式)、版本归档制(旧版挂 entity_id:v:时间戳,校验和原样保留防哈希链幻影缺口);previous_version_id=修正旧版,derived_from_id=跨实体派生。
  • get_lineage:BFS 链+来源文档集合+metadata 逆序聚合(最新者胜)+integrity_verified 全链校验和核验;invalidate 无效化留痕不删记录。
  • 导出双通道:audit_log(table/csv/json,人读)+ export_prov(turtle/ntriples/jsonld,PROV 命名空间、代理子类映射、与 RDFExporter 同 base URI 合流)。
  • 决策衔接:_track_decision_provenance 把决策记为 Entity+Activity;文档→抽取→实体→推理→决策全链在账本闭合,export_prov 交付监管。

下一节:02 双时态知识图谱与 GDPR 撤回——valid time 与 recorded time 的独立建模、state_at 时间点快照、retraction/purge 的语义差异与 GDPR 删除权。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U