Ayarlar

Dil

Yapay Zeka Ajanınız Neden Sürekli Hafızasını Kaybediyor

L
LemonData
·5 Mart 2026·752 görüntüleme
Yapay Zeka Ajanınız Neden Sürekli Hafızasını Kaybediyor

Yapay zeka ajanınız bir kullanıcıyla 30 dakikalık bir görüşme yaptı. Proje gereksinimlerini tartıştılar, tercihleri paylaştılar, kararlar aldılar. Sonra kullanıcı yeni bir oturum başlatmak için /new yazıyor.

Ajan, bu konuşmayı uzun süreli hafızaya aktarmaya çalışır. LLM çağrısı başarısız olur. Rate limit. Timeout. Veya model, gerekli tool'u çağırmak yerine metin döndürür.

Hafıza gitti. Otuz dakikalık bağlam (context) buharlaştı.

Bu, sandığınızdan daha sık olur. LemonClaw örneklerimizde bunu takip ettik: Hafıza birleştirme (memory consolidation), herhangi bir tekil modelde yaklaşık %15 başarısızlık oranına sahipti. Görünmez bir altyapı olması gereken bir özellik için bu kabul edilemez.

Sadece hafıza alt sistemini değil, çevreleyen ürün yüzeyini de oluşturuyorsanız, bu sayfayı tek anahtarlı chatbot rehberi ve self-hosted LemonClaw rehberi ile birlikte değerlendirin. Hafıza dayanıklılığı, ancak ajan gerçekten kullanılabilir bir uygulama içinde yaşadığında önem kazanır.

Diğer Framework'ler Bunu Nasıl Ele Alıyor (Almıyorlar)

Çoğu yapay zeka ajan framework'ü, hafıza birleştirmeyi basit bir LLM çağrısı olarak görür. Çalışırsa ne ala. Çalışmazsa hafıza kaybolur.

LemonClaw'un selefi olan framework, birleştirme için konuşma ile aynı modeli kullanır. Kullanıcının asla görmeyeceği bir sohbeti özetlemek için 0,003 dolar maliyetli ve 8 saniyeden fazla süren bir Claude Sonnet çağrısı. Bu çağrı başarısız olduğunda (rate limit, timeout, model hatası), framework bir uyarı günlüğü (log) tutar ve devam eder. Kullanıcının bağlamı (context) yok olmuştur.

nanobot, bir başka popüler framework, aynı mimariye sahip. Tek model, tek deneme, fallback yok. Birleştirme fonksiyonunun bir timeout süresi bile yok. Yavaş bir upstream (Cloudflare 524 hataları yaygındır), bağlantı kopana kadar tüm oturumu bloke eder.

Hiçbir framework birleştirmeyi ana modelden ayırmaz. Hiçbirinin hafıza işlemleri için fallback mantığı yoktur. Hiçbiri "API çağrısı başarısız oldu" ile "API çağrısı başarılı oldu ama model istediğimizi yapmadı" arasındaki farkı ayırt etmez.

Bunlar uç durumlar (edge cases) değil. Herhangi bir tekil modelde %15 başarısızlık oranıyla, günde 100 birleştirme yapan bir framework bunların 15'inde hafızayı kaybeder. Bir hafta içinde bu, ajanın her şeyi unuttuğu 105 konuşma demektir.

Sorun Retry Mantığından Daha Derin

Bariz çözüm, exponential backoff ile retry yapmaktır. Bizde bu vardı. Geçici HTTP hatalarını gayet iyi halleder:

# Retry loop: 1s → 2s → 4s backoff
for attempt in range(3):
    try:
        response = await acompletion(**kwargs)
        return await self._collect_stream(response)
    except (RateLimitError, APIConnectionError) as e:
        await asyncio.sleep(RETRY_DELAYS[attempt])

Bu catches 429'ları ve ağ aksaklıklarını yakalar. Ancak iki hata modu aradan sızar:

Hata modu 1: Model tool calling yapamıyor. Bazı modeller, özellikle hızlı inference motorlarında çalışan daha küçük olanlar, karmaşık prompt'larda bazen geçerli fonksiyon çağrıları oluşturamaz. API, içinde bir MidStreamFallbackError barındıran ServiceUnavailableError ile 200 döndürür. Retry mantığınız bir istisna (exception) görür, aynı modeli tekrar dener, aynı hatayı alır.

