python / sqlite / local-first
SQLite, FTS5 ve Python Standart Kütüphanesiyle Kalıcı Agent Belleği Kurmak
Konuşma geçmişi bellekle aynı şey değil. İşe yarayan bir agent küçük bir bilgiyi tutabilmeli, onu sonra bulabilmeli ve her prompt’a tüm transkripti yüklemeden oturumlar arasında taşıyabilmeli.
hermes-fact-store, bu soruna verdiğim küçük cevap: tek bir Python programı, tek bir SQLite veritabanı ve çekirdek uygulamada hiçbir üçüncü taraf paketi yok.
Tek bir SQLite dosyasının neden yettiği
Veri yerel, yapılandırılmış ve o kadar mütevazı ki bir servis, getireceği operasyonel yükle sağlayacağı değerden daha pahalıya patlar. SQLite zaten transaction’lar, indeksler, taşınabilir yedekler ve tam metin arama (full-text search) sunuyor. Üstelik hepsi, agent’ın diğer verileriyle birlikte taşıyabildiğiniz tek bir dosyanın içinde duruyor.
Ana facts tablosu, metnin yanında pratik metadata da tutuyor:
- kategori ve etiketler;
- kaynak oturum;
- önem derecesi;
- oluşturulma ve erişim zaman damgaları.
Bu kadarı hem doğrudan aramalara hem de operasyonel sorulara yetiyor: hangi kategoriler var, en son neler eklendi gibi.
İkinci bir sisteme gerek kalmadan tam metin arama
Bir FTS5 sanal tablosu bilgi metnini, etiketleri ve kategoriyi indeksliyor. SQLite trigger’ları bu indeksi ekleme, güncelleme ve silme işlemlerinden sonra senkron tutuyor. Böylece CLI ayrı bir indeksleme akışına ihtiyaç duymuyor.
Arama girdisi FTS5’e ulaşmadan önce temizleniyor. Sorgu dilinde anlam
taşıyan karakterler, sıradan kullanıcı metnini bozuk bir ifadeye
çevirmemeli. Bir FTS sorgusu yine de başarısız olursa uygulama bir
LIKE aramasına geri düşüyor. Bu yedek yöntem daha az yetenekli ama en
azından işe yarayan bir sonuç veriyor; bir bellek sorgusunu
exception’a çevirmekten çok daha iyisi.
Bu bir anahtar kelime araması, vektör veya semantik arama değil. Bu kısıtlama deposunu anlaşılır ve bağımlılıksız tutuyor, ancak başka bir yaklaşımın ne zaman değerli olmaya başlayacağını da tanımlıyor.
Kasıtlı olarak sıradan bir CLI
Komut satırı, deponun gerçekten ihtiyaç duyduğu işlemleri destekliyor:
add · search · recent · delete · stats · export · import
JSON export ve import, dahili SQLite şemasına bağlı olmayan bir yedekleme biçimi sağlıyor: veritabanı çalışan temsil olarak kalıyor, JSON ise taşınabilir olan.
Burada bir sunucu süreci, hesap sistemi veya senkronizasyon katmanı yok. Bu özellikler ancak bellek birden fazla makineye veya kullanıcıya hizmet etmek zorunda kalırsa gerekçelendirilebilir.
Bilgileri toplu hâlde çıkarın
İsteğe bağlı bir çıkarım script’i, Hermes’in kendi state.db’sinden
son oturumları okuyor, bir grubu OpenAI uyumlu bir endpoint’e
gönderiyor ve çıkarılan bilgileri depoya yazıyor. Endpoint, barındırılan
bir sağlayıcı da olabilir, yerel bir model de.
Toplu işlem burada önemli: çıkarımın her mesajı kesmesi gerekmiyor ve işlemi sonradan çalıştırmak maliyeti ve veri sınırını görünür kılıyor. Zamanlanmış bir görev bu süreci otomatikleştirebilir, ancak deponun kendisi bu zamanlamaya bağımlı değil.
“Hiç bağımlılık yok” ifadesinin biraz açıklık istediği yer de tam olarak LLM çıkarımı. Script’ler Python’un standart kütüphanesini kullanıyor, ancak otomatik çıkarım yine de bir LLM endpoint’i gerektiriyor. Barındırılan bir endpoint paraya mal olabilir ve çıkarılan bilgiler yanlış ya da tekrarlı çıkabilir. Veritabanı kalıcılık sağlıyor, doğruluk değil.
İşe yarayan tavan
Tek bir yerel agent için SQLite artı FTS5 şaşırtıcı derecede çok şeyi kapsıyor:
- kalıcı depolama;
- hızlı anahtar kelime araması;
- transaction’lı güncellemeler;
- incelenebilir veri;
- basit yedekleme ve geri yükleme.
Embedding’i ancak gerçek aramalar kelime farklılıkları yüzünden başarısız olmaya başladığında eklerim. Bir servisi ise ancak birden fazla süreç veya makine gerçekten koordineli erişime ihtiyaç duyduğunda eklerim. O zamana kadar tek dosya bir prototip kısıtlaması değil, en küçük eksiksiz sistem :)
Çekirdek kod
fact_store.py
içinde, toplu çıkarım ise
extract_facts.py
içinde bulunuyor.

