الرسم البياني المعرفي
GraphMemoryService هو شكل مختلف من الذاكرة: فبدلاً من كومة من الإدخالات النصية، يخزن رسمًا بيانيًا معرفيًا للمستخدم — الكيانات، الحقائق ("الملاحظات") المرفقة بها، والعلاقات المحددة النوع بينها — ويتتبع كل ذلك ثنائيًا زمنيًا. هذه هي الواجهة الخلفية وراء مثال Mindfulness-with-Mia و صفحة الذاكرة في الوقت الفعلي.
إنه يطبق نفس MemoryService trait مثل الواجهات الخلفية الأخرى، لذا فإنه يندمج في Agent بنفس الطريقة — ولكنه يكشف عن API بياني أكثر ثراءً في الأعلى.
نموذج البيانات
Entity "Alice" (type: person)
├─ observation: "prefers email over phone" valid_from 2026-06-01
├─ observation: "timezone is CET" valid_from 2026-06-10
└─ relation: Alice ──works_at──▶ "Acme"
Entity— شيء مسمى (شخص، مكان، تفضيل، موضوع) معentity_typeحر الشكل.Observation— حقيقة واحدة مرفقة بكيان، معidمستقر وvalid_fromزمني.Relation— حافة محددة النوع بين كيانين (source ──relation_type──▶ target)، على سبيل المثالAlice ──works_at──▶ Acme.
يوجد أيضًا مخزن عرضي (kg_episodic) يسجل الأدوار الخام، منفصلًا عن الرسم البياني المنسق — لذلك تحتفظ بكل من النص والنموذج المقطر.
لماذا ثنائي زمني
يتم تتبع كل ملاحظة وعلاقة على طول محورين زمنيين:
- valid time — عندما كانت الحقيقة صحيحة في العالم (
valid_from←valid_to). - ingestion time — عندما تعلمها النظام.
عندما تتغير حقيقة، لا يتم حذف القديمة — بل يتم إبطالها (يتم تعيين valid_to الخاص بها) وتضاف الجديدة. وهذا يعني أن الرسم البياني يمكنه الإجابة على سؤال "ما هو التفضيل الحالي للمستخدم؟" دون فقدان "ما كان عليه في السابق." تبقى الحقائق التي تم تجاوزها في التاريخ بدلاً من الكتابة فوق الحاضر — وهذا بالضبط ما تريده لذاكرة تثق بها على مدار أشهر.
kg.invalidate_observation(old_id).await?; // mark a fact no longer valid
kg.invalidate_relation(old_id).await?; // mark an edge no longer valid
إنشاء واحد
graph-memory مدعوم بـ SQLite، لذا فهو ملف (أو في الذاكرة للاختبارات):
use adk_memory::GraphMemoryService;
use std::sync::Arc;
let kg = GraphMemoryService::new("sqlite://mia-memory.db").await?;
kg.migrate().await?; // idempotent schema setup
let kg = Arc::new(kg);
الكتابة إلى الرسم البياني
use adk_memory::{CreateEntityInput, CreateRelationInput};
kg.create_entities("coach", "alice", vec![CreateEntityInput {
name: "Alice".into(),
entity_type: "person".into(),
observations: vec!["prefers morning sessions".into(), "goal: run a 10k".into()],
}]).await?;
kg.create_relations("coach", "alice", vec![CreateRelationInput {
source: "Alice".into(), relation_type: "training_for".into(), target: "10k race".into(),
}]).await?;
// add facts to an existing entity later
kg.add_observations("coach", "alice", /* entity */ "Alice", vec!["timezone is CET".into()]).await?;
إنشاء كيان هو upsert — إعادة إنشاء كيان معروف يقوم بتحديث نوعه ووقته بدلاً من تكراره.
قراءته مرة أخرى
ثلاثة أشكال استدعاء، بالإضافة إلى search الخاص بالـ trait:
// 1. Token-scored relevance search → entities + their relations + a score
let hits = kg.search_nodes("coach", "alice", "what is she training for?", 5).await?;
// 2. Fetch specific entities by name
let nodes = kg.open_nodes("coach", "alice", &["Alice".into()]).await?;
// 3. The whole graph (small graphs / debugging)
let graph = kg.read_graph("coach", "alice").await?;
بطاقة الملف الشخصي
الميزة القاتلة لـ Agents: profile_card يعرض ملخصًا مضغوطًا وحديثًا لمن هو المستخدم — الكيانات التي تم تحديثها مؤخرًا وملاحظاتها الصالحة — جاهزًا للحقن في system prompt عند بدء الجلسة.
let card = kg.profile_card("coach", "alice").await?;
// → a short text block: "Alice (person): prefers morning sessions; goal: run a 10k…"
حدد حجمه بميزانية بحيث يظل الـ prompt صغيرًا مع نمو الرسم البياني:
let kg = GraphMemoryService::new(url).await?
.with_profile_budget(/* entities */ 12, /* observations per entity */ 5);
السماح لـ Agent بتنسيقه
نادرًا ما تستدعي create_entities يدويًا في الإنتاج — بل تمنح Agent أدوات للكتابة إلى الرسم البياني أثناء تعلمه. انظر Tools & agents لـ remember و relate، والتي تتطابق مباشرة مع الاستدعاءات أعلاه ويتم شحنها في adk-tool.
التالي: Tools & agents ←