记忆概念
记忆的语义存储部分由少量小类型构成。先了解这四个,后面的内容就很容易理解了。
MemoryEntry
单条记忆记录:一些内容、作者以及时间。
use adk_memory::MemoryEntry;
use adk_core::Content;
use chrono::Utc;
let entry = MemoryEntry {
content: Content::new("user").with_text("I prefer dark mode"),
author: "user".to_string(),
timestamp: Utc::now(),
};
条目是存储的单位,也是回忆的单位 — search 会返回与查询最相关的条目。
MemoryService trait
每个后端都实现一个 trait。需要两个方法;其余方法都有默认实现,后端可以覆盖:
#[async_trait]
pub trait MemoryService: Send + Sync {
// Required
async fn add_session(&self, app: &str, user: &str, session: &str,
entries: Vec<MemoryEntry>) -> Result<()>;
async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;
// Optional (default: "not implemented")
async fn delete_user(&self, app: &str, user: &str) -> Result<()>; // GDPR
async fn delete_session(&self, app: &str, user: &str, session: &str) -> Result<()>;
async fn add_entry(&self, app: &str, user: &str, entry: MemoryEntry) -> Result<()>;
async fn delete_entries(&self, app: &str, user: &str, query: &str) -> Result<u64>;
// …plus a health check
}
add_session会摄取一段完整对话中的所有条目。当附加了 memory 时,Runner 会替你调用它。search是回忆。后端会以不同方式解释查询——关键字、嵌入相似度,或图的 token 评分——但契约是相同的。
SearchRequest / SearchResponse
use adk_memory::SearchRequest;
let req = SearchRequest {
app_name: "support".into(),
user_id: "alice".into(),
query: "contact preference".into(),
..Default::default() // top_k, project scoping, etc.
};
let resp = memory.search(req).await?; // resp.entries: Vec<MemoryEntry>
会话状态 vs. 记忆
这是不同的工具——不要把它们混为一谈:
| 会话状态 | 记忆 | |
|---|---|---|
| 生命周期 | 一次对话 | 跨对话 |
| API | adk-session(SessionService,状态映射) | adk-memory(MemoryService) |
| 保存 | 实时转录 + 临时状态 | 值得稍后回忆的持久事实 |
| 读取 | 始终在上下文中 | 按需,通过 search_memory |
一种典型流程是:对话存在于 会话状态 中;当它结束时(或每一轮后),重要部分会写入 记忆;下一次会话再从记忆中 搜索 以恢复上下文。参见 Sessions & State。
隔离:应用、用户和项目
记忆始终以 (app_name, user_id) 为键,因此用户永远看不到彼此的记忆。你可以在用户之下再设定第三层范围——项目:
- 全局条目(
project_id = None)— 在任何上下文中都可见。 - 项目条目(
project_id = Some(id))— 仅在该项目内可见。 - 项目搜索 返回全局 + 匹配的项目条目;全局搜索 只返回全局条目。
use adk_memory::{MemoryServiceAdapter, InMemoryMemoryService};
use std::sync::Arc;
let service = Arc::new(InMemoryMemoryService::new());
// store within a project
service.add_session_to_project("app", "user", "sess", "acme-project", entries).await?;
// an adapter scoped to that project
let adapter = MemoryServiceAdapter::new(service, "app", "user")
.with_project_id("acme-project");
使用项目可以让,例如,一个用户的 工作 和 个人 助手之间不共享记忆,同时仍然共享真正的全局事实。
并非所有后端都实现项目范围
项目隔离是后端能力,而不是 trait 能保证的东西。依赖之前请先确认:
if service.supports_project_scoping() {
service.add_entry_to_project("app", "user", "acme-project", entry).await?;
} else {
// Decide explicitly: refuse, or store globally on purpose.
}
| 后端 | 项目作用域 |
|---|---|
InMemoryMemoryService | 是 |
SqliteMemoryService | 是 |
PostgresMemoryService | 是 |
RedisMemoryService | 是 |
MongoMemoryService | 是 |
Neo4jMemoryService | 是 |
GraphMemoryService | 否 — 项目方法返回错误 |
没有项目支持的后端会让调用失败,而不是在全局范围内静默写入或删除。扩大写入的作用范围会使原本只针对某个项目的数据对同一应用和用户下的所有内容可见,而扩大删除的作用范围会移除命名项目之外的条目——这两者都不是调用方能从返回值中检测出来的。MemoryServiceAdapter::supports_project_scoping
会报告其后端支持的内容。
GDPR 擦除
delete_user(app, user) 会删除一个用户跨所有项目的全部记忆(条目和
嵌入)——这是“被遗忘权”的原语。持久化存储的后端会实现它;请在你的账户删除流程中调用它。
memory.delete_user("support", "alice").await?;
下一步:后端 →