مفاهيم الذاكرة
الجانب الخاص بـ semantic-store من الذاكرة مبني من عدد قليل من الأنواع الصغيرة. تعرّف على هذه الأربعة، وباقي القسم سيتبع.
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
كل backend يطبّق صفة واحدة. طريقتان مطلوبتان؛ أما الباقي فله تنفيذات افتراضية يمكن لـ backend أن يتجاوزها:
#[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تستوعب مجموعة إدخالات محادثة مكتملة. يستدعي Runner هذا لك عندما تكون الذاكرة مرفقة.searchهو الاسترجاع. تفسّر backend الاستعلام بشكل مختلف — مطابقة الكلمات المفتاحية، أو تشابه embedding، أو scoring للرموز في graph — لكن العقدة نفسها هي نفسها.
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>
حالة الجلسة مقابل الذاكرة
هذان أداتان مختلفتان — لا تخلط بينهما:
| حالة الجلسة | الذاكرة | |
|---|---|---|
| المدة | واحدة محادثة | عبر المحادثات |
| API | adk-session (SessionService، state map) | 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");
استخدم المشاريع لإبقاء، على سبيل المثال، مساعدي العمل والشخصي لمستخدم ما من مشاركة الذاكرة مع الاستمرار في مشاركة الحقائق العامة حقًا.
لا تنفذ كل الواجهات الخلفية نطاق المشروع
عزل المشروع هو قدرة في الواجهة الخلفية، وليس شيئًا يمكن للصفة ضمانه. اسأل قبل الاعتماد عليه:
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?;
التالي: الخلفيات →