Yapay zeka ajanları, günümüzün en heyecan verici teknolojik gelişmelerinden biri olarak karşımıza çıkıyor. Ancak, bu akıllı sistemlerin en büyük zorluklarından biri, edindikleri bilgileri kalıcı olarak hatırlayabilmeleri ve bu bilgileri yeni etkileşimlerde kullanabilmeleri. Çoğu zaman, büyük dil modelleri (LLM’ler) gibi teknolojilerle çalışan ajanlar, sadece o anki “bağlam penceresi” içinde bilgi tutabilir ve pencere kapandığında her şeyi unutma eğilimindedir. Peki, ajanlarımıza bir vektör veritabanının karmaşıklığına bulaşmadan nasıl uzun süreli hafıza kazandırabiliriz? İşte bu yazıda, bu sorunun cevabını, pratik ve anlaşılır yaklaşımlarla birlikte adım adım inceleyeceğiz.
Modern yapay zeka ajanları, özellikle diyalog sistemleri, kişisel asistanlar veya karmaşık görevleri otomatize eden botlar, insan benzeri bir etkileşim deneyimi sunmayı hedefler. Ancak, bu hedefe ulaşmanın önündeki en büyük engellerden biri, ajanların genellikle “unutkan” olmasıdır. Yani, bir sohbetin veya görevin sonunda, edindikleri tüm bilgileri kaybederler ve bir sonraki etkileşimde her şeye sıfırdan başlarlar. Bu durum, hem kullanıcı deneyimini olumsuz etkiler hem de ajanın karmaşık, çok adımlı görevleri öğrenme ve yerine getirme yeteneğini ciddi şekilde sınırlar. Örneğin, bir müşteri hizmetleri botu, önceki görüşmelerde konuşulan sorunları veya tercihleri hatırlayamadığında, müşteri aynı bilgileri defalarca tekrarlamak zorunda kalır; bu da doğal olarak hayal kırıklığı yaratır. Veya bir proje yönetim asistanı, bir önceki toplantıda belirlenen hedefleri, mevcut görevlerin durumunu veya ekip üyelerinin uzmanlık alanlarını hafızasında tutamazsa, her seferinde baştan yönlendirilmek zorunda kalır.
Bu unutkanlık problemini çözmek için geliştirilen ilk ve en popüler çözümlerden biri, vektör veritabanları (vector databases) ve gömülü (embedding) tabanlı anlamsal aramadır. Bu sistemler, metinleri sayısal vektörlere dönüştürerek, anlamsal olarak benzer bilgileri hızlıca bulmayı sağlar. Harika bir teknoloji olmasına rağmen, vektör veritabanlarının kendine özgü zorlukları vardır. Bunlar arasında, altyapı kurulumu ve yönetimi, embedding modellerinin seçimi ve optimizasyonu, maliyetler, veri senkronizasyonu ve özellikle de daha küçük ölçekli veya bütçesi kısıtlı projeler için gereksiz yere karmaşık hale gelebilen bir öğrenme eğrisi bulunur. Kısacası, her proje için bir vektör veritabanı kurmak, bir sineği avlamak için top kullanmaya benzeyebilir. Oysa bazen daha basit, daha doğrudan ve daha az kaynak tüketen çözümlere ihtiyacımız vardır. Bu noktada, daha geleneksel ama akıllıca uygulanan veri depolama ve erişim yöntemleri devreye girer. Amacımız, ajanın geçmiş deneyimlerinden, öğrenimlerinden ve önemli bilgilerden oluşan bir “bilgi bankası” oluşturarak, gerektiğinde bu bilgilere hızlı ve etkili bir şekilde ulaşmasını sağlamaktır. Böylece, ajanın daha tutarlı, kişiselleştirilmiş ve öğrenme yeteneği yüksek bir varlık haline gelmesinin yolunu açarız.
AI Ajan Belleği ve Vektör Veritabanlarının Ötesi
AI ajanlarının uzun süreli belleğe sahip olması, onların sadece şimdiki zamana odaklanmak yerine, geçmiş deneyimlerinden öğrenmesini ve bu bilgileri gelecekteki etkileşimlerde kullanmasını sağlar. Temel olarak, bir AI ajanının belleği iki ana kategoriye ayrılabilir: kısa süreli bellek ve uzun süreli bellek.
- Kısa Süreli Bellek (Bağlam Penceresi): Bu, büyük dil modellerinin (LLM’ler) işlem sırasında aktif olarak tuttuğu bilgidir. Tipik olarak, LLM’ler belirli bir belirteç (token) sayısıyla sınırlı bir “bağlam penceresine” sahiptir. Bu pencereye sığan tüm metinler, modelin o anki yanıtını oluşturmak için kullanılır. Ancak, pencere dolduğunda veya etkileşim sona erdiğinde, eski bilgiler dışarı itilir ve unutulur. Bu, bir insan zihnindeki anlık düşünceler veya çalışma belleği gibidir.
- Uzun Süreli Bellek: Ajanın kalıcı olarak sakladığı, gelecekteki kullanım için erişilebilen tüm bilgilerdir. Bu bilgiler, önceki konuşmaları, kullanıcı tercihlerini, öğrenilen gerçekleri, tanımlanan görevleri veya herhangi bir harici veri setini içerebilir. İnsan beynindeki gibi, uzun süreli bellek de farklı katmanlara sahip olabilir; örneğin, “anısal (episodic) bellek” belirli olayları ve deneyimleri saklarken, “semantik (semantic) bellek” genel dünya bilgisini, kavramları ve gerçekleri depolar.
Vektör veritabanları, uzun süreli bellek sağlamanın oldukça güçlü bir yoludur. Temel prensip, metin parçalarını yüksek boyutlu vektörlere dönüştürmek (embedding) ve bu vektörleri veritabanında saklamaktır. Bir sorgu geldiğinde, sorgu da bir vektöre dönüştürülür ve veritabanındaki diğer vektörlerle anlamsal benzerliğine göre en alakalı sonuçlar bulunur. Ancak, daha önce de belirttiğimiz gibi, vektör DB’lerin kurulumu, yönetimi ve ölçeklendirilmesi, özellikle daha küçük veya deneysel projeler için gereğinden fazla karmaşık olabilir. Bu “baş ağrısı”, genellikle şunları içerir:
- Altyapı Yönetimi: Vektör DB’leri kurmak ve sürdürmek, özel sunucular veya bulut hizmetleri gerektirebilir.
- Embedding Modelleri: Doğru embedding modelini seçmek, onu fine-tune etmek ve model çıktılarının kalitesini yönetmek ayrı bir uzmanlık alanıdır.
- Maliyet: Yüksek boyutlu vektörlerin depolanması ve hızlı aranması, önemli işlem ve depolama kaynakları gerektirebilir.
- Karmaşıklık: Anlamsal aramanın inceliklerini anlamak ve uygulamak, geleneksel veritabanı sorgularından daha farklı bir düşünce yapısı gerektirir.
Amacımız, bu karmaşıklıktan kaçınarak, benzer faydaları daha basit ve yönetilebilir yollarla elde etmektir. Bu, “anımsama” (retrieval) yeteneğini tamamen kaybetmek anlamına gelmez; aksine, anlamsal aramayı daha basit metin tabanlı veya yapısal tabanlı yöntemlerle taklit etmeye çalışırız. Örneğin, belirli anahtar kelimelerle arama yapmak, önceden tanımlanmış kategorilere göre filtreleme yapmak veya hatta LLM’nin kendisini bir “sorgu motoru” olarak kullanarak bellekten bilgi çekmek gibi yaklaşımlar mümkündür. Önemli olan, ajanın geçmiş deneyimlerinden ders çıkarabilmesi ve her yeni etkileşimde daha bilgili ve bağlamsal olarak uygun yanıtlar verebilmesidir. Bu yolda, geleneksel veritabanları, dosya sistemleri ve basit anahtar-değer depoları gibi araçlar, şaşırtıcı derecede güçlü çözümler sunabilir.
Alternatif Yaklaşımlar: Basit Yapılarla Bilgi Yönetimi Nasıl Sağlanır?
Vektör veritabanlarının karmaşıklığından kaçınarak AI ajanlarımıza uzun süreli bellek kazandırmak için bir dizi alternatif ve genellikle daha basit yaklaşım mevcuttur. Bu yaklaşımlar, temel olarak bilginin nasıl depolanacağı ve daha sonra nasıl geri çağrılacağı üzerine kuruludur. Ana fikir, bilginin, ajanın anlayabileceği ve işleyebileceği yapılandırılmış veya yarı yapılandırılmış bir formatta saklanmasıdır.
Yapısal Metin Depolama: JSON ve İlişkisel Olmayan Veritabanları
Bilgiyi yapılandırılmış bir şekilde depolamak, hem depolama hem de geri çağırma süreçlerini büyük ölçüde kolaylaştırır. İşte bu amaçla kullanabileceğiniz bazı popüler ve erişilebilir teknolojiler:
- JSON Dosyaları: JavaScript Object Notation (JSON), insan tarafından okunabilir ve kolayca ayrıştırılabilir bir veri değişim formatıdır. Her bir bellek parçacığını (örneğin, bir kullanıcının tercihleri, bir görevin detayları, bir konuşma özeti) bir JSON objesi olarak saklayabilir ve bu objeleri bir dosyada veya basit bir dizin yapısında tutabilirsiniz.
Avantajları: Çok basit kurulum, yüksek okunabilirlik, esneklik (şema gereksinimi yok).
Dezavantajları: Büyük veri setlerinde performans sorunları, eşzamanlı erişimde kilitlenme riski, karmaşık sorgular için yetersizlik.
Ne zaman kullanılır: Küçük ölçekli projeler, konfigürasyon verileri, tek kullanıcılı ajanlar, hızlı prototipleme. - SQLite: SQLite, sunucusuz, kendini içeren, yapılandırılabilir, sıfır konfigürasyonlu, işlem odaklı bir ilişkisel veritabanı yönetim sistemidir. Veritabanının tamamı tek bir disk dosyasında saklanır.
Avantajları: Hafif, kurulum gerektirmez (kütüphane olarak gelir), SQL ile güçlü sorgulama yetenekleri, ACID uyumluluğu, orta ölçekli veri setleri için iyi performans.
Dezavantajları: Yüksek eşzamanlı yazma işlemleri için sınırlı, dağıtık sistemler için uygun değil.
Ne zaman kullanılır: Tek ajanlı sistemler, masaüstü uygulamaları, mobil uygulamalar, web servislerinin hafif arka plan veritabanları. Bir müşteri hizmetleri botunun geçmiş görüşmelerini veya bir öğrenme asistanının öğrenci notlarını saklaması için idealdir. - Redis: Redis, açık kaynaklı, bellek içi bir veri yapısı sunucusudur. Genellikle bir önbellek (cache) olarak kullanılsa da, kalıcı veri depolama yetenekleri sayesinde anahtar-değer deposu olarak da işlev görebilir. Özellikle hızlı okuma/yazma gerektiren senaryolar için mükemmeldir.
Avantajları: Olağanüstü hızlı erişim, çeşitli veri yapıları (hash’ler, listeler, setler), kalıcılık seçenekleri.
Dezavantajları: Bellek tabanlı olduğu için maliyetli olabilir, çok büyük veri setleri için bellek kısıtlamaları.
Ne zaman kullanılır: Oturum bilgileri, anlık bildirimler, sık erişilen veriler, hızlı durum depolama. Örneğin, bir oyun NPC’sinin (oyuncu olmayan karakter) o anki durumunu, son etkileşimlerini veya kısa süreli hedeflerini depolamak için kullanılabilir.
Vaka Analizi: Müşteri Hizmetleri Botu ve SQLite
Diyelim ki bir e-ticaret sitesi için müşteri hizmetleri botu geliştiriyorsunuz. Bu botun, müşterinin geçmiş siparişlerini, şikayetlerini ve tercihlerini hatırlaması gerekiyor. Her müşteriyle her yeni etkileşimde bu bilgileri tekrar sormak, kullanıcı deneyimini zedeler. SQLite, bu senaryo için ideal bir çözümdür. Her müşterinin verilerini, müşteri ID’si ile ilişkilendirilmiş bir tabloya kaydedebilirsiniz. Örneğin, MusteriGecmisi tablosu (MusteriID, SiparisID, SiparisTarihi, SorunTuru, Cozum, Tercihler) gibi sütunlara sahip olabilir. Bot, yeni bir etkileşim başladığında, müşteri ID’sini kullanarak SQLite’dan geçmiş verileri çeker ve LLM’nin bağlam penceresine ekler. Böylece LLM, müşterinin geçmişini bilerek daha kişiselleştirilmiş ve etkili yanıtlar üretebilir. Bu yaklaşım, karmaşık bir dağıtık sistem kurmaya gerek kalmadan, tek bir sunucuda veya hatta yerel bir uygulamada bile etkili bir uzun süreli bellek çözümü sunar.
Bilgi Formatlama ve Modelleme: Anlamı Nasıl Yakalarız?
Sadece veriyi depolamak yetmez; aynı zamanda veriyi ajanın kolayca anlayabileceği ve işleyebileceği bir formatta modellemek de önemlidir. İşte bazı yaklaşımlar:
- Ham Metin Depolama: En basit yöntem, her bellek parçasını olduğu gibi (örneğin, bir konuşma transkripti veya bir belge) saklamaktır. Geri çağırma sırasında anahtar kelimelerle arama yapılabilir.
- Yapılandırılmış Veri: Bilgiyi anahtar-değer çiftleri, JSON objeleri veya ilişkisel tablo kayıtları olarak depolamak, hem depolamayı hem de sorgulamayı kolaylaştırır. Örneğin, bir kullanıcının “pizza siparişi” isteğini sadece metin olarak değil,
{"type": "sipariş", "ürün": "pizza", "boyut": "orta", "ekstralar": ["mantar", "sucuk"], "adres": "..."}gibi yapılandırılmış bir formatta saklayabilirsiniz. Bu, ajanın daha sonra bu bilgiyi daha kesin bir şekilde işlemesine olanak tanır. - Üçlüler (Triples): Bilgi grafiği tabanlı yaklaşımların basitleştirilmiş bir formu olan üçlüler (Subject-Predicate-Object), bilgiyi
(Varlık, İlişki, Değer)formatında ifade eder. Örneğin,(Ahmet, sever, kahve)veya(İstanbul, sahip, nüfus). Bu format, karmaşık ilişkileri ve gerçekleri depolamak için güçlüdür ve sorgulama sırasında ilişkisel çıkarımlar yapmayı kolaylaştırır.
Bilgiyi yapılandırma biçimimiz, ajanın bellekteki bilgileri ne kadar verimli bir şekilde kullanabileceğini doğrudan etkiler. Basit bir anahtar kelime araması için ham metin yeterli olabilirken, daha karmaşık çıkarımlar ve mantıksal sorgulamalar için yapılandırılmış veya üçlü tabanlı depolama çok daha etkilidir. Bu modeller, ajanın sadece ne söylendiğini değil, aynı zamanda söylenenlerin ne anlama geldiğini ve diğer bilgilerle nasıl ilişkili olduğunu da anlamasına yardımcı olur. Böylece, vektör DB’lerin anlamsal güçlerini taklit etme yolunda önemli bir adım atmış oluruz.
Bellek Mekanizmalarını Oluşturma: Ajanınız Bilgiyi Nasıl Hatırlar?
Bir AI ajanı için uzun süreli bellek oluşturmak, sadece veriyi bir yere kaydetmekten ibaret değildir; aynı zamanda bu verinin nasıl ekleneceği, güncelleneceği ve en önemlisi, ihtiyaç duyulduğunda nasıl geri çağrılacağıyla ilgilidir. Bu süreçler, ajanın zekasının ve kullanışlılığının temelini oluşturur.
Bilgi Ekleme ve Güncelleme Stratejileri
Ajanın yeni bilgileri belleğine nasıl kaydedeceği ve mevcut bilgileri nasıl güncelleyeceği, bellek sisteminin verimliliği için kritik öneme sahiptir. İşte bazı stratejiler:
- Otomatik Öğrenme ve Çıkarma: Ajan, etkileşimler sırasında doğal dil işleme (NLP) yeteneklerini kullanarak önemli bilgileri otomatik olarak çıkarabilir. Örneğin, bir sohbet botu, kullanıcının “En sevdiğim renk mavidir” dediğini duyduğunda, bu bilgiyi
{"kullanici_id": "...", "tercih_tipi": "favori_renk", "deger": "mavi"}gibi yapılandırılmış bir formatta belleğine kaydedebilir. Bu çıkarma işlemi, LLM’nin kendisi tarafından veya daha küçük, özel olarak eğitilmiş NLP modelleriyle yapılabilir.def extract_and_store_preference(user_id, text, memory_db): # LLM'e metni vererek önemli bilgileri çıkarmasını isteyin # Örnek: "En sevdiğim renk mavidir" -> {"tercih_tipi": "favori_renk", "deger": "mavi"} extracted_info = llm_extract_preferences(text) if extracted_info: memory_db.add_memory(user_id, "user_preference", extracted_info) print(f"Belleğe eklendi: {extracted_info}") else: print("Bilgi çıkarılamadı.")Yukarıdaki kod örneği, bir metinden önemli bir tercihin nasıl çıkarılıp belleğe kaydedilebileceğini göstermektedir. Burada
llm_extract_preferencesfonksiyonunun, LLM API'sine bir çağrı yaparak metni analiz edip yapılandırılmış bir bilgi döndürdüğü varsayılır. - Dışarıdan Bilgi Yükleme: Ajanın belleği, önceden hazırlanmış veri setleri (örneğin, bir şirket politikaları dokümanı, ürün kataloğu veya bir Wikipedia özeti) ile beslenebilir. Bu bilgiler genellikle ilk kurulumda veya periyodik güncellemelerle yüklenir. Bu veriler de yapılandırılmış (JSON, CSV) veya ham metin olarak depolanabilir.
- Değişiklik İzleme ve Tutarlılık: Bir bilgi güncellendiğinde, bellekteki ilgili tüm kayıtların da güncellendiğinden emin olmak önemlidir. Örneğin, bir kullanıcının telefon numarası değiştiğinde, ajan bu bilgiyi eski numarayı silip yenisiyle değiştirmelidir. Bu, zaman damgaları (timestamp) ve versiyonlama gibi mekanizmalarla yönetilebilir. Bilginin ne zaman eklendiğini veya son güncellendiğini bilmek, ajanın zamanla eskiyen bilgileri fark etmesine ve onları daha güncel olanlarla değiştirmesine yardımcı olabilir.
Bağlamsal Geri Çağırma (Retrieval) Teknikleri
Depolanan bilginin gerçek değeri, ihtiyaç duyulduğunda doğru ve ilgili parçaların geri çağrılabilmesidir. Vektör DB'siz bir ortamda, anlamsal aramayı taklit etmek için farklı stratejiler izleyebiliriz:
- Anahtar Kelime Tabanlı Arama (Full-Text Search): Bu, en temel geri çağırma yöntemidir. Kullanıcının sorgusundaki anahtar kelimeleri veya LLM tarafından türetilen anahtar kelimeleri kullanarak bellekteki metin alanlarında arama yapılır. SQLite'ın FTS5 (Full-Text Search 5) uzantısı veya Redis Search modülü gibi araçlar, bu tür aramaları oldukça hızlı ve etkili bir şekilde gerçekleştirebilir.
import sqlite3 def retrieve_with_keywords(query_keywords, db_path="memory.db"): conn = sqlite3.connect(db_path) cursor = conn.cursor() # Örnek: 'memory_table' adında bir tablonuz ve 'content' adında bir sütununuz var. # FTS5 için tabloyu ayrı bir şekilde oluşturmak gerekir. # Diyelim ki 'memory_fts' adında FTS5 özellikli bir tablonuz var. query_str = " OR ".join([f"content MATCH '{kw}*'" for kw in query_keywords]) cursor.execute(f"SELECT id, content FROM memory_fts WHERE {query_str} LIMIT 5") results = cursor.fetchall() conn.close() return resultsYukarıdaki Python kodu, SQLite FTS5 kullanarak anahtar kelime tabanlı bir arama yapmayı göstermektedir. Arama sorgusu, birden fazla anahtar kelimeyi 'OR' ile birleştirerek daha geniş bir eşleşme yelpazesi sunar.
- Pattern Matching (Regex): Özellikle yapılandırılmış verilerde veya belirli desenleri içeren metinlerde, düzenli ifadeler (regular expressions) kullanarak belirli kalıplara uyan bilgileri bulmak mümkündür. Örneğin, belirli bir proje kodunu veya tarih formatını aramak için kullanılabilir.
- LLM Kullanarak Özetleme ve Çıkarma: Bu, belki de en güçlü ve vektör DB'siz en "anlamsal" yaklaşımlardan biridir. Bellekteki tüm bilgiler (veya belirli filtrelerle daraltılmış bir alt küme), LLM'nin bağlam penceresine sığacak şekilde özetlenebilir veya belirli bir soruyu yanıtlamak için doğrudan LLM'ye sunulabilir. LLM, bu büyük metin bloklarından en alakalı bilgileri "okuyup" çıkarabilir ve özetleyebilir.
def retrieve_with_llm_summarization(query, all_memories, llm_api_call): # Tüm bellek parçalarını (veya filtrelenmiş bir alt kümesini) bir stringde birleştirin context_string = "\n".join([mem["content"] for mem in all_memories]) # LLM'e belleği ve sorguyu vererek ilgili bilgiyi çıkarmasını isteyin prompt = f"Aşağıdaki bellek parçalarından '{query}' sorusuna cevap verin ve özeti çıkarın:\n\n{context_string}\n\nCevap:" response = llm_api_call(prompt) # LLM API'sine çağrı return responseBu yöntem, LLM'nin anlama yeteneğini kullanarak, anahtar kelime aramalarının kaçırabileceği daha derin anlamsal ilişkileri ortaya çıkarabilir. Elbette, bu yaklaşım LLM çağrı maliyetlerini ve gecikmesini artırabilir, bu yüzden dikkatli kullanılmalıdır (örneğin, ilk önce anahtar kelime araması yapıp ardından sadece çıkan sonuçları LLM'ye vermek gibi karma bir strateji izlenebilir).
Bu stratejilerin kombinasyonu, AI ajanınızın bağlamı daha iyi anlamasını, geçmiş deneyimlerinden ders çıkarmasını ve böylece daha akıllı, kişiselleştirilmiş ve kullanışlı yanıtlar üretmesini sağlayacaktır. Vektör DB'lere alternatif olarak, bu yöntemler genellikle daha hızlı kurulum, daha düşük maliyet ve daha doğrudan kontrol sunar. Önemli olan, projenizin ihtiyaçlarına en uygun depolama ve geri çağırma mekanizmalarını seçmek ve bunları ajanın genel mimarisine entegre etmektir.
Uygulamalı Kısım: Basit Bir Bellek Sistemi Kurulumu
Şimdi pratik bir örnek üzerinden, AI ajanı için vektör veritabanı kullanmadan nasıl basit bir uzun süreli bellek sistemi kurabileceğimizi görelim. Senaryomuz, bir "Proje Yönetim Asistanı" botu geliştirmek olsun. Bu asistanın, farklı projelerle ilgili görevleri, toplantı notlarını ve önemli kararları hatırlaması gerekecek.
Adım 1: Bellek Yapısı Tanımlama (SQLite ve JSON)
Bu örnekte, bilgiyi hem yapılandırılmış hem de esnek bir şekilde saklamak için SQLite veritabanını kullanacağız. Her bellek parçacığı için bir JSON belgesi kullanacağız, ancak bu JSON'ları SQLite tablosundaki bir metin sütununda saklayacağız. Böylece, hem SQL'in sorgulama gücünden faydalanabilir hem de JSON'un esnekliğinden ödün vermemiş oluruz.
Veritabanı tablomuz agent_memory adını taşıyacak ve şu sütunlara sahip olacak:
id(INTEGER PRIMARY KEY AUTOINCREMENT): Bellek girdisinin benzersiz kimliği.timestamp(TEXT): Girdinin oluşturulduğu zaman damgası.type(TEXT): Bellek girdisinin türü (örn: 'task', 'meeting_note', 'decision', 'user_preference').project_id(TEXT): Hangi projeyle ilgili olduğunu belirten ID.content(TEXT): Asıl bellek içeriğini barındıran JSON string'i.
Örnek bir content JSON yapısı şöyle olabilir:
{
"title": "Yeni Özellik Geliştirme Toplantısı",
"description": "API entegrasyonu için gereksinimler belirlendi.",
"participants": ["Alice", "Bob"],
"action_items": [
{"task": "Dokümantasyon hazırla", "assignee": "Alice"},
{"task": "Endpointleri test et", "assignee": "Bob"}
],
"keywords": ["API", "entegrasyon", "gereksinimler"]
}
Şimdi veritabanını ve tabloyu oluşturalım:
import sqlite3
import json
import datetime
def setup_database(db_path="agent_memory.db"):
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS agent_memory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
type TEXT,
project_id TEXT,
content TEXT
)
""")
conn.commit()
conn.close()
print(f"Veritabanı ve 'agent_memory' tablosu oluşturuldu veya zaten var: {db_path}")
# Veritabanını kurmak için çağırın
setup_database()
Bu kodu çalıştırdığınızda, belirttiğiniz yolda (varsayılan olarak agent_memory.db) bir SQLite veritabanı dosyası oluşturulacak ve içinde agent_memory tablosu hazır olacaktır.
Adım 2: Belleğe Yazma Fonksiyonu
Ajanın yeni bilgileri belleğine eklemesini sağlayacak bir fonksiyon yazalım. Bu fonksiyon, JSON içeriğini string'e dönüştürerek veritabanına kaydedecek.
def add_memory(db_path, memory_type, project_id, content_dict):
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
timestamp = datetime.datetime.now().isoformat()
content_json = json.dumps(content_dict, ensure_ascii=False) # Türkçe karakterler için ensure_ascii=False
cursor.execute("""
INSERT INTO agent_memory (timestamp, type, project_id, content)
VALUES (?, ?, ?, ?)
""", (timestamp, memory_type, project_id, content_json))
conn.commit()
conn.close()
print(f"Belleğe eklendi: Tip='{memory_type}', Proje='{project_id}'")
# Örnek bellek eklemeleri:
add_memory("agent_memory.db", "meeting_note", "project_alpha", {
"title": "Haftalık Senkronizasyon",
"description": "Ekip, projenin mevcut durumu hakkında bilgi aldı. Yeni görevler atandı.",
"participants": ["Ayşe", "Mehmet"],
"action_items": [
{"task": "Raporu bitir", "assignee": "Ayşe"},
{"task": "Test senaryolarını yaz", "assignee": "Mehmet"}
],
"keywords": ["senkronizasyon", "haftalık", "rapor", "test"]
})
add_memory("agent_memory.db", "task", "project_alpha", {
"name": "Kullanıcı arayüzü tasarımı",
"status": "devam ediyor",
"priority": "yüksek",
"due_date": "2023-12-31",
"assigned_to": "Ayşe",
"description": "Yeni özellik için arayüz taslağını tamamla.",
"keywords": ["UI", "tasarım", "arayüz"]
})
add_memory("agent_memory.db", "decision", "project_beta", {
"context": "Veritabanı seçimi",
"decision_made": "NoSQL yerine ilişkisel veritabanı kullanma kararı alındı.",
"reason": "Veri tutarlılığı ve karmaşık sorgular için daha uygun.",
"keywords": ["veritabanı", "seçim", "NoSQL", "ilişkisel"]
})
Adım 3: Bellekten Okuma/Arama Fonksiyonu
Ajanın belleğinden bilgi çekmesini sağlayacak bir fonksiyon geliştirelim. Bu fonksiyon, belirli filtreler (tür, proje ID'si) ve anahtar kelimeler kullanarak belleği arayacak. SQLite'ın LIKE operatörü ile basit metin aramaları yapabilir veya daha gelişmiş aramalar için FTS5 kullanabiliriz (bu örnekte basit LIKE kullanacağız, ancak FTS5'in potansiyelini unutmayın).
def retrieve_memory(db_path, query="", memory_type=None, project_id=None, limit=5):
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
sql_query = "SELECT timestamp, type, project_id, content FROM agent_memory WHERE 1=1"
params = []
if memory_type:
sql_query += " AND type = ?"
params.append(memory_type)
if project_id:
sql_query += " AND project_id = ?"
params.append(project_id)
if query:
# JSON içeriğinde anahtar kelime arama. Bu, tüm JSON string'ini arar.
# Daha spesifik aramalar için JSON_EXTRACT veya FTS5 gereklidir.
sql_query += " AND content LIKE ?"
params.append(f"%{query}%")
sql_query += " ORDER BY timestamp DESC LIMIT ?"
params.append(limit)
cursor.execute(sql_query, tuple(params))
results = cursor.fetchall()
conn.close()
parsed_results = []
for row in results:
timestamp, m_type, p_id, content_json = row
parsed_content = json.loads(content_json)
parsed_results.append({
"timestamp": timestamp,
"type": m_type,
"project_id": p_id,
"content": parsed_content
})
return parsed_results
# Örnek bellek aramaları:
print("\n--- 'project_alpha' projesindeki görevler ---")
tasks = retrieve_memory("agent_memory.db", memory_type="task", project_id="project_alpha")
for task in tasks:
print(f"- [{task['timestamp']}] Görev: {task['content']['name']} (Durum: {task['content']['status']})")
print("\n--- 'API' anahtar kelimesini içeren bellekler ---")
api_memories = retrieve_memory("agent_memory.db", query="API")
for mem in api_memories:
print(f"- [{mem['timestamp']}] Tip: {mem['type']}, Proje: {mem['project_id']}, Başlık: {mem['content'].get('title', 'N/A')}")
print("\n--- Mehmet ile ilgili tüm bellekler (JSON içeriğinde ara) ---")
mehmet_memories = retrieve_memory("agent_memory.db", query="Mehmet")
for mem in mehmet_memories:
print(f"- [{mem['timestamp']}] Tip: {mem['type']}, Proje: {mem['project_id']}, İçerik Özeti: {mem['content'].get('description', mem['content'].get('name', 'N/A'))}")
Bu kod parçacıkları, basit bir proje yönetim asistanının nasıl bellek ekleyip arayabileceğini gösteriyor. Ajanınız, gelen sorguları analiz ederek (yine bir LLM yardımıyla) hangi memory_type, project_id veya query anahtar kelimelerinin kullanılacağına karar verebilir ve bu fonksiyonları çağırarak ilgili bilgileri alabilir. Daha sonra bu alınan bilgiyi LLM'nin bağlam penceresine ekleyerek daha akıllı ve bilgili yanıtlar üretebilir.
Uzman İpucu: SQLite'ın dahili JSON fonksiyonları (
JSON_EXTRACT,JSON_EACHvb.) ve FTS5 uzantısı ilecontentsütunu içindeki JSON verileri üzerinde çok daha gelişmiş ve hızlı aramalar yapabilirsiniz. Örneğin,SELECT * FROM agent_memory WHERE JSON_EXTRACT(content, '$.status') = 'devam ediyor'gibi sorgularla JSON alanlarına doğrudan filtre uygulayabilirsiniz.
Bu temel yapı, AI ajanınız için oldukça işlevsel bir uzun süreli bellek çözümü sunar. Geliştireceğiniz ajanın türüne ve ihtiyaçlarına göre bu yapıyı daha da genişletebilir ve optimize edebilirsiniz. Örneğin, Redis gibi bir aracı, sık erişilen son 100 bellek parçasını önbelleğe almak için kullanırken, tüm kalıcı verileri SQLite'ta tutabilirsiniz. Bu katmanlı yaklaşım, hem performansı artırır hem de bellek yönetimini daha verimli hale getirir.
Performans ve Ölçeklenebilirlik İpuçları: Belleğinizi Nasıl Optimize Edersiniz?
AI ajanınızın uzun süreli bellek sistemi büyüdükçe, performans ve ölçeklenebilirlik önemli hale gelir. Vektör veritabanı kullanmadan da bellek sisteminizi optimize etmek için uygulayabileceğiniz bazı stratejiler mevcuttur.
Bilgi İndeksleme
Bellek veritabanınızdaki (örneğin SQLite) ilgili sütunlara indeksler eklemek, arama sorgularının hızını önemli ölçüde artırır. Özellikle type, project_id gibi sıkça filtrelenen sütunlara indeks eklemek faydalıdır. Eğer metin tabanlı arama yapıyorsanız, tam metin indeksleme (Full-Text Search) çözümlerini düşünmelisiniz.
- SQLite FTS5: SQLite için FTS5, metin tabanlı aramalarda olağanüstü performans sağlar. Bellek içeriklerinizi ayrı bir FTS5 tablosunda depolayarak veya mevcut tablonuza bağlayarak metin aramalarını hızlandırabilirsiniz. Örneğin:
-- FTS5 tablosu oluşturma örneği CREATE VIRTUAL TABLE agent_memory_fts USING fts5( content, id UNINDEXED, type UNINDEXED, project_id UNINDEXED ); -- Ana agent_memory tablosundaki verileri FTS5 tablosuna kopyalama INSERT INTO agent_memory_fts(rowid, content, type, project_id) SELECT id, content, type, project_id FROM agent_memory; -- Arama örneği: SELECT T1.timestamp, T1.type, T1.project_id, T1.content FROM agent_memory AS T1 JOIN agent_memory_fts AS T2 ON T1.id = T2.rowid WHERE T2.content MATCH 'API*' ORDER BY T1.timestamp DESC LIMIT 5;Bu, doğrudan
LIKE '%query%'kullanmaktan çok daha hızlı ve esnek bir arama sağlar. - Redis Search: Eğer Redis kullanıyorsanız, Redis Search modülü gelişmiş indeksleme ve sorgulama yetenekleri sunar. Anahtar-değer çiftlerinizin üzerinde tam metin aramaları, alan bazlı aramalar ve coğrafi aramalar yapabilirsiniz.
Bellek Temizleme ve Sıkıştırma
Bellek sistemi zamanla çok fazla gereksiz veya eski bilgi biriktirebilir. Bu durum, arama sürelerini uzatabilir ve depolama maliyetlerini artırabilir. Düzenli olarak bellek temizliği ve sıkıştırma işlemleri yapmak önemlidir:
- Eskimiş Bilgileri Arşivleme/Silme: Belirli bir yaştan (örn: 1 yıl) sonra kritik olmayan bilgileri otomatik olarak arşivleyebilir veya silebilirsiniz.
- Özetleme: Çok detaylı bellek parçalarını daha kısa özetlere dönüştürerek depolama boyutunu küçültebilirsiniz. Bu, özellikle LLM'nin özetleme yetenekleriyle birleştirildiğinde güçlü bir stratejidir.
- Tekilleştirme: Aynı bilginin birden fazla kopyası varsa, bunları birleştirmek veya referanslamak depolama alanından tasarruf sağlar.
Katmanlı Bellek Mimarisi
Performans ve maliyet arasında denge kurmak için katmanlı bir bellek mimarisi kullanabilirsiniz. Bu, "sıcak" veriyi (sık erişilen) "soğuk" veriden (nadir erişilen) ayırma prensibine dayanır:
- Hızlı Erişim Katmanı (Önbellek): Sıkça ihtiyaç duyulan veya son kullanılan bilgileri Redis gibi bellek içi bir önbellekte tutun. Bu, ajanın yanıt sürelerini dramatik şekilde kısaltır.
import redis # Redis bağlantısı r = redis.Redis(host='localhost', port=6379, db=0) def add_to_cache(key, value, expiry_seconds=3600): r.setex(key, expiry_seconds, json.dumps(value)) def get_from_cache(key): cached_data = r.get(key) return json.loads(cached_data) if cached_data else None # Örnek kullanım: Sıkça sorulan bir sorunun cevabını önbelleğe al # cached_answer = {"soru": "AI nedir?", "cevap": "Yapay zeka..."} # add_to_cache("faq:ai_nedir", cached_answer) - Kalıcı Depolama Katmanı: Tüm kalıcı ve kapsamlı bilgileri SQLite veya daha büyük ölçekli projeler için PostgreSQL/MySQL gibi geleneksel bir ilişkisel veritabanında saklayın. Ajan önce önbelleğe bakar, bilgi orada yoksa kalıcı depolama katmanına sorgu gönderir.
Uzman İpucu: Belleğinizi düzenli olarak analiz ederek en çok kullanılan ve en kritik bilgileri belirleyin. Bu "sıcak" bilgileri hızlı erişim katmanına (örneğin Redis önbellek) taşıyarak genel performansı %40'a kadar artırabilirsiniz. Ayrıca, az kullanılan "soğuk" verileri daha uygun maliyetli, yavaş depolama çözümlerine (örneğin dosya sistemindeki sıkıştırılmış JSON'lar) taşıyın.
Bellek Parçalama (Sharding) veya Dağıtık Sistemler
Eğer ajanın bellek yükü tek bir veritabanının veya sunucunun taşıyamayacağı kadar büyürse, veriyi birden fazla sunucuya veya veritabanına dağıtmak (sharding) gerekebilir. Bu, daha karmaşık bir kurulum gerektirse de, sistemin yatay ölçeklenmesine olanak tanır. Örneğin, farklı projelerin belleklerini ayrı SQLite dosyalarında tutmak ve ilgili projeye özel veritabanını yüklemek basit bir parçalama örneği olabilir.
Bu ipuçlarını uygulayarak, vektör veritabanı kullanmadan bile AI ajanınız için sağlam, performanslı ve ölçeklenebilir bir uzun süreli bellek sistemi oluşturabilirsiniz. Anahtar, projenizin mevcut ve gelecekteki ihtiyaçlarını doğru bir şekilde değerlendirmek ve buna uygun bir mimari seçmektir.
Geleceğe Yönelik Bakış: Daha Akıllı Bellek Sistemleri
AI ajanları için uzun süreli bellek sistemlerini geliştirmek, sadece bilginin depolanmasından ibaret değildir; aynı zamanda bu bilginin nasıl organize edildiği, ilişkilendirildiği ve zamanla nasıl evrildiği ile de ilgilidir. Vektör veritabanı kullanmasak bile, ajanın bellek yeteneklerini artırmak için ileri düzey yaklaşımlar mevcuttur.
Hiyerarşik Bellek Modelleri: Genelden Özele Bilgi Saklama
İnsan beyni, bilgiyi düz bir liste halinde saklamaz; bunun yerine, kavramları ve anıları hiyerarşik bir yapıda düzenler. Benzer bir yaklaşım AI ajanları için de uygulanabilir. Bu, bilginin farklı soyutlama seviyelerinde saklanması anlamına gelir:
- Genel Bellek (Global Context): Tüm projeler veya kullanıcılar için geçerli olan yüksek seviyeli bilgiler (şirket politikaları, genel ürün bilgisi, ajanın kişiliği ve hedefleri). Bu bilgiler, genellikle daha statiktir ve tüm etkileşimler için temel bir bağlam sağlar.
- Proje/Kullanıcı Bazlı Bellek (Specific Context): Belirli bir proje veya kullanıcıya ait detaylı bilgiler (proje hedefleri, kullanıcı tercihleri, geçmiş etkileşimler). Bu katman, daha dinamiktir ve kişiselleştirilmiş etkileşimler için kritik öneme sahiptir.
- Diyalog Bazlı Bellek (Episodic Context): Mevcut konuşmanın veya görevin en kısa süreli ve en spesifik detayları. Bu bilgiler, genellikle konuşma bittikten sonra özetlenerek veya çıkarılarak daha yüksek katmanlara eklenir veya kısa bir süre sonra silinir.
Bu hiyerarşik yapı, ajanın bir sorgu geldiğinde önce en genelden başlayarak en spesifik bilgiye doğru arama yapmasını sağlayarak, daha verimli ve alakalı bilgi geri çağırımına olanak tanır. Örneğin, bir "proje_alpha" hakkında soru sorulduğunda, ajan önce global politika bilgilerine bakar, ardından "proje_alpha"ya özgü bellekleri tarar ve son olarak mevcut diyalogdaki detayları değerlendirir.
Öğrenme ve Unutma Mekanizmaları: Bilginin Önemine Göre Ağırlıklandırma
Her bilginin değeri aynı değildir. Bazı bilgiler çok önemlidir ve asla unutulmamalıdır, bazıları ise geçicidir ve zamanla önemini yitirir. Ajanların belleğini daha akıllı hale getirmek için, bilginin önemine (sıklık, yakınlık, duygusal değer gibi faktörlere göre) ağırlık veren ve bu ağırlığa göre bilgiyi hatırlama veya unutma kararı veren mekanizmalar geliştirilebilir:
- Sıklık ve Yakınlık: Bir bilginin ne sıklıkta kullanıldığı veya en son ne zaman kullanıldığı, o bilginin önemini gösteren güçlü bir göstergedir. Sık kullanılan veya yakın zamanda erişilen bilgiler daha yüksek bir "canlılık" puanına sahip olabilir ve bu puan, geri çağırma sırasında önceliklendirme için kullanılabilir.
- Önem Puanlaması: Her bellek girdisine, LLM tarafından veya manuel olarak bir "önem" veya "kritiklik" puanı atanabilir. Bu puan, bilginin ajanın genel hedefleri veya kullanıcının istekleri açısından ne kadar değerli olduğunu gösterir. Örneğin, bir güvenlik protokolü bilgisi, bir kullanıcının favori renginden daha yüksek bir öneme sahip olabilir.
- Unutma (Forgetfulness): İnsan beyni, bilgileri unutarak aşırı yüklenmeyi önler. AI ajanları da benzer bir mekanizmaya sahip olabilir. Düşük öneme sahip ve uzun süredir kullanılmayan bilgiler, otomatik olarak arşivlenebilir, özetlenebilir veya silinebilir. Bu, belleğin daha küçük ve daha yönetilebilir kalmasını sağlar.
LLM'leri Kullanarak Daha Sofistike Çıkarımlar ve Çapraz Referanslama
Büyük dil modellerinin anlama ve üretme yetenekleri, basit depolama ve geri çağırmanın ötesine geçerek, bellek sistemini çok daha akıllı hale getirebilir:
- Bağlam Zenginleştirme: Ajan, bir sorguyu belleğe göndermeden önce, LLM'den sorguyu zenginleştirmesini isteyebilir. Örneğin, "Haftalık toplantının özeti nedir?" sorusu için, LLM, ilgili anahtar kelimeleri ("haftalık", "toplantı", "özet") ve olası proje ID'lerini (eğer konuşma içinde varsa) çıkararak daha iyi bir arama sorgusu oluşturabilir.
- Çapraz Referanslama: LLM, bellekteki farklı bilgi parçaları arasındaki ilişkileri belirleyebilir ve yeni çıkarımlar yapabilir. Örneğin, bir bellek parçasında "Ayşe test senaryolarını yazdı" bilgisi varken, başka birinde "Ayşe'nin uzmanlık alanı kalite güvencesidir" bilgisi varsa, LLM bu iki bilgiyi birleştirerek Ayşe'nin test senaryolarında iyi olduğunu çıkarabilir.
- Dinamik Bilgi Grafiği Oluşturma: Depolanan yapılandırılmış verilerden (JSON, üçlüler) dinamik olarak bir bilgi grafiği oluşturmak ve bu grafiği LLM'ye bir referans olarak sunmak, ajanın karmaşık ilişkileri anlamasına yardımcı olabilir. LLM, bu grafiği kullanarak sorgulara daha bağlamsal ve ilişkisel yanıtlar verebilir.
Bu ileri düzey yaklaşımlar, AI ajanlarının sadece bilgi depolayan ve geri çağıran sistemler olmaktan çıkıp, bilgiyi aktif olarak işleyen, ilişkileri anlayan ve zamanla öğrenerek daha akıllı hale gelen varlıklar olmalarını sağlayabilir. Vektör veritabanları olmadan da, doğru stratejilerle ve LLM'nin gücünü kullanarak, karmaşık ve etkileyici bellek sistemleri inşa etmek mümkündür.
Sonuç: Vektör DB'siz Uzun Süreli Hafıza Mümkün Mü?
Bu makalede gördüğümüz gibi, AI ajanlarına uzun süreli bellek kazandırmak için karmaşık ve pahalı vektör veritabanlarına başvurmak her zaman şart değil. Küçük ve orta ölçekli projeler, kişisel asistanlar veya özel görev botları için JSON dosyaları, SQLite veya Redis gibi daha geleneksel ve yönetilebilir depolama çözümleri, şaşırtıcı derecede etkili ve yeterli olabilir. Anahtar, bilgiyi akıllıca yapılandırmak, ilgili veriyi etkili bir şekilde indekslemek ve LLM'nin doğal dil anlama yeteneklerini kullanarak bellekten en alakalı parçaları geri çağırmaktır.
Bu yaklaşımların temel avantajları, düşük maliyet, kolay kurulum ve yönetim, ve projeye özgü ihtiyaçlara göre yüksek esneklik sunmalarıdır. Geliştiriciler, daha az altyapı karmaşıklığıyla uğraşarak, ajanın asıl işlevselliğine ve kullanıcı deneyimine odaklanabilirler. Elbette, bu yöntemler vektör veritabanlarının sunduğu saf anlamsal benzerlik arama gücünü birebir taklit edemez. Ancak, anahtar kelime tabanlı arama, yapısal filtreleme ve LLM'nin bağlamsal anlama yetenekleriyle bu açığı büyük ölçüde kapatmak mümkündür.
Özetle, evet, vektör DB'siz uzun süreli hafıza kesinlikle mümkündür. Doğru araçları, stratejileri ve biraz yaratıcılığı bir araya getirerek, AI ajanlarınıza unutkanlık sorununu aşacak ve onları çok daha yetenekli, bağlamsal ve kullanıcı dostu hale getirecek sağlam bir bellek sistemi kazandırabilirsiniz.
Sıkça Sorulan Sorular (SSS)
1. Bu yöntem vektör DB'lerin yerini tamamen alabilir mi?
Bu yöntemler, özellikle daha küçük ve orta ölçekli projelerde veya bütçe kısıtlamaları olan durumlarda vektör DB'lere güçlü bir alternatif sunar. Ancak, çok büyük ve karmaşık veri setlerinde, saf anlamsal benzerlik aramasının kritik olduğu senaryolarda veya çok yüksek eşzamanlı sorgu yüklerinde vektör DB'ler hala daha üstün performans gösterebilir. Bu yöntemler, vektör DB'lerin "yerine tamamen geçmek"ten ziyade, onlara güçlü ve erişilebilir bir alternatif sunar.
2. Büyük ölçekli uygulamalar için uygun mu?
Doğrudan JSON dosyalarıyla çalışmak büyük ölçekli uygulamalar için performans sorunları yaratabilir. Ancak SQLite, FTS5 gibi eklentilerle birlikte orta ölçekli uygulamalar için oldukça yeterli olabilir. Redis, bellek içi depolama ve dağıtık mimarilerle birleştirildiğinde büyük ölçekli uygulamaların hızlı erişim katmanları için kullanılabilir. PostgreSQL veya MySQL gibi geleneksel veritabanları da daha karmaşık ve büyük ölçekli yapılandırılmış bellek sistemleri için güçlü seçeneklerdir.
3. Bellek sistemi ne kadar karmaşık olabilir?
Bellek sisteminin karmaşıklığı tamamen projenizin ihtiyaçlarına bağlıdır. Basit bir anahtar-değer depolamasından, hiyerarşik yapılandırılmış, öğrenme ve unutma mekanizmaları içeren katmanlı bir sisteme kadar değişebilir. Temel bir sistemle başlayıp, ihtiyaçlar doğrultusunda zamanla karmaşıklığı artırmak genellikle en iyi yaklaşımdır.
4. Bu yaklaşımın temel dezavantajı nedir?
Temel dezavantaj, anlamsal benzerlik aramasının (semantik search) doğuştan gelen gücünün olmamasıdır. Vektör DB'ler, iki metin parçasının içerdiği kelimeler tamamen farklı olsa bile, anlamsal olarak benzer olduklarını anlayabilir. Anahtar kelime tabanlı veya yapısal aramalarda bu yetenek sınırlıdır ve daha çok doğrudan eşleşmelere veya önceden tanımlanmış ilişkilere dayanır. Bu açığı kapatmak için LLM'nin kendisini bir "anlamsal filtre" olarak kullanmak ek maliyet ve gecikme yaratabilir.
5. Hangi programlama dilleriyle uygulanabilir?
Bu makaledeki örnekler Python ile verilmiş olsa da, bu yaklaşımlar hemen hemen tüm modern programlama dilleriyle uygulanabilir. SQLite, Redis ve JSON gibi teknolojiler çoğu dilde güçlü kütüphane ve SDK desteğine sahiptir. Örneğin, Node.js, Java, C#, Go gibi dillerde de benzer uygulamaları kolayca geliştirebilirsiniz.
