Machine Learning Mastery

Adding Temporal Reasoning to Graph-RAG: Tracking Fact Freshness and Staleness

6.9内容质量

TL;DR · AI 摘要

Adding Temporal Reasoning to Graph-RAG: Tracking Fact Freshness and Staleness - MachineLearningMastery.com Adding Tempor...

核心要点

  • 主题聚焦:Adding Temporal Reasoning to Graph-RAG: Tracking
  • 来源:Machine Learning Mastery,建议结合原文判断细节。
  • AI 分析暂不可用,本条为保底评分与摘要。
#AI#编程#后端
打开原文

为Graph-RAG添加时间推理:追踪事实的新鲜度和过时性 - MachineLearningMastery.com

为Graph-RAG添加时间推理:追踪事实的新鲜度和过时性

作者:

Iván Palomares Carrascosa

发布于

2026年10月1日

分类

语言模型

0

分享

发布

在本文中,你将学习如何为Graph-RAG系统添加一个轻量级的时间推理层,使其能够区分新鲜事实和过时事实。

我们将涵盖的主题包括:

  • 如何将标准的主谓宾三元组扩展为存储在简单时间图中的带时间戳的四元组。
  • 如何使用指数衰减计算近期权重,并利用它们根据给定查询日期对冲突事实进行排序。
  • 如何调整半衰期参数,并将时间图集成到确定性三级Graph-RAG检索流水线中。

引言与动机

在之前的文章《构建确定性三级Graph-RAG系统》中,我们解决了RAG(检索增强生成)架构中处理冲突信息的挑战。具体来说,我们通过赋予“新鲜”事实比较不新鲜的事实更高的优先级,构建了一个分层结构来管理冲突信息。

在这一过程中,一个关键问题浮现出来:我们的基于图的RAG系统如何确切地知道哪些事实是新鲜的?标准的知识图谱将事实视为“无时间”的、与上下文无关的SPO(主谓宾)三元组,例如(Company, HAS_CEO, Alice)。这种方法并不完全符合我们所处的现实世界——一个充满变化和混乱的世界:如果Alice换了工作,不再担任CEO怎么办?在没有时间上下文的情况下将这些事实输入LLM,是产生幻觉的完美配方,会导致令人困惑或事实错误的响应。

为了解决这个挑战,本文将展示构建专用轻量级时间推理引擎的关键步骤,通过几个简单的Python函数实现。我们还将讨论其与之前构建的三级Graph-RAG系统的集成。核心思想是将标准三元组升级为带时间戳的四元组,并计算表示“事实新鲜度”程度的近期权重。

准备好了吗?让我们开始吧!

一次新的时间之旅,逐步进行

第一步是将标准的SPO三元组扩展为“时间四元组”,其中第四个维度引入了时间,具体来说是一个时间戳:(Subject, Predicate, Object, Timestamp)。

以下定义的Python类用于存储我们的新扩展知识,也称为时间图。如果你正在使用笔记本环境,只需将此代码粘贴到你的第一个代码单元格中:

import datetime import math class TemporalGraph: def __init__(self): # 数据将按以下方式存储在知识库中:Subject -> Predicate -> List of (Object, Date) self.knowledge_base = {} def add_fact(self, subject, predicate, obj, date_string): """将带时间戳的事实添加到图中。""" # 将字符串转换为可比较的日期对象 fact_date = datetime.datetime.strptime(date_string, "%Y-%m-%d").date() if subject not in self.knowledge_base: self.knowledge_base[subject] = {} if predicate not in self.knowledge_base[subject]: self.knowledge_base[subject][predicate] = [] self.knowledge_base[subject][predicate].append((obj, fact_date)) print(f"已添加:{subject} {predicate} {obj}(截至{date_string})") # 初始化我们的图 tg = TemporalGraph()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

import

datetime

math

class

TemporalGraph

:

def

__init__

(

self

)

数据将按以下方式存储在知识库中:主体 -> 谓词 -> (对象, 日期)的列表

.

knowledge_base

=

{

}

add_fact

,

subject

predicate

obj

date_string

""

"向图中添加带时间戳的事实。"

将字符串转换为可比较的日期对象

fact_date

strptime

"%Y-%m-%d"

date

if

not

[

]

append

print

f

"已添加:{subject} {predicate} {obj}(截至 {date_string})"

初始化我们的图

tg

现在是时候用一个现实场景来填充我们新创建的时间图 tg 了,在这个场景中事实变化速度非常快……好吧,可能没有那么快,但仍然很快!如果我们正在跟踪一家科技公司在充满变化的混乱周内的领导角色变化,可能会有这样的情况:

事实变化的时间线

tg.add_fact("TechCorp", "HAS_CEO", "Alice", "2021-01-15") tg.add_fact("TechCorp", "HAS_CEO", "Bob", "2023-11-17") tg.add_fact("TechCorp", "HAS_CEO", "Charlie", "2023-11-19") tg.add_fact("TechCorp", "HAS_CEO", "Bob", "2023-11-21") # Bob 回来了!

添加一个静态事实作为对比

tg.add_fact("TechCorp", "FOUNDED_IN", "San Francisco", "2010-05-01")

事实变化的时间线

"TechCorp"

"HAS_CEO"

"Alice"

"2021-01-15"

"Bob"

"2023-11-17"

"Charlie"

"2023-11-19"

"2023-11-21"

Bob 回来了!

添加一个静态事实作为对比

"FOUNDED_IN"

"San Francisco"

"2010-05-01"

输出:

已添加:TechCorp HAS_CEO Alice(截至 2021-01-15) 已添加:TechCorp HAS_CEO Bob(截至 2023-11-17) 已添加:TechCorp HAS_CEO Charlie(截至 2023-11-19) 已添加:TechCorp HAS_CEO Bob(截至 2023-11-21) 已添加:TechCorp FOUNDED_IN San Francisco(截至 2010-05-01)

已添加:

TechCorp

HAS_CEO

Alice

截至

2021

-

01

Bob

2023

Charlie

FOUNDED_IN

San

Francisco

2010

05

请注意,在标准的 RAG 系统中,像“谁担任 TechCorp 的 CEO?”这样的搜索很可能会同时检索到 Alice、Bob 和 Charlie!因此,我们需要一种机制来为事实分配真实性权重,而这个机制可能比你想象的要简单得多。

计算近期权重是解决潜在冲突的关键。我们只需要一种机制来表达:“嘿,这个事实比那个更新,因此它更有可能构成当前的事实。” 实现这一目标的聪明方法是基于指数衰减,即为事实分配一个半衰期时间窗口。例如,如果半衰期设置为一年(365 天),那么一年前的事实权重为 0.5,而今天提出的事实在权重为 1.0。

这两个函数旨在将上述权重评分逻辑引入我们的时间图中:

def calculate_recency_weight(fact_date, query_date, half_life_days=365): """根据事实的年龄计算一个0到1之间的分数。采用指数衰减公式:weight = (0.5) ^ (age_in_days / half_life) """ age_in_days = (query_date - fact_date).days # 如果事实日期在查询日期之后,权重上限为1.0 if age_in_days < 0: return 1.0 weight = 0.5 ** (age_in_days / half_life_days) return round(weight, 4) def query_temporal_graph(graph, subject, predicate, as_of_date_str, half_life_days=365): """查询知识图谱并按时间权重对结果排序""" query_date = datetime.datetime.strptime(as_of_date_str, "%Y-%m-%d").date() try: facts = graph.knowledge_base[subject][predicate] except KeyError: return f"未找到 {subject} -> {predicate} 的相关信息" scored_results = [] for obj, fact_date in facts: # 仅考虑发生在查询日期之前或当天的事实 if fact_date <= query_date: weight = calculate_recency_weight(fact_date, query_date, half_life_days) scored_results.append({ "answer": obj, "date": fact_date.strftime("%Y-%m-%d"), "weight": weight }) # 按权重降序排序(最新/权重最高优先) scored_results.sort(key=lambda x: x['weight'], reverse=True) return scored_results

24

25

26

27

28

29

30

31

32

33

34

35

36

37

calculate_recency_weight

query_date

half_life_days

365

"

根据事实的年龄计算一个0到1之间的分数。

采用指数衰减公式:weight = (0.5) ^ (age_in_days / half_life)

