Ayarlar

Dil

Yapay Zeka Ajanınız Neden Hafızasını Kaybedip Duruyor

T
TokenLab
·5 Mart 2026·1332 görüntüleme
Yapay Zeka Ajanınız Neden Hafızasını Kaybedip Duruyor

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 belleğe aktarmaya (consolidate) ç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. Hermes Agent çalışma zamanında (runtime), özel bir fallback eklemeden önce hafıza konsolidasyonu tek bir modelde yaklaşık %15 hata oranına sahipti. Görünmez bir altyapı olması gereken bir özellik için bu kabul edilemez.

Eğer sadece hafıza alt sistemi yerine çevreleyen ürün yüzeyini oluşturuyorsanız, bu sayfayı tek anahtarlı chatbot kılavuzu ve AI API rate limiting kılavuzu 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 konsolidasyonunu basit bir LLM çağrısı olarak görür. Çalışırsa harika. Çalışmazsa hafıza kaybolur.

Hermes Agent başlangıç seviyesinde, konsolidasyon için konuşma ile aynı modeli kullanıyordu. 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 olur.

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

Hiçbir framework konsolidasyonu ana modelden ayırmıyor. Hiçbirinin hafıza işlemleri için fallback mantığı yok. 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 etmiyor.

Bunlar uç durumlar (edge cases) değil. Herhangi bir modelde %15 hata oranıyla, günde 100 konsolidasyon çalıştıran bir framework bunlardan 15'inde hafıza 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 yeniden denemedir (retry). Bizde bu vardı. Geçici HTTP hatalarını düzgün bir şekilde yönetiyor:

# 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, 429'ları ve ağ aksaklıklarını yakalar. Ancak iki hata modu gözden kaçar:

Hata modu 1: Model tool calling yapamıyor. Bazı modeller, özellikle hızlı çıkarım (inference) motorlarında çalışan daha küçük olanlar, karmaşık prompt'larda bazen geçerli fonksiyon çağrıları oluşturamazlar. API, bir MidStreamFallbackError içine sarılmış ServiceUnavailableError ile 200 döner. Retry mantığınız bir istisna (exception) görür, aynı modeli yeniden dener ve 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öner. 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. Konsolidasyon fonksiyonu tool çağrılarını kontrol eder, hiçbirini bulamaz ve vazgeçer.

İkinci hata modu sinsi olanıdı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üzeyi retry düzeltemez.

Çift Katmanlı Fallback Mimarisi

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

Kullanıcı /new gönderir
    │
    ▼
consolidate() ─── İş Katmanı Fallback
    │               "Model save_memory'yi çağırdı mı?"
    │               Hayır → zincirdeki bir sonraki modeli dene
    │
    ▼
_chat_with_retry() ─── Taşıma Katmanı Fallback
    │                    HTTP hataları → exponential backoff
    │                    Tüm denemeler tükendi → 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-yeniden-dene yaklaşımından temelden farklıdır. Bir model bir tool'u çağıramadığında, onu aynı prompt ile yeniden denemek nadiren yardımcı olur. Farklı ağırlıklara ve farklı tool calling davranışı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 listesinden gizle

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 konsolidasyon modelleri (yalnızca dahili kullanım)
    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 yine de fallback zincirlerine dahil eder. Kullanıcılar geçiş yapabilecekleri 16 model görürler. Sistem ise 19 model kullanır. Üç gizli model, hız ve maliyetin konuşma kalitesinden daha önemli olduğu hafıza konsolidasyonu gibi arka plan görevleri için özel olarak 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ü Tespiti ile 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 olmadan, A→B→A gibi bir zincir sonsuza kadar dönerdi. Onunla birlikte motor, her modeli tam olarak bir kez dener.

Gateway çözünürlüğü de önemlidir. Farklı modeller farklı API formatlarına ihtiyaç duyar. Claude modelleri bir Anthropic formatlı gateway üzerinden yönlendirilir (/v1 son eki olmadan). 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 uyumsuzlukları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 model varken bu varsayım anında çöker.

İş Katmanı: Tool Call Doğrulaması

Konsolidasyon 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ı: hafızayı çıkar 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  # Başka fallback kalmadı

    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ığı durumu yakalar. Konsolidasyon fonksiyonu has_tool_calls olup olmadığını kontrol eder ve eksikse zincirdeki bir sonraki modele geçer.

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

Konsolidasyon İçin Neden Groq?

Hafıza konsolidasyonu 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. Eğer konuşma için Claude Sonnet çalıştırıyorsanız, hafıza konsolidasyonu için de Claude Sonnet çalıştırıyorsunuz demektir. Bu, hiçbir insanın okumadığı bir çıktı üreten bir görev için giriş token başına 3 dolar/M maliyet ve konsolidasyon başına 8+ saniye demektir.

Konsolidasyonu konuşma modelinden tamamen ayırdık. Konuşma, kullanıcının seçtiği modeli kullanır. Konsolidasyon ise Groq tarafından barındırılan özel bir model zincirini kullanır:

Model Hız Giriş Maliyeti Çıkış 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 konsolide eder. Önceki varsayılan model (gpt-4.1-mini) 8 saniyeden fazla sürüyordu. Konsolidasyon başına maliyet ~0,003 dolardan ~0,001 dolara düştü.

Buradaki ödünleşim (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.

Üretim ortamında, birincil modelin vakaların yaklaşık %85'inde başarılı olduğunu görüyoruz. Zincir, konsolidasyonların %2'sinden azında gpt-4.1-mini'ye ulaşır. Toplam hata oranı: fiilen sıfır.

Üretim Sonuçları

Bunu iki Hermes Agent runtime ö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 yönetemedi. 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 bunlardan haberi bile olmaz.

Mimari Boşluk

Hafıza sistemi ve alternatifleri, özellik bazında karşılaştırma:

Yetenek Tipik Yapay Zeka Ajanı Framework'ü Çift katmanlı fallback tasarımı
Konsolidasyon modeli Konuşma ile aynı (pahalı, yavaş) Bağımsız model zinciri, Groq-hızlandırmalı
Hata yönetimi Uyarı logla, hafızayı kaybet Çift katmanlı fallback, 5 model derinliğinde
Taşıma fallback'i Aynı modeli 3 kez dene Farklı modeller arasında zincirleme fallback
İş mantığı fallback'i Yok Tool call doğrulaması + model değiştirme
Zaman aşımı koruması Yok (Cloudflare 524 oturumu bloke eder) asyncio.wait_for(timeout=30) + fallback
Oturum budama (truncation) Yok (bağlam sonsuza kadar büyür) Konsolidasyondan sonra eski mesajları buda
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 API formatı varsayılır Protokol tespiti ile model başına gateway

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

Neler Öğrendik

"İstek başarılı" demek "görev başarılı" demek değildir. Genel retry motorları HTTP düzeyinde çalışır. 200 yanıtının geçerli JSON ile gelmesinin aslında bir hata olduğunu, çünkü modelin istediğiniz tool'u kullanmadığını 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ı çıkarım 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 hata değildir. Mimari müdahale gerektiren bir yetenek boşluğudur.

Sentetik verilerle değil, üretim verileriyle test edin. 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 çıkaramayacağı hata modlarını ifşa eder.

Bu aynı zamanda AI API rate limiting kılavuzunun burada önemli olmasının nedenidir. 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.


Bu makale, Hermes Agent'tan bir güvenilirlik modelini açıklamaktadır. Buradaki mimari modeli hafıza dayanıklılığı, fallback tasarımı ve gateway uyumlu model yönlendirmesi için referans olarak kullanın.

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

Paylaş: