Agent memory पुरानी होने से कैसे बचाएं और prune करें
Agent memory पुरानी होने पर गलत जानकारी देती है। समय सीमा वाले तथ्यों के लिए expiry सेट करें, cascade deletes का उपयोग करें और SQLite store को sqlite3 से चेक करें।
एजेंट की मेमोरी पुरानी क्यों हो जाती है
एजेंट की मेमोरी इसलिए पुरानी हो जाती है क्योंकि एक तथ्य को एक बार लिख दिया जाता है और उसे दोबारा कभी जांचा नहीं जाता। स्टोर इसे बार-बार लौटाता रहता है, रिट्रीवल लेयर इसे बिना किसी तारीख के सादे टेक्स्ट के रूप में प्रॉम्प्ट में डाल देती है, और मॉडल इसे उसी आत्मविश्वास के साथ दोहराता है जो इसे लिखे जाने के दिन था। इसमें कोई एरर नहीं आता। यही पूरी समस्या है: मॉडल और आपके लिए, एक पुरानी मेमोरी बिल्कुल नई मेमोरी जैसी ही दिखती है।
सेव करते समय बेहतर तरीके से लिखने से यह समस्या ठीक नहीं होती। इसे ठीक करने का तरीका यह है कि जिन तथ्यों की समय-सीमा तय हो सकती है, उन पर expiry सेट की जाए, और बाकी तथ्यों के लिए एक review routine बनाया जाए। एक छोटे डेटाबेस के लिए ये दोनों सामान्य रखरखाव के कार्य हैं, और इसमें अधिकांश काम SQL (structured query language) का होता है।
Decay और drift अलग-अलग प्रकार की विफलताएं हैं
Decay एक ऐसा तथ्य है जिसकी समाप्ति की एक निश्चित तिथि होती है। "इस सप्ताह यात्रा पर हूँ।" "Migration के लिए staging box बंद है।" "बजट ड्राफ्ट की समीक्षा कर रहा हूँ।" ये बातें लिखे जाते समय सत्य थीं, और आप लिखते समय ही इनकी शेल्फ-लाइफ बता सकते हैं। Decay का समाधान संभव है। इसमें एक expiry जोड़ें, जिसे कभी-कभी TTL (time to live) कहा जाता है, और समय पूरा होने पर उस row को delete कर दें।
Drift एक ऐसा तथ्य है जिसे एक बार store किया जाता है और फिर कभी दोबारा जांचा नहीं जाता। "pnpm पसंद है।" "Database Postgres 15 है।" "Deploy staging branch के माध्यम से होते हैं।" कोई भी घड़ी इन्हें गलत साबित नहीं करती। कहीं और लिया गया कोई निर्णय इन्हें गलत बनाता है, और आपके memory store को इसके बारे में कोई जानकारी नहीं मिलती।
Drift का कोई स्पष्ट स्वचालित समाधान नहीं है। एक store उस बदलाव का पता नहीं लगा सकता जिसे उसने कभी देखा ही नहीं, इसलिए जो job store को पढ़ती है और उस पर विचार करती है, वह केवल उसी पुराने text को दोबारा पढ़ रही होती है। जो तरीका काम करता है वह है तथ्य की उस चीज़ से दोबारा तुलना करना जिसका वह वर्णन करता है, जिसके लिए किसी व्यक्ति की आवश्यकता होती है, या ऐसे agent की जो ऐसा tool इस्तेमाल करे जो वर्तमान स्थिति को पढ़ सके।
इसलिए योजना दो भागों में विभाजित है। जो decay होता है उसे expire करें। जो drift होता है उसकी समीक्षा करें। दूसरे प्रकार की समस्या को पहले प्रकार की समस्या जैसा न समझें।
समय-सीमा वाले तथ्यों पर समाप्ति तिथि निर्धारित करना
प्रत्येक मेमोरी रो (row) को तीन ऐसे कॉलम की आवश्यकता होती है जो अधिकांश स्टोर्स में नहीं मिलते: तथ्य कहाँ से आया, इसकी अंतिम बार पुष्टि कब हुई, और यह कब तक सत्य रहेगा। यह एक ऐसा स्टोर है जिसे आप केवल sqlite3 का उपयोग करके बना सकते हैं, और इन्हीं कॉलम को आप अपने मौजूदा स्टोर में भी जोड़ सकते हैं।
CREATE TABLE memory (
id TEXT PRIMARY KEY,
subject TEXT NOT NULL,
fact TEXT NOT NULL,
source TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
confirmed_at TEXT NOT NULL DEFAULT (datetime('now')),
expires_at TEXT,
superseded_by TEXT REFERENCES memory(id) ON DELETE CASCADE
);
CREATE INDEX memory_expires ON memory(expires_at);
CREATE INDEX memory_superseded ON memory(superseded_by);datetime('now'), UTC (coordinated universal time) को YYYY-MM-DD HH:MM:SS के रूप में लौटाता है, जो टेक्स्ट के रूप में सही ढंग से सॉर्ट और तुलना करने योग्य है, इसलिए नीचे दिए गए सभी दिनांक संबंधी प्रश्न एक साधारण WHERE क्लॉज हैं। source कॉलम वैकल्पिक नहीं है। जिस तथ्य को आप किसी संदेश, फाइल या कमांड आउटपुट तक ट्रेस नहीं कर सकते, उसकी दोबारा जांच नहीं की जा सकती, और जिस तथ्य की दोबारा जांच नहीं हो सकती, उसे केवल हटाया ही जा सकता है।
समाप्त होने वाली मेमोरी लिखना:
INSERT INTO memory (id, subject, fact, source, expires_at)
VALUES ('m_0191', 'availability', 'Away from keyboard, replies are delayed',
'chat 2026-08-08', datetime('now', '+7 days'));डेटा प्राप्त (retrieval) करते समय कभी भी सीधे टेबल को न पढ़ें। इसके बजाय एक व्यू (view) पढ़ें जो समाप्त हो चुकी और पुरानी हो चुकी पंक्तियों को छिपा देता है:
CREATE VIEW live_memory AS
SELECT id, subject, fact, source, confirmed_at, expires_at
FROM memory
WHERE superseded_by IS NULL
AND (expires_at IS NULL OR expires_at > datetime('now'));यह व्यू इसका महत्वपूर्ण हिस्सा है, क्योंकि यह किसी प्रूनिंग (prune) प्रक्रिया के छूट जाने पर भी सिस्टम को सुरक्षित रखता है। एक समाप्त हो चुकी पंक्ति, उसके समाप्त होते ही रिट्रीवल में दिखना बंद हो जाती है, चाहे डिलीट जॉब चली हो या नहीं। डिलीट जॉब तब केवल डिस्क के उपयोग और रिव्यू लोड को नियंत्रित करती है, न कि डेटा की शुद्धता को।
sqlite3 memory.db "SELECT count(*) FROM memory;" के साथ गैप की जांच करें और live_memory के विरुद्ध समान गणना करें। एक स्वस्थ स्टोर में ये दोनों संख्याएं एक-दूसरे के करीब होती हैं। एक बड़ा अंतर मृत पंक्तियों (dead rows) के बैकलॉग को दर्शाता है।
मेमोरी डिलीट करने पर पुरानी मेमोरी पीछे क्यों रह जाती है
सुधार हमेशा जोड़ों में होते हैं। एजेंट यह सीखता है कि आप npm से pnpm पर चले गए हैं, एक नई पंक्ति लिखता है, और पुरानी पंक्ति को उसकी ओर इंगित (point) कर देता है:
UPDATE memory SET superseded_by = 'm_0207' WHERE id = 'm_0140';पुरानी पंक्ति अब live_memory के लिए अदृश्य है, और चेन अभी भी रिकॉर्ड करती है कि क्या बदला है। अब m_0207 को डिलीट करें, क्योंकि यह गलत साबित हुआ। superseded_by पर मौजूद ON DELETE CASCADE को अपने साथ m_0140 को भी ले जाना चाहिए, क्योंकि उस संबंध में पुरानी पंक्ति चाइल्ड (child) है। आमतौर पर ऐसा नहीं होता, क्योंकि SQLite फॉरेन कीज़ (foreign keys) को तब तक अनदेखा करता है जब तक आप उन्हें चालू न करें, और डिफ़ॉल्ट रूप से वे बंद रहती हैं:
sqlite3 memory.db "PRAGMA foreign_keys;"यह स्टॉक बिल्ड पर 0 प्रिंट करता है। फॉरेन कीज़ बंद होने पर, DELETE FROM memory WHERE id = 'm_0207'; सफल हो जाता है और m_0140 पीछे रह जाता है, जो एक ऐसी id की ओर इशारा करता है जिसका अब कोई अस्तित्व नहीं है। कोई भी चीज़ आपको चेतावनी नहीं देती। वह पंक्ति अब गलत कारण से छिपी हुई है, और पहली सफाई स्क्रिप्ट (tidy-up script) जो डैंगलिंग पॉइंटर्स को NULL पर रीसेट करती है, वह "prefers npm" को सीधे live_memory में वापस डाल देती है।
टूटी हुई चेन्स को खोजें:
sqlite3 memory.db "PRAGMA foreign_key_check;"foreign_key_check उल्लंघन (violations) की रिपोर्ट तब भी करता है जब प्रवर्तन (enforcement) बंद हो, इसलिए यह उस गंदगी पर काम करता है जो पहले से मौजूद है। यह प्रति उल्लंघन एक पंक्ति प्रिंट करता है: टेबल, rowid, पैरेंट टेबल, और कौन सी फॉरेन की विफल रही। खाली आउटपुट का मतलब है कि चेन्स बरकरार हैं।
जो नियम इसका पालन करता है वह संक्षिप्त है। PRAGMA foreign_keys = ON; प्रति कनेक्शन सेटिंग है, इसलिए हर कनेक्शन को इसकी आवश्यकता होती है: आपका एप्लिकेशन, आपकी प्रून स्क्रिप्ट, और वह sqlite3 सत्र जिसमें आप टाइप कर रहे हैं। इसे हर उस SQL फ़ाइल की पहली पंक्ति के रूप में रखें जो कुछ भी डिलीट करती है।
आपकी यादें वास्तव में कहाँ रहती हैं
कुछ भी डिलीट करने से पहले, यह पता लगाएँ कि आपके पास कितने स्टोरेज हैं। एक self-hosted memory service आमतौर पर memory text और उसके embedding को एक vector database में रखती है, और एक change log को SQLite में रखती है। ये अलग-अलग फाइलें हैं जिनका lifecycle भी अलग होता है, और ये एक-दूसरे से स्वतंत्र रूप से विफल हो सकती हैं।
mem0 एक उचित उदाहरण है, और यही संरचना अन्य जगहों पर भी दिखाई देती है। इसकी open source library डिफ़ॉल्ट रूप से /tmp/qdrant पर Qdrant vector store का उपयोग करती है, जो mem0 नामक collection में होता है, साथ ही ~/.mem0/history.db पर एक SQLite change log रखती है जिसका स्थान MEM0_DIR environment variable द्वारा निर्धारित होता है। history table में memory_id, old_memory, new_memory, event, created_at और is_deleted होते हैं।
उस column list को दोबारा पढ़ें। SQLite फाइल एक change log है। यादें स्वयं Qdrant में होती हैं, इसलिए history.db से rows डिलीट करने पर केवल यह record हटता है कि कुछ बदला था, लेकिन memory अभी भी प्राप्त की जा सकती है। Deletes को library के स्वयं के API (application programming interface) के माध्यम से किया जाना चाहिए ताकि दोनों स्थान अपडेट हो सकें:
from mem0 import Memory
memory = Memory()
memory.delete(memory_id="mem_123")
memory.delete_all(user_id="alice")/tmp डिफ़ॉल्ट सेटिंग एक चेतावनी की हकदार है। Ubuntu 24.10 और उसके बाद के संस्करणों पर, /tmp एक tmpfs है, जो memory में स्थित एक filesystem है, इसलिए हर reboot के बाद यह खाली हो जाता है और पूरा store नष्ट हो जाता है। findmnt /tmp के साथ अपना कॉन्फ़िगरेशन चेक करें। यदि कोई लाइन tmpfs दिखाती है, तो path को आज ही बदलें:
config = {
"vector_store": {
"provider": "qdrant",
"config": {"collection_name": "mem0", "path": "/srv/agent/qdrant"},
}
}
memory = Memory.from_config(config)यही प्रश्न हर उस चीज़ पर लागू होता है जिसे आप run करते हैं। कॉन्फ़िगरेशन पढ़ें, और उन सभी paths को लिखें जहाँ service डेटा लिखती है। अपने स्वयं के VPS पर mem0 memory server चलाना उस सेवा के पक्ष को कवर करता है, और agent memory को एक मशीन तक सीमित रखना एक छोटा store है जिसमें रखरखाव की समान आवश्यकताएं होती हैं।
sqlite3 के साथ स्टोर को पढ़ना
यदि CLI (command line interface) मौजूद न हो, तो इसे sudo apt install -y sqlite3 के साथ install करें। इसके बाद, चार commands आपके डिस्क पर मौजूद किसी भी स्टोर से जुड़े अधिकांश सवालों के जवाब दे देती हैं।
sqlite3 ~/.mem0/history.db ".tables"tables की सूची दिखाता है। यदि output खाली है, तो इसका मतलब है कि आपने गलत file खोली है।sqlite3 ~/.mem0/history.db ".schema history"सटीक columns को print करता है, जो कि किसी स्टोर की बनावट का एकमात्र विश्वसनीय documentation है।sqlite3 -cmd ".mode line" ~/.mem0/history.db "SELECT * FROM history ORDER BY created_at DESC LIMIT 5;"सबसे हालिया पांच बदलावों को प्रति field एक line में दिखाता है, जो तब भी पढ़ने योग्य रहता है जब किसी column में पूरा paragraph हो।sqlite3 ~/.mem0/history.db "SELECT event, count(*) FROM history GROUP BY event;"यह दिखाता है कि स्टोर क्या कर रहा है, और आपकी library वास्तव में कौन से event names लिखती है।
हर memory store एक database नहीं होता। हर session की शुरुआत में पढ़ी जाने वाली notes की एक साधारण file में न केवल विफलताएं होती हैं, बल्कि इसमें कोई tooling भी नहीं होती: न कोई expiry column, न कोई पुष्टि की गई तारीख, और न ही dead rows को छिपाने का कोई तरीका। अपने हाथ से लिखी गई हर line पर तारीख डालें और उसे हर महीने दोबारा पढ़ें। Claude Code sessions के बीच बनी रहने वाली memory में भी छोटे दायरे में यही समस्या होती है।
उन तथ्यों की समीक्षा करना जिनकी समय-सीमा समाप्त नहीं हो सकती
Drift के लिए एक queue, एक cap और एक आदत की आवश्यकता होती है। Queue सबसे पुराने पुष्टिकरणों (confirmations) की होती है:
SELECT id, subject, fact, source, confirmed_at
FROM live_memory
WHERE confirmed_at < datetime('now', '-90 days')
ORDER BY confirmed_at
LIMIT 20;प्रति सप्ताह बीस पंक्तियों (rows) की समीक्षा एक ऐसा कार्य है जिसे कोई भी वास्तव में पूरा कर सकता है। चार सौ पंक्तियों की समीक्षा कोई नहीं करता, जिससे आप वहीं पहुँच जाते हैं जहाँ से शुरू किया था। प्रत्येक पंक्ति के लिए दो परिणाम होते हैं। इसे इसके source के विरुद्ध पुनः जाँचें और उस पर मुहर लगाएँ:
UPDATE memory SET confirmed_at = datetime('now') WHERE id = 'm_0140';या इसे बदलें: नया तथ्य डालें, पुरानी पंक्ति के superseded_by को नई id पर सेट करें, और chain को इतिहास सुरक्षित रखने दें।
दो आदतें इसे सस्ता बनाती हैं। Store को छोटा रखें, क्योंकि केवल बढ़ने वाला store समीक्षा को असंभव बना देता है: एक last_used_at कॉलम जोड़ें, जब कोई पंक्ति वास्तव में प्राप्त (retrieved) की जाए तो उसे अपडेट करें, और छह महीने से उपयोग न की गई पंक्तियों को विलोपन (deletion) के लिए उम्मीदवार मानें। इसमें प्रति retrieval एक write का खर्च आता है, इसलिए यदि agent अधिक सक्रिय है तो इसे batch में करें।
दूसरी आदत पर कोई खर्च नहीं आता। Prompt में आयु (age) शामिल करें। यदि आपका retriever जो memory block बनाता है, उसमें प्रत्येक तथ्य के साथ confirmed 2026-05-02 मौजूद हो, तो model यह कहने के बजाय कि "आप pnpm का उपयोग कर रहे हैं", यह कह सकता है कि "मई तक आप pnpm का उपयोग कर रहे थे"। बिना तारीख वाला तथ्य language model के लिए हर बार वर्तमान काल (present tense) में पढ़ा जाता है।
prune को एक schedule पर चलाएं
एक prune जो केवल आपके याद आने पर चलता है, वह वास्तव में नहीं चलता है। SQL को /srv/agent/prune.sql में डालें:
PRAGMA foreign_keys = ON;
DELETE FROM memory
WHERE expires_at IS NOT NULL AND expires_at <= datetime('now');
DELETE FROM memory
WHERE superseded_by IS NOT NULL
AND created_at < datetime('now', '-180 days');/etc/systemd/system/memory-prune.service को save करें:
[Unit]
Description=Prune expired agent memories
[Service]
Type=oneshot
User=agent
ExecStart=/usr/bin/sqlite3 /srv/agent/memory.db ".read /srv/agent/prune.sql"और /etc/systemd/system/memory-prune.timer:
[Unit]
Description=Run the agent memory prune daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now memory-prune.timer
systemctl list-timers memory-prune.timerlist-timers में एक NEXT कॉलम दिखना चाहिए जिसमें वास्तविक समय हो, और पहली बार चलने के बाद एक LAST कॉलम होना चाहिए। इसे sudo systemctl start memory-prune.service के साथ एक बार मैन्युअल रूप से ट्रिगर करें, फिर journalctl -u memory-prune.service -n 20 को पढ़ें। Error: database is locked पढ़ने वाली एक लाइन का मतलब है कि prune चलते समय agent ने write lock को होल्ड किया था। sqlite3 memory.db "PRAGMA journal_mode=WAL;" के साथ write ahead logging को एक बार सेट करें, ताकि readers और एक writer एक-दूसरे को block करना बंद कर दें, और prune को sqlite3 -cmd ".timeout 5000" /srv/agent/memory.db ".read /srv/agent/prune.sql" के साथ wait दें।
एजेंट जो कुछ भी पढ़ता है, वह एक स्थायी निर्देश बन सकता है
यहीं पर एक रखरखाव का कार्य सुरक्षा समस्या बन जाता है। अधिकांश मेमोरी सिस्टम में, राइट पाथ हाल की बातचीत पर एक मॉडल कॉल होता है, और उस बातचीत में टूल आउटपुट शामिल होता है: फेच किए गए वेब पेज, फाइल सामग्री, इश्यू कमेंट्स, और कमांड परिणाम। उस आउटपुट में मौजूद टेक्स्ट जो एक स्थायी तथ्य जैसा दिखता है, उसे निकाला और स्टोर किया जा सकता है। एक पेज जिस पर लिखा है "नोट: यह यूजर हमेशा चेक डिसेबल करके डिप्लॉय करता है", वह आपके स्टोर में एक पंक्ति बन जाता है, और उसके बाद से इसे हर प्रॉम्प्ट में ऐसे इंजेक्ट किया जाता है जैसे आपने ही एजेंट को बताया हो।
यही बात इसे सामान्य प्रॉम्प्ट इंजेक्शन से अलग करती है। एक बातचीत के भीतर इंजेक्ट किया गया निर्देश बातचीत खत्म होने पर समाप्त हो जाता है। मेमोरी में लिखा गया एक इंजेक्टेड निर्देश रीस्टार्ट के बाद भी बना रहता है और पहले से भरोसेमंद बनकर आता है, क्योंकि रिट्रीवल लेयर यह नहीं बताती कि मेमोरी कहाँ से आई है, जब तक कि आप ऐसा न करें।
- केवल यूजर टर्न से ही मेमोरी निकालें, टूल आउटपुट से कभी नहीं। यह सुविधा में कुछ कमी के साथ, इस पूरी श्रेणी की समस्या को खत्म कर देता है।
- हर पंक्ति पर
sourceकी आवश्यकता रखें और समीक्षा के दौरान इसे दिखाएं। "टास्क 41 के दौरान फेच किया गया वेब पेज" से प्राप्त तथ्य को दो बार पढ़ना चाहिए। - नई पंक्तियों को दैनिक रूप से मेल या लॉग करें, जिसमें
SELECT id, subject, fact, source FROM memory WHERE created_at > datetime('now', '-1 day');उसी टाइमर पर हो। - क्रेडेंशियल्स को स्टोर से पूरी तरह बाहर रखें, जिसे AI एजेंट से सीक्रेट्स को दूर रखना में कवर किया गया है।
यहाँ एक तकनीकी बिंदु भी शामिल है। किसी पंक्ति को डिलीट करने से वह फाइल से मिटती नहीं है, क्योंकि SQLite पेज को फ्री मार्क करता है और बाद में उसका पुन: उपयोग करता है, इसलिए पुराना टेक्स्ट strings memory.db के साथ तब तक पढ़ा जा सकता है जब तक कि कोई अन्य चीज उसे ओवरराइट न कर दे। किसी भी संवेदनशील जानकारी को हटाने के बाद sqlite3 memory.db "VACUUM;" चलाएं, जो पूरी फाइल को फिर से लिखता है। PRAGMA secure_delete = ON; डिलीट करने वाले कनेक्शन को फ्री की गई सामग्री को शून्य (zeros) से ओवरराइट करने के लिए मजबूर करता है।
क्या बैकअप लें और किस क्रम में
स्टोर छोटा है और इसे दोबारा बनाना कठिन है, इसलिए इसका उचित बैकअप लें। कभी भी किसी लाइव database फाइल को cp के साथ कॉपी न करें, क्योंकि लिखते समय ली गई कॉपी शायद न खुले। SQLite में इन-बिल्ट snapshot का उपयोग करें:
sqlite3 /srv/agent/memory.db "VACUUM INTO '/srv/backup/memory-$(date +%F).db'"
sqlite3 /srv/backup/memory-$(date +%F).db "PRAGMA integrity_check;"integrity_check ok को प्रिंट करना ही इस बात का एकमात्र प्रमाण है कि बैकअप फाइल उपयोग करने योग्य है। इसके अलावा कुछ भी करने का अर्थ है कि पिछला बैकअप सुरक्षित रखें और उसे ओवरराइट करने से पहले जांच करें।
उसी जॉब में, एक ही समय पर vector store का snapshot लें। यदि दोनों हिस्सों को घंटों के अंतराल पर कैप्चर किया जाता है, तो रिस्टोर करने पर नया change log पुरानी यादों के सेट के साथ मिल जाएगा, और डिलीट किए गए तथ्य वापस आ जाएंगे। दोनों को एक ही दिनांकित डायरेक्टरी में लिखें ताकि उन्हें केवल एक साथ ही रिस्टोर किया जा सके। VPS पर production में SQLite चलाना लॉकिंग, बैकअप और लंबे समय तक चलने वाली सर्विस के लिए आवश्यक सेटिंग्स के बारे में विस्तार से बताता है।
FAQ
एजेंट की मेमोरी को समाप्त होने से पहले कितने समय तक रहना चाहिए?
समाप्ति का समय किसी वैश्विक डिफ़ॉल्ट के बजाय तथ्य के आधार पर निर्धारित करें। यात्रा संबंधी नोट या "इस सप्ताह इस प्रोजेक्ट पर काम कर रहे हैं" जैसे नोट के लिए सात दिन का समय रखें। टीम के नियमों या व्यक्तिगत प्राथमिकताओं के लिए कोई समाप्ति तिथि न रखें और उन्हें इसके बजाय समीक्षा कतार (review queue) में डालें। किसी सॉफ्टवेयर संस्करण के बारे में तथ्य की समाप्ति अवधि लगभग उस प्रोजेक्ट की release cadence के बराबर होनी चाहिए। यदि आप तथ्य लिखते समय उसकी शेल्फ लाइफ तय नहीं कर पा रहे हैं, तो यह संकेत है कि वह जानकारी समय के साथ बदलती है, न कि पुरानी होती है। इसलिए उसे confirmed_at तिथि दें और उसे समाप्त करने के बजाय उसकी समीक्षा करें।
क्या मैं स्वचालित रूप से पता लगा सकता हूँ कि कोई संग्रहीत तथ्य गलत हो गया है?
विश्वसनीय रूप से नहीं। स्टोर के पास अपने बाहर की दुनिया का कोई दृश्य नहीं होता है, इसलिए वह उस बदलाव को नहीं देख सकता जिसने किसी तथ्य को गलत बना दिया है। जो जॉब स्टोर को फिर से पढ़ता है, वह केवल उसी पुराने टेक्स्ट को दोबारा पढ़ रहा होता है। आप जो स्वचालित कर सकते हैं वह है जानकारी को सामने लाना: confirmed_at के आधार पर सॉर्ट करें और सबसे पुरानी पंक्तियों को किसी व्यक्ति के सामने रखें, या ऐसे एजेंट के सामने रखें जिसके पास ऐसा टूल हो जो repository, config file या monitoring endpoint से वर्तमान स्थिति पढ़ सके। कतार को स्वचालित करना उपयोगी है। निर्णय को स्वचालित करना अभी संभव नहीं है।
मैंने एक मेमोरी डिलीट की और वह वापस आ गई। क्यों?
आमतौर पर ऐसा इसलिए होता है क्योंकि दो स्टोर होते हैं और आपने केवल एक में लिखा है। मेमोरी टेक्स्ट और उसकी embedding सामान्यतः एक vector database में रहती है, जबकि एक SQLite फाइल change log रखती है। इसलिए SQLite फाइल से पंक्तियाँ हटाने पर केवल audit record हटता है और मेमोरी पुनः प्राप्त की जा सकती है। library API के माध्यम से डिलीट करें ताकि दोनों अपडेट हो जाएं। दूसरा सामान्य कारण restore है, जहाँ vector store और SQLite फाइल का snapshot अलग-अलग समय पर लिया गया था, इसलिए restore करने पर वे पंक्तियाँ वापस आ जाती हैं जिन्हें दूसरे हिस्से ने पहले ही हटा दिया था।
क्या एजेंट के चलते समय मेमोरी डेटाबेस को मैन्युअल रूप से एडिट करना सुरक्षित है?
पढ़ना (Reads) सुरक्षित है। लिखना (Writes) केवल write ahead logging मोड में ही सुरक्षित है, और वह भी एक समय में केवल एक राइटर के साथ। यह देखने के लिए कि आप किस मोड में हैं, sqlite3 memory.db "PRAGMA journal_mode;" चलाएँ, और wal वह उत्तर है जो आपको चाहिए। यदि आप Error: database is locked देखते हैं, तो किसी अन्य प्रक्रिया के पास write lock है। इसलिए अपने सत्र को sqlite3 -cmd ".timeout 5000" के साथ प्रतीक्षा दें या पहले एजेंट सर्विस को रोकें। vector store को मैन्युअल रूप से एडिट करना अलग है: उसे library पर छोड़ दें, क्योंकि embedding और टेक्स्ट का एक-दूसरे के साथ सुसंगत रहना आवश्यक है।