age_in_days

days

如果事实日期在查询日期之后,权重上限为1.0

<

return

1.0

weight

0.5

*

/

round

query_temporal_graph

graph

as_of_date_str

"查询知识图谱并按时间权重对结果排序。"

try

facts

except

KeyError

"未找到 {subject} -> {predicate} 的相关信息"

scored_results

for

仅考虑发生在查询日期之前或当天的事实

<=

"answer"

"date"

strftime

"weight"

按权重降序排序(最新/权重最高优先)

sort

key

lambda

x

'weight'

reverse

True

最后,我们来看一个完整的示例。我们将展示如何查询知识图谱。时间推理在执行时相当于一种“时间旅行”:如果我们添加了持久化事实的代码,然后询问几天后谁是CEO,我们实现的机制会自动实时调整权重:

print("--- 查询1:截至2023年11月18日,谁是CEO? ---") results_past = query_temporal_graph(tg, "TechCorp", "HAS_CEO", "2023-11-18") for res in results_past: print(f"候选人:{res['answer']} | 事实日期:{res['date']} | 置信度权重:{res['weight']}") print("\n--- 查询2:截至2023年12月1日,谁是CEO? ---") results_present = query_temporal_graph(tg, "TechCorp", "HAS_CEO", "2023-12-01") for res in results_present: print(f"候选人:{res['answer']} | 事实日期:{res['date']} | 置信度权重:{res['weight']}")

"--- 查询1:截至2023年11月18日,谁是CEO? ---"

results_past

"2023-11-18"

res

"候选人:{res['answer']} | 事实日期:{res['date']} | 置信度权重:{res['weight']}"

"\n--- 查询2:截至2023年12月1日,谁是CEO? ---"

results_present

"2023-12-01"

结果:

/think

--- 查询 1:截至 2023 年 11 月 18 日,谁是 CEO? --- 候选人:Bob | 事实日期:2023-11-17 | 置信权重:0.9981 候选人:Alice | 事实日期:2021-01-15 | 置信权重:0.1396 --- 查询 2:截至 2023 年 12 月 1 日,谁是 CEO? --- 候选人:Bob | 事实日期:2023-11-21 | 置信权重:0.9812 候选人:Charlie | 事实日期:2023-11-19 | 置信权重:0.9775 候选人:Bob | 事实日期:2023-11-17 | 置信权重:0.9738 候选人:Alice | 事实日期:2021-01-15 | 置信权重:0.1362

--

查询

谁

是

首席执行官

11 月

?

候选人

|

事实日期

置信权重

0.9981

0.1396

12 月

0.9812

0.9775

0.9738

0.1362

正如预期的那样,运行第一个查询时,Bob 会以几乎满的权重成为最佳答案:Charlie 甚至没有出现,因为当时他尚未被任命!与此同时,运行第二个查询揭示了一个需要注意的问题:或许 365 天的半衰期窗口过长,因为需要整整一年时间事实才会失去 50% 的相关性。因此,在充满组织变动的紧张一周中,我们可以看到尽管 Bob 再次成为最佳答案,但 Charlie 紧随其后,甚至 Bob 之前的任命也紧随其后。快速的解决方案是调整 half_life_days 参数,例如将其从 365 改为 7。亲自尝试一下,享受新的结果吧!

总结

现在我们已经构建了这种机制来考虑时间图信息,如何将其整合到之前相关文章中构建的确定性三层架构中呢?当用户在 RAG 系统中向 LLM 发送提示时,您希望检索器不再仅获取文本:相反,它应该对时间图运行查询,按置信权重对事实进行排序,并仅将权重最高的一个(或最多一个小型排序列表)传递到提示的上下文中。这有可能消除 LLM 猜测哪个事实是最新的需求:在最终提示到达模型之前,这个问题就已经解决了。

更多相关内容

  • 为循环网络添加自定义注意力层…
  • 如何通过…提高深度学习模型的鲁棒性
  • 版本控制和跟踪 Scikit-LLM 实验
  • 使用推理大语言模型进行零样本和少样本学习
  • 如何将传统机器学习与…结合
  • 机器学习薪资和就业市场分析…