الذاكرة
ذاكرة دلالية طويلة المدى لوكلاء الذكاء الاصطناعي باستخدام adk-memory.
نظرة عامة
يوفر نظام الذاكرة تخزينًا ثابتًا وقابلاً للبحث لمحادثات الوكيل. على عكس حالة الجلسة (التي تكون سريعة الزوال)، تستمر الذاكرة عبر الجلسات وتمكن الوكلاء من استدعاء السياق ذي الصلة من التفاعلات السابقة.
التثبيت
[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) للخلفيات التخزينية (memory backends):
#[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(),
};
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(),
};
let response = memory.search(request).await?;
println!("Found {} memories", response.memories.len());
Ok(())
}
عزل الذاكرة
يتم عزل الذكريات بواسطة:
app_name: التطبيقات المختلفة لها مساحات ذاكرة منفصلة.user_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(),
};
سلوك البحث
يستخدم InMemoryMemoryService المطابقة القائمة على الكلمات:
- يتم تقسيم الاستعلام إلى كلمات (أحرف صغيرة).
- يتم تقسيم محتوى كل ذاكرة إلى كلمات.
- يتم إرجاع الذكريات التي تحتوي على أي كلمات متطابقة.
// Query: "rust programming"
// Matches memories containing "rust" OR "programming"
واجهة خلفية ذاكرة مخصصة
نفّذ MemoryService للتخزين المخصص (مثل: vector database):
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![] })
}
}
التكامل مع Agents
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:
- قبل كل دور، يتم البحث عن
memoriesذات الصلة - يتم حقن
memoriesالمطابقة في السياق - بعد كل
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 أو الأرشفة للبيانات القديمة |
| التضمين بشكل استراتيجي | قم بتخزين الملخصات، وليس المحادثات الخام |
مقارنة مع الجلسات
| الميزة | حالة الجلسة | الذاكرة |
|---|---|---|
| الاستمرارية | مدة صلاحية الجلسة | دائمة |
| النطاق | جلسة واحدة | عبر الجلسات |
| البحث | البحث عن طريق المفتاح والقيمة | البحث الدلالي |
| حالة الاستخدام | السياق الحالي | الاستدعاء طويل الأمد |