知识图谱

GraphMemoryService 是一种不同形式的记忆:它不是一堆文本条目,而是存储用户的知识图谱——实体、附加到实体的事实(“观察”)以及它们之间带类型的关系——并且它双时间性地跟踪所有这些。这是 Mindfulness-with-Mia examplerealtime memory page 背后的后端。

它实现了与其他后端相同的 MemoryService trait,因此它以相同的方式集成到 agent 中——但它在顶部暴露了一个更丰富的图 API。

数据模型

   Entity "Alice"  (type: person)
     ├─ observation: "prefers email over phone"   valid_from 2026-06-01
     ├─ observation: "timezone is CET"            valid_from 2026-06-10
     └─ relation:    Alice ──works_at──▶ "Acme"
  • Entity — 一个命名事物(人、地点、偏好、主题),带有一个自由形式的 entity_type
  • Observation — 附加到实体的一个事实,带有一个稳定的 id 和一个 valid_from 时间戳。
  • Relation — 两个实体(source ──relation_type──▶ target)之间的一个带类型边,例如 Alice ──works_at──▶ Acme

还有一个情景存储(kg_episodic),它记录原始轮次,与精心策划的图谱分开——因此您可以同时保留转录本和提炼出的模型。

为什么是双时间性

每个观察和关系都沿着两个时间轴进行跟踪:

  • 有效时间 — 事实在世界中真实发生的时间(valid_fromvalid_to)。
  • 摄入时间 — 系统学习到它的时间。

当一个事实改变时,旧的事实不会被删除——它会被失效(其 valid_to 被设置),并添加新的事实。这意味着图谱可以回答“用户当前的偏好是什么?”而不会丢失“它曾经是什么?”。被取代的事实保留在历史中,而不是覆盖当前——这正是您希望在数月内信任的记忆所需要的。

kg.invalidate_observation(old_id).await?;   // mark a fact no longer valid
kg.invalidate_relation(old_id).await?;      // mark an edge no longer valid

创建一个

graph-memory 是 SQLite 支持的,所以它是一个文件(或用于测试的内存中):

use adk_memory::GraphMemoryService;
use std::sync::Arc;

let kg = GraphMemoryService::new("sqlite://mia-memory.db").await?;
kg.migrate().await?;                         // idempotent schema setup
let kg = Arc::new(kg);

写入图谱

use adk_memory::{CreateEntityInput, CreateRelationInput};

kg.create_entities("coach", "alice", vec![CreateEntityInput {
    name: "Alice".into(),
    entity_type: "person".into(),
    observations: vec!["prefers morning sessions".into(), "goal: run a 10k".into()],
}]).await?;

kg.create_relations("coach", "alice", vec![CreateRelationInput {
    source: "Alice".into(), relation_type: "training_for".into(), target: "10k race".into(),
}]).await?;

// add facts to an existing entity later
kg.add_observations("coach", "alice", /* entity */ "Alice", vec!["timezone is CET".into()]).await?;

创建实体是 upsert——重新创建已知实体会更新其类型和时间戳,而不是重复它。

读回它

除了 trait 的 search 之外,还有三种召回形式:

// 1. Token-scored relevance search → entities + their relations + a score
let hits = kg.search_nodes("coach", "alice", "what is she training for?", 5).await?;

// 2. Fetch specific entities by name
let nodes = kg.open_nodes("coach", "alice", &["Alice".into()]).await?;

// 3. The whole graph (small graphs / debugging)
let graph = kg.read_graph("coach", "alice").await?;

个人资料卡

agent 的杀手级功能:profile_card 渲染用户身份的紧凑、当前摘要——最近更新的实体及其有效观察——准备在会话开始时注入到系统提示中。

let card = kg.profile_card("coach", "alice").await?;
// → a short text block: "Alice (person): prefers morning sessions; goal: run a 10k…"

通过预算限制其大小,以便随着图谱的增长,提示保持小巧:

let kg = GraphMemoryService::new(url).await?
    .with_profile_budget(/* entities */ 12, /* observations per entity */ 5);

让 agent 管理它

在生产环境中,您很少手动调用 create_entities——您会赋予 agent 工具,让它在学习时写入图谱。请参阅 Tools & agents 以了解 rememberrelate,它们直接映射到上述调用并随 adk-tool 一起提供。

下一步:Tools & agents →