Hata modu 2: Model "başarılı" olur ama tool'u çağırmaz. LLM tamamen geçerli bir yanıt döndürür. HTTP 200. Hata yok. Ancak yapılandırılmış verilerle save_memory çağırmak yerine, düz metin bir özet yazar. Retry motorunuz bunu bir başarı olarak kabul eder. Birleştirme fonksiyonu tool çağrılarını kontrol eder, hiçbir şey bulamaz ve pes eder.

İkinci hata modu sinsi olandır. Taşıma katmanı (transport layer) her şeyin çalıştığını düşünür. İş katmanı (business layer) çalışmadığını bilir. Tool şemanızı anlamayan bir modeli hiçbir HTTP düzeyindeki retry düzeltemez.

Çift Katmanlı Fallback Mimarisi

Bunu, farklı seviyelerde çalışan iki bağımsız fallback döngüsüyle çözdük:

Kullanıcı /new gönderir
    │
    ▼
consolidate() ─── İş Katmanı Fallback
    │               "Model save_memory çağırdı mı?"
    │               Hayır → zincirdeki bir sonraki modeli dene
    │
    ▼
_chat_with_retry() ─── Taşıma Katmanı Fallback
    │                    HTTP hataları → exponential backoff
    │                    Tüm retry hakları bitti → fallback zincirini tara
    │
    ▼
MODEL_MAP fallback zinciri:
    llama-3.3-70b  ─$0.59/M─→  qwen3-32b  ─$0.29/M─→  llama-4-scout  ─$0.11/M─→  gpt-4.1-mini  ─→  claude-haiku
    (394 TPS)                   (662 TPS)                (594 TPS)                  (güvenilir)        (son çare)

Katman 1 taşıma hatalarını yönetir. Katman 2 iş mantığı hatalarını yönetir. Fallback zinciri her iki katman arasında paylaşılır ve merkezi bir katalogda bir kez tanımlanır.

Bu, "aynı-modeli-tekrar-dene" yaklaşımından temelden farklıdır. Bir model bir tool'u çağıramadığında, onu aynı prompt ile tekrar denemek nadiren işe yarar. Farklı ağırlıklara ve farklı tool calling davranışlarına sahip farklı bir modele geçmek ise işe yarar.

Model Kataloğu: Tek Doğruluk Kaynağı

Kataloğumuzdaki her modelin, denenecek bir sonraki modeli işaret eden isteğe bağlı bir fallback alanı vardır:

@dataclass(frozen=True)
class ModelEntry:
    id: str
    label: str
    tier: str
    description: str
    fallback: str | None = None
    hidden: bool = False  # Kullanıcıya yönelik /model listesinde gizli

MODEL_CATALOG = [
    # Kullanıcı tarafından görülebilen modeller (kullanıcıların geçiş yapabileceği 16 model)
    ModelEntry("claude-sonnet-4-6", "Claude Sonnet 4.6", "standard",
               "Recommended", fallback="claude-sonnet-4-5"),
    ModelEntry("gpt-4.1-mini", "GPT-4.1 Mini", "economy",
               "Stable tool calling", fallback="claude-haiku-4-5"),

    # Gizli birleştirme modelleri (yalnızca dahili kullanım için)
    ModelEntry("llama-3.3-70b-versatile", "Llama 3.3 70B (Groq)", "economy",
               "394 TPS", fallback="qwen3-32b", hidden=True),
    ModelEntry("qwen3-32b", "Qwen3 32B (Groq)", "economy",
               "662 TPS", fallback="llama-4-scout-17b-16e-instruct", hidden=True),
    # ...
]

hidden=True bayrağı, dahili modelleri kullanıcıya yönelik /model komutunun dışında tutarken fallback zincirlerine dahil etmeye devam eder. Kullanıcılar geçiş yapabilecekleri 16 model görürler. Sistem ise 19 model kullanır. Üç gizli model, yalnızca hız ve maliyetin konuşma kalitesinden daha önemli olduğu hafıza birleştirme gibi arka plan görevleri için mevcuttur.

