记忆

用于 AI Agent 的长期语义记忆,使用 adk-memory

概述

记忆系统为 Agent 对话提供持久且可搜索的存储。与会话状态(其是短暂的)不同,记忆在会话之间持续存在,并使 Agent 能够回忆起过去交互中的相关上下文。

安装

[dependencies]
adk-memory = "0.2.0"

核心概念

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(),
};

MemoryService Trait

记忆后端的核心 Trait:

#[async_trait]
pub trait MemoryService: Send + Sync {
    /// 存储用户的会话记忆
    async fn add_session(
        &self,
        app_name: &str,
        user_id: &str,
        session_id: &str,
        entries: Vec<MemoryEntry>,
    ) -> Result<()>;

    /// 通过查询搜索记忆
    async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;
}

SearchRequest

记忆搜索的查询参数:

use adk_memory::SearchRequest;

let request = SearchRequest {
    query: "user preferences".to_string(),
    user_id: "user-123".to_string(),
    app_name: "my_app".to_string(),
};

InMemoryMemoryService

用于开发和测试的简单内存实现:

use adk_memory::{InMemoryMemoryService, MemoryService, MemoryEntry, SearchRequest};
use adk_core::Content;
use chrono::Utc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let memory = InMemoryMemoryService::new();

    // 从会话中存储记忆
    let entries = vec![
        MemoryEntry {
            content: Content::new("user").with_text("I like Rust programming"),
            author: "user".to_string(),
            timestamp: Utc::now(),
        },
        MemoryEntry {
            content: Content::new("assistant").with_text("Rust is great for systems programming"),
            author: "assistant".to_string(),
            timestamp: Utc::now(),
        },
    ];

    memory.add_session("my_app", "user-123", "session-1", entries).await?;

    // 搜索记忆
    let request = SearchRequest {
        query: "Rust".to_string(),
        user_id: "user-123".to_string(),
        app_name: "my_app".to_string(),
    };

    let response = memory.search(request).await?;
    println!("找到 {} 条记忆", response.memories.len());

    Ok(())
}

记忆隔离

记忆通过以下方式隔离:

  • app_name:不同的应用程序拥有独立的记忆空间
  • user_id:每个用户的记忆都是私有的
// 用户 A 的记忆
memory.add_session("app", "user-a", "sess-1", entries_a).await?;

// 用户 B 的记忆(独立)
memory.add_session("app", "user-b", "sess-1", entries_b).await?;

// 搜索仅返回用户 A 的记忆
let request = SearchRequest {
    query: "topic".to_string(),
    user_id: "user-a".to_string(),
    app_name: "app".to_string(),
};

搜索行为

InMemoryMemoryService 使用基于词语的匹配:

  1. 查询被分词为词语(小写)
  2. 每个记忆的 content 被分词
  3. 返回包含任何匹配词语的记忆
// 查询:"rust programming"
// 匹配包含 "rust" 或 "programming" 的记忆

自定义 Memory 后端

实现 MemoryService 以用于自定义存储(例如,向量数据库):

use adk_memory::{MemoryService, MemoryEntry, SearchRequest, SearchResponse};
use adk_core::Result;
use async_trait::async_trait;

pub struct VectorMemoryService {
    // 您的向量数据库客户端
}

#[async_trait]
impl MemoryService for VectorMemoryService {
    async fn add_session(
        &self,
        app_name: &str,
        user_id: &str,
        session_id: &str,
        entries: Vec<MemoryEntry>,
    ) -> Result<()> {
        // 1. 为每个条目生成嵌入
        // 2. 将其与元数据一起存储在向量数据库中
        Ok(())
    }

    async fn search(&self, req: SearchRequest) -> Result<SearchResponse> {
        // 1. 为查询生成嵌入
        // 2. 执行相似性搜索
        // 3. 返回 Top-K 结果
        Ok(SearchResponse { memories: vec![] })
    }
}

与 Agent 集成

Memory 与 LlmAgentBuilder 集成:

use adk_agent::LlmAgentBuilder;
use adk_memory::InMemoryMemoryService;
use std::sync::Arc;

let memory = Arc::new(InMemoryMemoryService::new());

let agent = LlmAgentBuilder::new("assistant")
    .model(model)
    .instruction("You are a helpful assistant with memory.")
    .memory(memory)
    .build()?;

当 memory 配置后:

  1. 每次交互前,会搜索相关的 memories
  2. 匹配的 memories 会被注入到上下文中
  3. 每次 session 结束后,对话会作为 memories 存储

架构

┌─────────────────────────────────────────────────────────────┐
│                      Agent Request                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Memory Search                            │
│                                                             │
│   SearchRequest { query, user_id, app_name }               │
│                         │                                   │
│                         ▼                                   │
│   ┌─────────────────────────────────────────────────────┐  │
│   │              MemoryService                          │  │
│   │  ┌─────────────┐  ┌─────────────┐  ┌────────────┐  │  │
│   │  │ InMemory    │  │ Vector DB   │  │ Custom     │  │  │
│   │  │ (dev/test)  │  │ (Qdrant)    │  │ Backend    │  │  │
│   │  └─────────────┘  └─────────────┘  └────────────┘  │  │
│   └─────────────────────────────────────────────────────┘  │
│                         │                                   │
│                         ▼                                   │
│   SearchResponse { memories: Vec<MemoryEntry> }            │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│              Context Injection                              │
│                                                             │
│   Relevant memories added to agent context                 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Agent Execution                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   Memory Storage                            │
│                                                             │
│   Session conversation stored for future recall            │
└─────────────────────────────────────────────────────────────┘

最佳实践

实践描述
在生产环境中使用向量数据库InMemory 仅用于开发/测试
按用户范围划分始终包含 user_id 以保护隐私
限制结果数量限制返回的记忆数量以避免上下文溢出
清理旧记忆为过期数据实现 TTL 或归档
策略性地嵌入存储摘要,而非原始对话

与 Session 的比较

特性Session 状态Memory
持久性Session 生命周期永久
范围单 Session跨 Session
搜索键值查找语义搜索
用例当前上下文长期回忆

上一页: ← Guardrails | 下一页: Studio →