记忆
为你的代理提供一种超越单次对话生命周期的记忆。会话状态保存的是当前对话;记忆则是代理在每轮开始时读取、并在学习过程中写回的长期存储——因此下一次会话已经了解用户。
本节将从头开始介绍:ADK-Rust 提供的两种记忆类型、核心类型、后端、双时态知识图谱,以及如何将它们全部接入代理。
两种记忆
ADK-Rust 在同一个MemoryService trait 下提供两种互补的记忆模型,因此代理可以通过一个接口使用其中任意一种:
| 语义存储 | 知识图谱 | |
|---|---|---|
| 形态 | 可搜索的文本条目集合 | 实体、观察结果和类型化关系 |
| 召回 | 对条目进行相似度 / 关键词搜索 | 配置文件卡片 + 基于 token 评分的节点搜索 |
| 适用于 | “我们讨论了关于 X 的什么内容?” | “关于此用户现在有什么事实?” |
| 后端 | InMemory、SQLite、Postgres、Redis、MongoDB、Neo4j | GraphMemoryService(SQLite,双时态) |
| 页面 | 概念 · 后端 | 知识图谱 |
你不必进行全局选择——可以根据每个 agent 的需求,在基于记录的回忆或对用户的清晰、可查询模型之间进行选择。
心智模型
Agent turn
│ search_memory(query) ← recall relevant context at turn start
▼
adk_core::Memory ← the interface the agent sees
│ (MemoryServiceAdapter bridges to…)
▼
MemoryService ← add_session / search / delete_user …
├─ InMemoryMemoryService (dev)
├─ Sqlite/Postgres/Redis/… (semantic store)
└─ GraphMemoryService (bi-temporal knowledge graph)
MemoryService是存储后端:它存储条目(或图节点),并回答search。MemoryServiceAdapter将其封装为adk_core::Memory,作用域限定为(app_name, user_id, project_id?),而这正是 agent 的search_memory实际调用的对象。- Runner 持有
Memory并将其提供给 agent;memory tools 让 agent 可以主动搜索和整理记忆。
安装
# Semantic store — pick the backend you need
adk-memory = { version = "2.1.0", features = ["sqlite-memory"] }
# Bi-temporal knowledge graph
adk-memory = { version = "2.1.0", features = ["graph-memory"] }
| 功能 | 添加内容 |
|---|---|
| (默认) | InMemoryMemoryService — 零配置,适用于开发 |
sqlite-memory | SqliteMemoryService — 基于文件的语义存储 |
graph-memory | GraphMemoryService — 双时态知识图谱(SQLite) |
database-memory | PostgresMemoryService 与 pgvector |
redis-memory | RedisMemoryService |
mongodb-memory | MongoMemoryService |
neo4j-memory | Neo4jMemoryService |
60 秒快速开始
存储几条记忆并搜索它们:
use adk_memory::{InMemoryMemoryService, MemoryService, MemoryEntry, SearchRequest};
use adk_core::Content;
use chrono::Utc;
# async fn run() -> anyhow::Result<()> {
let memory = InMemoryMemoryService::new();
memory.add_session("support", "alice", "s1", vec![
MemoryEntry { content: Content::new("user").with_text("I prefer email over phone"),
author: "user".into(), timestamp: Utc::now() },
]).await?;
let hits = memory.search(SearchRequest {
app_name: "support".into(), user_id: "alice".into(),
query: "how should we contact this customer?".into(),
..Default::default()
}).await?;
for entry in hits.entries { println!("{:?}", entry.content); }
# Ok(()) }
在真实的代理中,你不需要手动调用 search —— 将服务附加到
Runner,让代理自行回忆和整理记忆。