Bu katalog, tüm model yönlendirmeleri için tek doğruluk kaynağıdır (single source of truth). Fallback zincirine yeni bir model eklemek, tek bir satır eklemek demektir. Senkronize edilecek yapılandırma dosyaları, güncellenecek ortam değişkenleri veya değiştirilecek dağıtım script'leri yoktur.

Taşıma Katmanı: Döngü Algılamalı Zincirleme Fallback

Retry motoru, sonsuz döngüleri önlemek için bir visited seti kullanarak fallback zincirini tarar:

async def _chat_with_retry(self, kwargs, original_model):
    # Aşama 1: Birincil modelde exponential backoff
    for attempt in range(3):
        try:
            response = await acompletion(**kwargs)
            return await self._collect_stream(response)
        except (RateLimitError, APIConnectionError, APIError) as e:
            await asyncio.sleep(RETRY_DELAYS[attempt])
        except AuthenticationError:
            return LLMResponse(content="API key invalid.", finish_reason="error")

    # Aşama 2: Fallback zincirini tara
    visited = {original_model}
    current = original_model
    while True:
        entry = MODEL_MAP.get(current)
        if not entry or not entry.fallback or entry.fallback in visited:
            break
        current = entry.fallback
        visited.add(current)

        # Bu model için doğru gateway'i çöz
        gw = self._resolve_gateway_for_model(current)
        resolved = self._resolve_model(current, gateway=gw)
        fb_kwargs = {**kwargs, "model": resolved}

        # Hedef modelin protokolü için api_base'i düzelt
        if gw and gw.default_api_base:
            fb_kwargs["api_base"] = gw.default_api_base

        try:
            response = await acompletion(**fb_kwargs)
            return await self._collect_stream(response)
        except Exception:
            continue  # Zincirdeki bir sonrakini dene

    return LLMResponse(content="Service unavailable.", finish_reason="error")

visited seti kritiktir. O olmasaydı, A→B→A gibi bir zincir sonsuza kadar dönerdi. Bu set sayesinde motor her modeli tam olarak bir kez dener.

Gateway çözünürlüğü de önemlidir. Farklı modeller farklı API formatlarına ihtiyaç duyar. Claude modelleri Anthropic formatlı bir gateway üzerinden yönlendirilir (/v1 son eki yok). GPT modelleri OpenAI uyumlu bir gateway üzerinden yönlendirilir (/v1 ile). Groq modelleri ise başka bir endpoint kullanır. Fallback motoru, zincirdeki her model için doğru gateway'i çözerek, Anthropic isteklerini bir OpenAI endpoint'ine göndermek gibi protokol uyuşmazlıklarını önler.

Bu, çoğu framework'ün tamamen görmezden geldiği bir detaydır. Tüm modellerin aynı protokolü konuştuğunu varsayarlar. Üretim ortamında (production), 4 farklı API formatında 19 modelle bu varsayım anında çöker.

İş Katmanı: Tool Call Doğrulaması

Birleştirme fonksiyonu, üzerine kendi fallback döngüsünü ekler:

async def consolidate(self, session, provider, model, **kwargs):
    visited = set()
    current_model = model

    while current_model and current_model not in visited and len(visited) <= 3:
        visited.add(current_model)

        response = await asyncio.wait_for(
            provider.chat(messages=messages, tools=SAVE_MEMORY_TOOL, model=current_model),
            timeout=30,
        )

        if response.has_tool_calls:
            # Başarılı: hafızayı ayıkla ve kaydet
            args = response.tool_calls[0].arguments
            self.write_long_term(args["memory_update"])
            self.append_history(args["history_entry"])
            return True

        # Model tool'u çağırmadı — zincirdeki bir sonrakini dene
        entry = MODEL_MAP.get(current_model)
        next_model = entry.fallback if entry else None
        if next_model and next_model not in visited:
            current_model = next_model
            continue

        return False  # Daha fazla fallback yok

    return False

Bu, _chat_with_retry fonksiyonunun başarılı bir yanıt (HTTP 200, geçerli içerik) döndürdüğü ancak modelin tool'u kullanmadığı durumları yakalar. Birleştirme fonksiyonu has_tool_calls kontrolü yapar ve eksikse zincirdeki bir sonraki modele geçer.

Timeout sarmalayıcısı (asyncio.wait_for) da fallback'i tetikler. Bir model 30 saniyeden uzun sürerse (yavaş upstream'lerde Cloudflare 524 hatalarında yaygındır), fonksiyon TimeoutError yakalar ve kullanıcının oturumunu süresiz olarak bloke etmek yerine bir sonraki modeli dener.

Birleştirme İçin Neden Groq?

Hafıza birleştirme bir arka plan görevidir. Kullanıcı çıktıyı görmez. Sadece çalışmasına ihtiyaç duyarlar. Bu, onu hızlı ve ucuz modeller için mükemmel bir aday yapar.

Çoğu framework her şey için aynı pahalı modeli kullanır. Konuşma için Claude Sonnet çalıştırıyorsanız, hafıza birleştirme için de Claude Sonnet çalıştırıyorsunuz demektir. Bu, hiçbir insanın okumadığı bir çıktı üreten bir görev için input token başına 3 dolar maliyet ve birleştirme başına 8+ saniye demektir.

Birleştirmeyi konuşma modelinden tamamen ayırdık. Konuşma, kullanıcının seçtiği modeli kullanır. Birleştirme ise Groq üzerinde barındırılan özel bir model zincirini kullanır:

Model Hız Girdi Maliyeti Çıktı Maliyeti
llama-3.3-70b-versatile 394 TPS $0.59/M $0.79/M
qwen3-32b 662 TPS $0.29/M $0.59/M
llama-4-scout-17b-16e 594 TPS $0.11/M $0.34/M
gpt-4.1-mini (önceki) ~150 TPS $0.40/M $1.60/M

Birincil model (llama-3.3-70b), 60 mesajlık bir oturumu yaklaşık 5 saniyede birleştirir. Önceki varsayılan (gpt-4.1-mini) 8+ saniye sürüyordu. Birleştirme başına maliyet ~0,003 dolardan ~0,001 dolara düştü.

Takas (tradeoff): Groq modelleri karmaşık prompt'larda daha az güvenilir tool calling performansına sahiptir. Çift katmanlı fallback tam da bu yüzden var. llama-3.3-70b tool'u çağıramadığında, qwen3-32b devreye girer. O da başarısız olursa, llama-4-scout dener. Üç Groq modeli de başarısız olursa, gpt-4.1-mini neredeyse %100 tool calling güvenilirliği ile işi halleder.

Üretimde, birincil modelin %85 oranında başarılı olduğunu görüyoruz. Zincir, birleştirmelerin %2'sinden azında gpt-4.1-mini'ye ulaşır. Toplam başarısızlık oranı: etkili bir şekilde sıfır.

Üretim Sonuçları

Bunu iki LemonClaw örneğine dağıttık ve gerçek Telegram konuşmalarıyla test ettik.

İlk dağıtım (yalnızca tek katmanlı fallback):

Memory consolidation (archive_all): 56 messages
llama-3.3-70b-versatile → "Failed to call a function"
Falling back → qwen3-32b
qwen3-32b: LLM did not call save_memory, skipping
→ "Memory archival failed, session not cleared."

Taşıma katmanı ilk hatayı yakaladı ve fallback yaptı. Ancak qwen3-32b, tool'u çağırmadan metin döndürdü. Tek katmanlı fallback bunu halledemedi. Bu, diğer her framework'ün sessizce hafıza kaybedeceği senaryonun aynısıdır.

İkinci dağıtım (çift katmanlı fallback):

Memory consolidation (archive_all): 60 messages
model=llama-3.3-70b-versatile → success
Memory consolidation done: 60 messages remaining

Aynı model, aynı mesaj hacmi. Bu sefer ilk denemede çalıştı. Tool calling hatasının aralıklı doğası, tek bir yedek model yerine neden bir fallback zincirine ihtiyacınız olduğunun tam olarak nedenidir.

Birincil model başarısız olduğunda zincir onu yakalar:

llama-3.3-70b → tool call failed
→ consolidate() fallback → qwen3-32b
→ qwen3-32b didn't call tool
→ consolidate() fallback → llama-4-scout
→ llama-4-scout didn't call tool
→ consolidate() fallback → gpt-4.1-mini
→ gpt-4.1-mini called save_memory ✓
Memory consolidation done

Dört model denendi, hafıza kaydedildi. Kullanıcı "Yeni oturum başlatıldı." mesajını görür ve tüm bunların yaşandığından haberi bile olmaz.

