الذاكرة

ذاكرة دلالية طويلة الأمد للوكلاء الذكيين باستخدام adk-memory.

نظرة عامة

يوفر نظام الذاكرة تخزينًا دائمًا وقابلًا للبحث لمحادثات الوكلاء. وعلى خلاف حالة الجلسة (التي تكون مؤقتة)، تستمر الذاكرة عبر الجلسات وتمكّن الوكلاء من استرجاع السياق ذي الصلة من التفاعلات السابقة.

التثبيت

[dependencies]
adk-memory = "2.1.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

السمة الأساسية للواجهات الخلفية للذاكرة:

#[async_trait]
pub trait MemoryService: Send + Sync {
    /// Store session memories for a user
    async fn add_session(
        &self,
        app_name: &str,
        user_id: &str,
        session_id: &str,
        entries: Vec<MemoryEntry>,
    ) -> Result<()>;

    /// Search memories by query
    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(),
    limit: None,
    min_score: None,
    project_id: None, // None = global only, Some("id") = global + project
};

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

    // Store memories from a session
    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?;

    // Search memories
    let request = SearchRequest {
        query: "Rust".to_string(),
        user_id: "user-123".to_string(),
        app_name: "my_app".to_string(),
        limit: None,
        min_score: None,
        project_id: None,
    };

    let response = memory.search(request).await?;
    println!("Found {} memories", response.memories.len());

    Ok(())
}

عزل الذاكرة

تُعزل الذكريات حسب:

  • app_name: للتطبيقات المختلفة مساحات ذاكرة منفصلة
  • user_id: ذكريات كل مستخدم خاصة
  • project_id (اختياري): يمكن تحديد نطاق الإدخالات ليقتصر على مشروع ضمن مستخدم
// User A's memories
memory.add_session("app", "user-a", "sess-1", entries_a).await?;

// User B's memories (separate)
memory.add_session("app", "user-b", "sess-1", entries_b).await?;

// Search only returns user-a's memories
let request = SearchRequest {
    query: "topic".to_string(),
    user_id: "user-a".to_string(),
    app_name: "app".to_string(),
    limit: None,
    min_score: None,
    project_id: None, // None = global entries only
};

الذاكرة المحددة النطاق بالمشروع

يمكن تحديد نطاق الذكريات ليقتصر على مشروع ضمن مستخدم. ويصبح مفتاح العزل هو (app_name, user_id, project_id?):

  • الإدخالات العامة (project_id = None): تكون مرئية في جميع سياقات المشاريع وفي عمليات البحث العامة فقط.
  • إدخالات المشروع (project_id = Some(id)): تكون مرئية فقط عند البحث ضمن ذلك المشروع المحدد.
  • البحث في المشروع (project_id = Some(id)): يعيد الإدخالات العامة + إدخالات ذلك المشروع.
  • البحث العام (project_id = None): يعيد الإدخالات العامة فقط.

تخزين الإدخالات المحددة النطاق بالمشروع

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

let service = InMemoryMemoryService::new();

let entry = MemoryEntry {
    content: Content::new("user").with_text("Project uses microservices"),
    author: "user".to_string(),
    timestamp: Utc::now(),
};

// Global entry (no project scope)
service.add_session("app", "user-1", "sess-1", vec![entry.clone()]).await?;

// Project-scoped entry
service.add_session_to_project("app", "user-1", "sess-2", "my-project", vec![entry.clone()]).await?;

// Single entry to a project
service.add_entry_to_project("app", "user-1", "my-project", entry).await?;

البحث ضمن نطاق مشروع

use adk_memory::SearchRequest;

// Global-only search — returns only global entries
let global = service.search(SearchRequest {
    query: "microservices".into(),
    user_id: "user-1".into(),
    app_name: "app".into(),
    limit: None,
    min_score: None,
    project_id: None,
}).await?;

// Project search — returns global + project entries
let project = service.search(SearchRequest {
    query: "microservices".into(),
    user_id: "user-1".into(),
    app_name: "app".into(),
    limit: None,
    min_score: None,
    project_id: Some("my-project".into()),
}).await?;

حذف الإدخالات المحددة النطاق بالمشروع

// Delete entries matching a query within a project only
service.delete_entries_in_project("app", "user-1", "my-project", "microservices").await?;

// Delete ALL entries for a project
service.delete_project("app", "user-1", "my-project").await?;

// Global delete — only removes global entries, project entries are unaffected
service.delete_entries("app", "user-1", "microservices").await?;

// GDPR delete_user — removes everything (global + all projects)
service.delete_user("app", "user-1").await?;

MemoryServiceAdapter مع نطاق مشروع

يربط MemoryServiceAdapter بين MemoryService وadk_core::Memory. استخدم with_project_id() لتحديد نطاق جميع العمليات:

use adk_memory::{InMemoryMemoryService, MemoryServiceAdapter};
use adk_core::Memory;
use std::sync::Arc;

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

// Adapter without project — operates on global entries
let global_adapter = MemoryServiceAdapter::new(service.clone(), "app", "user-1");

// Adapter with project — all search/add/delete operations scoped to the project
let project_adapter = MemoryServiceAdapter::new(service.clone(), "app", "user-1")
    .with_project_id("my-project");

// Core Memory trait also supports ad-hoc project access
global_adapter.search_in_project("query", "other-project").await?;
global_adapter.add_to_project(entry, "other-project").await?;

التحقق من صحة معرّف المشروع

تتم التحقق من معرّفات المشروع في جميع عمليات الكتابة:

  • يجب ألا تكون فارغة
  • يجب ألا يتجاوز طولها 256 حرفًا
use adk_memory::validate_project_id;

validate_project_id("my-project")?;       // Ok
validate_project_id("")?;                  // Err: must not be empty
validate_project_id(&"x".repeat(257))?;   // Err: exceeds 256 chars

مصفوفة دلالات البحث

SearchRequest.project_idتُرجع الإدخالات العامةتُرجع إدخالات المشروع
None✅ الاستعلام المطابق❌ لا شيء
Some("A")✅ الاستعلام المطابق✅ إدخالات المشروع "A" المطابقة للاستعلام

مصفوفة دلالات الحذف

العمليةالنطاق
delete_entries (بدون مشروع)الإدخالات العامة المطابقة للاستعلام فقط
delete_entries_in_project("A")إدخالات المشروع "A" المطابقة للاستعلام فقط
delete_project("A")جميع الإدخالات للمشروع "A"
delete_userجميع الإدخالات (العامة + جميع المشاريع)

سلوك البحث

يستخدم InMemoryMemoryService المطابقة المستندة إلى الكلمات:

  1. يُقسَّم الاستعلام إلى كلمات (بحروف صغيرة)
  2. يُقسَّم محتوى كل ذاكرة إلى كلمات
  3. تُرجع الذكريات التي تحتوي على أي كلمات متطابقة
// Query: "rust programming"
// Matches memories containing "rust" OR "programming"

الواجهة الخلفية المخصصة للذاكرة

نفّذ MemoryService للتخزين المخصص (مثل قاعدة بيانات المتجهات):

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

pub struct VectorMemoryService {
    // Your vector DB client
}

#[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. Generate embeddings for each entry
        // 2. Store in vector database with metadata
        Ok(())
    }

    async fn search(&self, req: SearchRequest) -> Result<SearchResponse> {
        // 1. Generate embedding for query
        // 2. Perform similarity search
        // 3. Return top-k results
        Ok(SearchResponse { memories: vec![] })
    }
}

التكامل مع الوكلاء

تتكامل الذاكرة مع 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()?;

عند تهيئة الذاكرة:

  1. قبل كل دورة، يُبحث عن الذكريات ذات الصلة
  2. تُحقن الذكريات المتطابقة في السياق
  3. بعد كل جلسة، تُخزَّن المحادثة باعتبارها ذكريات

البنية

┌─────────────────────────────────────────────────────────────┐
│                      Agent Request                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Memory Search                            │
│                                                             │
│   SearchRequest { query, user_id, app_name, project_id }   │
│                         │                                   │
│                         ▼                                   │
│   ┌─────────────────────────────────────────────────────┐  │
│   │              MemoryService                          │  │
│   │  ┌─────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐  │  │
│   │  │InMemory │ │ SQLite   │ │Postgres│ │  Redis   │  │  │
│   │  │(dev)    │ │          │ │pgvector│ │          │  │  │
│   │  └─────────┘ └──────────┘ └────────┘ └──────────┘  │  │
│   │  ┌─────────┐ ┌──────────┐                           │  │
│   │  │MongoDB  │ │  Neo4j   │                           │  │
│   │  └─────────┘ └──────────┘                           │  │
│   └─────────────────────────────────────────────────────┘  │
│                         │                                   │
│                         ▼                                   │
│   SearchResponse { memories: Vec<MemoryEntry> }            │
│   (filtered by project scope)                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│              Context Injection                              │
│                                                             │
│   Relevant memories added to agent context                 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Agent Execution                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   Memory Storage                            │
│                                                             │
│   Session conversation stored for future recall            │
│   (global or project-scoped)                               │
└─────────────────────────────────────────────────────────────┘

أفضل الممارسات

الممارسةالوصف
استخدم قاعدة بيانات المتجهات في الإنتاجInMemory مخصّصة للتطوير/الاختبار فقط
حدّد النطاق حسب المستخدماحرص دائمًا على تضمين user_id للخصوصية
تحديد النتائجتقييد الذكريات المُعادة لتجنب تجاوز سعة السياق
تنظيف الذكريات القديمةتنفيذ TTL أو الأرشفة للبيانات القديمة
التضمين بذكاءتخزين الملخصات، وليس المحادثات الأولية

مقارنة مع الجلسات

الميزةحالة الجلسةالذاكرة
الاستمراريةمدة الجلسةدائم
النطاقجلسة واحدةعبر الجلسات
البحثالبحث عن قيمة مفتاحالبحث الدلالي
حالة الاستخدامالسياق الحاليالاسترجاع طويل الأمد

السابق: ← الضوابط | التالي: الاستوديو →

الذاكرة - وثائق ADK-Rust | ADK-Rust