跳到主要内容

第 3 章:时间知识图谱(TKG)

本章讲什么: HSG 管"模糊、联想式"的记忆;时间知识图谱管"精确、会变的事实"。比如"CompanyX 的 CEO 是谁"这种答案会随时间翻转的事实。这是一套独立于 HSG 的子系统,存在自己的表里、有自己的 API。


1. 要解决的小问题:事实会过期

向量记忆不擅长回答"2022 年谁是 CEO"——它只会召回"最像"的文本,不理解真值的时间窗

TKG 的做法:把事实存成三元组 + 一对时间戳:

(subject, predicate, object, valid_from, valid_to)
主语 谓语 宾语 生效时刻 失效时刻(NULL=至今仍有效)

例:(CompanyX, has_CEO, Alice, 2021-01-01, NULL)


2. 核心机制:插入即自动关闭旧事实

巧妙点: 你不需要手动"结束"旧任期。插入 (CompanyX, has_CEO, Bob, 2024-04-10) 时,系统自动把"同 subject+predicate 且还没结束(valid_to IS NULL)"的旧事实的 valid_to 设成新事实生效前一毫秒。

# 示意,非源码:insert_fact 的自动关闭逻辑
new_from = 2024_04_10
for old in facts_where(subject, predicate, valid_to IS NULL):
if old.valid_from < new_from:
old.valid_to = new_from - 1 # 旧任期在新任期开始前一刻结束
insert(subject, predicate, object, valid_from=new_from, valid_to=NULL)

真实实现:insert_fact(temporal_graph/store.py:11),自动关闭在 :24-26。批量版 batch_insert_facts(:83)同逻辑并包在事务里。

结果:任何时刻,同一 (subject,predicate) 最多只有一条"当前有效"(valid_to IS NULL)的事实,时间线不会自相矛盾。


3. 查询:某时刻的真值

核心谓词是"在时刻 at 有效":valid_from <= at AND (valid_to IS NULL OR valid_to >= at)。这一句反复出现:

查询回答什么函数
point-in-time"某时刻 X 的所有/某条事实"query_facts_at_time(query.py:7)
current"X 现在的 predicate 是什么"get_current_fact(query.py:37)
range"某时间段内涉及的事实"query_facts_in_range(query.py:49)
conflict"某时刻同主谓有几条并存(冲突)"find_conflicting_facts(query.py:83)
by-subject"X 的当前全部事实"get_facts_by_subject(query.py:95)
pattern search"subject/predicate/object LIKE %..%"search_facts(query.py:118)
时间轴: 2021 ───────── 2024-04 ──────▶ now
Alice: [valid_from ......... valid_to] ← 已关闭
Bob: [valid_from .... NULL] ← 当前有效

query_facts_at_time(at=2022): 命中 Alice(2022 落在她的窗口内)
get_current_fact(now): 命中 Bob

4. 时间线与变化分析

temporal_graph/timeline.py 把事实"事件化":每条事实拆成 created(在 valid_from)和 invalidated(在 valid_to)两个时间点,按时间排序就得到一条可读时间线。

  • get_subject_timeline(timeline.py:8):某主语的完整演变史。
  • compare_time_points(timeline.py:144):对比两个时刻,输出 added/removed/changed/unchanged——"从 t1 到 t2 有什么变了"。
  • get_change_frequency(timeline.py:181)/get_volatile_facts(:213):算某事实多久变一次、哪些事实最"善变"。

5. 置信度衰减:老事实缓慢褪色

apply_confidence_decay(store.py:111)用一条 SQL 把所有"当前有效"事实的 confidence 按存在时长线性下调,但地板锁在 0.1——老事实不会归零,只是没那么可信。


6. 边界与坑

  • 无实体归一化。 subject/predicate 是裸字符串精确匹配——"CompanyX" 和 "company x" 会被当成两个主语,系统不会合并。
  • schema 命名不一致(值得警惕)。 迁移脚本 migrations/001_initial.sql:73 把宾语列建为 obj、关系列建为 relation,但代码到处用 objectrelation_type(如 store.py:30query.py:143)——说明实际运行的建表 DDL 与该迁移文件不一致(真实 schema 另有来源)。读代码时以 store.py/query.py 里的列名为准。
  • MCP 侧参数名对不上。 ai/mcp.py:159query_facts_at_time 用了 obj=/at_time=,而函数签名是 subject_object=/at=(query.py:7)——这条 factual 查询路径在当前代码下会 TypeError(inferred,基于两处签名比对)。
  • 两套"记忆"不自动互通。 TKG 的事实和 HSG 的向量记忆是分开的;MCP 的 unified 查询只是把两边结果拼在一起返回(mcp.py:143-189),并没有真正融合打分。