Mimari Farkı

LemonClaw'un hafıza sistemi ile alternatiflerin özellik bazında karşılaştırması:

Yetenek Tipik Yapay Zeka Ajan Framework'ü LemonClaw
Birleştirme modeli Konuşma ile aynı (pahalı, yavaş) Bağımsız model zinciri, Groq hızlandırmalı
Hata yönetimi Uyarı günlüğü tut, hafızayı kaybet Çift katmanlı fallback, 5 model derinliğinde
Taşıma fallback Aynı modeli 3 kez tekrar dene Farklı modeller arasında zincirleme fallback
İş mantığı fallback Yok Tool call doğrulaması + model değiştirme
Timeout koruması Yok (Cloudflare 524 oturumu bloke eder) asyncio.wait_for(timeout=30) + fallback
Oturum kısaltma Yok (bağlam sonsuza kadar büyür) Birleştirmeden sonra eski mesajları kısalt
Geçmiş araması Yok HISTORY.md kayan pencere, grep ile aranabilir
Dahili modeller Desteklenmiyor Sistem modelleri için hidden=True
Döngü önleme Gerekli değil (zincir yok) visited seti A→B→A döngülerini önler
Gateway çözünürlüğü Tek bir API formatı varsayılır Protokol algılamalı model başına gateway

Bu tablodaki her satır, ya bizzat deneyimlediğimiz ya da diğer framework'lerin hata takip sistemlerinde gözlemlediğimiz bir üretim hatasını temsil eder. Çift katmanlı fallback, gizli model kataloğu, model başına gateway çözünürlüğü, timeout tetiklemeli fallback: Bunların hiçbiri nanobot'ta veya incelediğimiz diğer herhangi bir açık kaynaklı ajan framework'ünde mevcut değildir.

Neler Öğrendik?

"İstek başarılı oldu", "görev başarılı oldu" demek değildir. Genel retry motorları HTTP düzeyinde çalışır. Geçerli JSON içeren bir 200 yanıtının, model istediğiniz tool'u kullanmadığı için aslında bir başarısızlık olduğunu bilemezler. İş açısından kritik operasyonların kendi başarı kriterlerine ve kendi fallback mantıklarına ihtiyacı vardır.

Küçük modeller büyük modellerden farklı şekilde hata verir. Büyük modeller (GPT-4.1, Claude Sonnet) istendiğinde neredeyse her zaman tool'ları çağırır. Hızlı inference motorlarındaki küçük modeller bazen tool şemasını tamamen görmezden gelen geçerli görünümlü yanıtlar üretir. Bu, prompt engineering ile düzeltebileceğiniz bir bug değildir. Mimari müdahale gerektiren bir yetenek açığıdır.

Üretim verileriyle test edin, sentetik verilerle değil. 6 sentetik mesajla yaptığımız ilk testimiz her modelde başarılı oldu. Tool call geçmişi, zaman damgaları ve karışık diller içeren gerçek 60 mesajlık oturum, üç Groq modelinden ikisinde başarısız oldu. Gerçek verilerin karmaşıklığı, temiz test verilerinin asla ortaya çıkarmayacağı hata modlarını ifşa eder.

Bu, yapay zeka API rate limiting rehberinin burada önemli olmasının nedeni de budur. Hafıza sisteminin sadece "daha iyi bir modele" ihtiyacı yoktur. Bir taşıma politikasına, bir iş mantığı başarı kontrolüne ve sıradan sağlayıcı hataları altında çökmeyen bir fallback merdivenine ihtiyacı vardır.


LemonClaw, yerleşik çoklu model yönlendirme, kalıcı hafıza ve 10'dan fazla sohbet platformu entegrasyonuna sahip açık kaynaklı bir yapay zeka ajan framework'üdür. Burada açıklanan çift katmanlı fallback sisteminin tamamı açık kaynaklı sürümle birlikte sunulur. Kendi sunucunuzda çalıştırın: github.com/hedging8563/lemonclaw

Tek bir API anahtarı üzerinden 300'den fazla yapay zeka modeline mi ihtiyacınız var? lemondata.cc; OpenAI, Anthropic, Google, DeepSeek, Groq ve daha fazlasına birleşik erişim sağlar.

Share: