Pengaturan

Bahasa

Mengapa Agen AI Anda Terus Kehilangan Memorinya

L
LemonData
ยท5 Maret 2026ยท825 tampilan
Mengapa Agen AI Anda Terus Kehilangan Memorinya

AI agent Anda baru saja melakukan percakapan selama 30 menit dengan pengguna. Mereka mendiskusikan persyaratan proyek, berbagi preferensi, membuat keputusan. Kemudian pengguna mengetik /new untuk memulai sesi baru.

Agent mencoba mengonsolidasikan percakapan tersebut ke dalam memori jangka panjang. Panggilan LLM gagal. Rate limit. Timeout. Atau model mengembalikan teks alih-alih memanggil tool yang diperlukan.

Memorinya hilang. Tiga puluh menit context, menguap begitu saja.

Ini terjadi lebih sering daripada yang Anda bayangkan. Kami melacaknya di seluruh instance LemonClaw kami: konsolidasi memori memiliki tingkat kegagalan ~15% pada model tunggal mana pun. Untuk fitur yang seharusnya menjadi infrastruktur yang tidak terlihat, hal itu tidak dapat diterima.

Jika Anda sedang membangun permukaan produk di sekitarnya daripada hanya subsistem memori, pasangkan halaman ini dengan panduan chatbot satu kunci dan panduan LemonClaw self-hosted. Ketahanan memori hanya penting ketika agent benar-benar hidup di dalam aplikasi yang dapat digunakan.

Bagaimana Framework Lain Menangani Ini (Mereka Tidak Menanganinya)

Kebanyakan framework AI agent memperlakukan konsolidasi memori sebagai panggilan LLM sederhana. Jika berhasil, bagus. Jika tidak, memorinya hilang.

Framework pendahulu LemonClaw menggunakan model yang sama untuk konsolidasi seperti halnya untuk percakapan. Panggilan Claude Sonnet yang memakan biaya $0,003 dan waktu 8+ detik, hanya untuk merangkum chat yang tidak akan pernah dilihat pengguna. Ketika panggilan itu gagal (rate limit, timeout, kesalahan model), framework mencatat peringatan dan melanjutkan proses. Context pengguna pun hilang.

nanobot, framework populer lainnya, memiliki arsitektur yang sama. Satu model, satu percobaan, tanpa fallback. Fungsi konsolidasi bahkan tidak memiliki timeout. Upstream yang lambat (kesalahan Cloudflare 524 sering terjadi) memblokir seluruh sesi hingga koneksi terputus.

Kedua framework tersebut tidak memisahkan konsolidasi dari model utama. Keduanya tidak memiliki logika fallback untuk operasi memori. Keduanya tidak membedakan antara "panggilan API gagal" dan "panggilan API berhasil tetapi model tidak melakukan apa yang kita minta."

Ini bukan kasus ekstrem (edge cases). Dengan tingkat kegagalan 15% pada model tunggal mana pun, framework yang menjalankan 100 konsolidasi per hari akan kehilangan memori pada 15 di antaranya. Selama seminggu, itu berarti 105 percakapan di mana agent melupakan segalanya.

Masalahnya Lebih Dalam Daripada Logika Retry

Perbaikan yang jelas adalah retry dengan exponential backoff. Kami pernah menerapkannya. Ini menangani kesalahan HTTP sementara dengan baik:

# 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])

Ini menangani error 429 dan gangguan jaringan. Namun, ada dua mode kegagalan yang lolos:

Mode kegagalan 1: model tidak dapat melakukan tool calling. Beberapa model, terutama yang lebih kecil yang berjalan pada mesin inference cepat, terkadang gagal menghasilkan pemanggilan fungsi yang valid pada prompt yang kompleks. API mengembalikan status 200 dengan ServiceUnavailableError yang terbungkus di dalam MidStreamFallbackError. Logika retry Anda melihat pengecualian, mencoba kembali model yang sama, dan mendapatkan kesalahan yang sama.

Mode kegagalan 2: model "berhasil" tetapi tidak memanggil tool. LLM mengembalikan respons yang sangat valid. HTTP 200. Tidak ada error. Tetapi alih-alih memanggil save_memory dengan data terstruktur, ia menulis ringkasan teks biasa. Mesin retry Anda menganggap ini sebagai keberhasilan. Fungsi konsolidasi memeriksa pemanggilan tool, tidak menemukannya, dan menyerah.

Mode kegagalan kedua adalah yang paling berbahaya. Lapisan transport mengira semuanya berhasil. Lapisan bisnis tahu bahwa itu tidak berhasil. Tidak ada jumlah retry di tingkat HTTP yang akan memperbaiki model yang tidak memahami skema tool Anda.

Arsitektur Fallback Dua Lapis

Kami menyelesaikan ini dengan dua loop fallback independen yang beroperasi pada level yang berbeda:

User mengirim /new
    โ”‚
    โ–ผ
consolidate() โ”€โ”€โ”€ Fallback Lapisan Bisnis
    โ”‚               "Apakah model memanggil save_memory?"
    โ”‚               Tidak โ†’ coba model berikutnya dalam rantai
    โ”‚
    โ–ผ
_chat_with_retry() โ”€โ”€โ”€ Fallback Lapisan Transport
    โ”‚                    Kesalahan HTTP โ†’ exponential backoff
    โ”‚                    Semua retry habis โ†’ telusuri rantai fallback
    โ”‚
    โ–ผ
Rantai fallback MODEL_MAP:
    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)                  (andal)        (pilihan terakhir)

Lapis 1 menangani kegagalan transport. Lapis 2 menangani kegagalan logika bisnis. Rantai fallback digunakan bersama oleh kedua lapisan, yang didefinisikan sekali dalam katalog pusat.

Ini adalah pendekatan yang secara fundamental berbeda dari sekadar mencoba kembali model yang sama. Ketika sebuah model gagal memanggil tool, mencobanya kembali dengan prompt yang sama jarang membuahkan hasil. Beralih ke model yang berbeda dengan bobot yang berbeda dan perilaku tool calling yang berbeda justru lebih efektif.

Katalog Model: Satu Sumber Kebenaran

Setiap model dalam katalog kami memiliki field fallback opsional yang menunjuk ke model berikutnya untuk dicoba:

@dataclass(frozen=True)
class ModelEntry:
    id: str
    label: str
    tier: str
    description: str
    fallback: str | None = None
    hidden: bool = False  # Tersembunyi dari daftar /model yang menghadap pengguna

MODEL_CATALOG = [
    # Model yang terlihat oleh pengguna (16 model yang dapat diganti oleh pengguna)
    ModelEntry("claude-sonnet-4-6", "Claude Sonnet 4.6", "standard",
               "Direkomendasikan", fallback="claude-sonnet-4-5"),
    ModelEntry("gpt-4.1-mini", "GPT-4.1 Mini", "economy",
               "Tool calling yang stabil", fallback="claude-haiku-4-5"),

    # Model konsolidasi tersembunyi (hanya untuk penggunaan internal)
    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),
    # ...
]

Flag hidden=True menjaga model internal agar tidak muncul dalam perintah /model yang menghadap pengguna, namun tetap berpartisipasi dalam rantai fallback. Pengguna melihat 16 model yang dapat mereka pilih. Sistem menggunakan 19. Tiga model tersembunyi tersebut ada semata-mata untuk tugas latar belakang seperti konsolidasi memori, di mana kecepatan dan biaya lebih penting daripada kualitas percakapan.

Katalog ini adalah satu-satunya sumber kebenaran untuk semua perutean model. Menambahkan model baru ke rantai fallback berarti hanya menambahkan satu baris. Tidak ada file konfigurasi yang perlu disinkronkan, tidak ada variabel lingkungan yang perlu diperbarui, tidak ada skrip deployment yang perlu dimodifikasi.

Lapisan Transport: Fallback Berantai dengan Deteksi Siklus

Mesin retry menelusuri rantai fallback menggunakan set yang dikunjungi untuk mencegah loop tak terbatas:

async def _chat_with_retry(self, kwargs, original_model):
    # Fase 1: Exponential backoff pada model utama
    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 tidak valid.", finish_reason="error")

    # Fase 2: Telusuri rantai fallback
    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)

        # Resolusi gateway yang benar untuk model ini
        gw = self._resolve_gateway_for_model(current)
        resolved = self._resolve_model(current, gateway=gw)
        fb_kwargs = {**kwargs, "model": resolved}

        # Perbaiki api_base untuk protokol model target
        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  # Coba berikutnya dalam rantai

    return LLMResponse(content="Layanan tidak tersedia.", finish_reason="error")

Set visited sangatlah krusial. Tanpanya, rantai seperti Aโ†’Bโ†’A akan berputar selamanya. Dengan set ini, mesin mencoba setiap model tepat satu kali.

Resolusi gateway juga penting. Model yang berbeda membutuhkan format API yang berbeda. Model Claude merute melalui gateway format Anthropic (tanpa akhiran /v1). Model GPT merute melalui gateway yang kompatibel dengan OpenAI (dengan /v1). Model Groq menggunakan endpoint lainnya. Mesin fallback menyelesaikan gateway yang benar untuk setiap model dalam rantai, mencegah ketidakcocokan protokol seperti mengirim permintaan Anthropic ke endpoint OpenAI.

Ini adalah detail yang diabaikan oleh sebagian besar framework. Mereka mengasumsikan semua model berbicara dalam protokol yang sama. Dalam produksi, dengan 19 model di 4 format API yang berbeda, asumsi tersebut akan langsung gagal.

Lapisan Bisnis: Verifikasi Pemanggilan Tool

Fungsi konsolidasi menambahkan loop fallback-nya sendiri di atasnya:

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:
            # Berhasil: ekstrak dan simpan memori
            args = response.tool_calls[0].arguments
            self.write_long_term(args["memory_update"])
            self.append_history(args["history_entry"])
            return True

        # Model tidak memanggil tool โ€” coba berikutnya dalam rantai
        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  # Tidak ada fallback lagi

    return False

Ini menangani kasus di mana _chat_with_retry mengembalikan respons yang berhasil (HTTP 200, konten valid) tetapi model tidak menggunakan tool tersebut. Fungsi konsolidasi memeriksa has_tool_calls, dan jika tidak ada, pindah ke model berikutnya dalam rantai.

Wrapper timeout (asyncio.wait_for) juga memicu fallback. Jika sebuah model memakan waktu lebih dari 30 detik (umum terjadi dengan kesalahan Cloudflare 524 pada upstream yang lambat), fungsi tersebut menangkap TimeoutError dan mencoba model berikutnya daripada memblokir sesi pengguna tanpa batas waktu.

Mengapa Groq untuk Konsolidasi

Konsolidasi memori adalah tugas latar belakang. Pengguna tidak melihat hasilnya. Mereka hanya butuh itu berfungsi. Hal ini menjadikannya kandidat sempurna untuk model yang cepat dan murah.

Kebanyakan framework menggunakan model mahal yang sama untuk segalanya. Jika Anda menjalankan Claude Sonnet untuk percakapan, Anda juga menjalankan Claude Sonnet untuk konsolidasi memori. Itu berarti biaya token input $3/M dan waktu 8+ detik per konsolidasi, untuk tugas yang menghasilkan output yang tidak pernah dibaca manusia.

Kami memisahkan konsolidasi dari model percakapan sepenuhnya. Percakapan menggunakan model apa pun yang dipilih pengguna. Konsolidasi menggunakan rantai khusus dari model yang di-host di Groq:

Model Kecepatan Biaya Input Biaya Output
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 (sebelumnya) ~150 TPS $0,40/M $1,60/M

Model utama (llama-3.3-70b) mengonsolidasikan sesi 60 pesan dalam waktu ~5 detik. Default sebelumnya (gpt-4.1-mini) memakan waktu 8+ detik. Biaya per konsolidasi turun dari ~$0,003 menjadi ~$0,001.

Timbal baliknya: model Groq memiliki tool calling yang kurang andal pada prompt yang kompleks. Itulah alasan mengapa fallback dua lapis ada. Ketika llama-3.3-70b gagal memanggil tool, qwen3-32b mengambil alih. Jika itu juga gagal, llama-4-scout mencoba. Jika ketiga model Groq gagal, gpt-4.1-mini menanganinya dengan keandalan tool calling yang hampir 100%.

Dalam produksi, kami melihat model utama berhasil ~85% dari waktu yang ada. Rantai mencapai gpt-4.1-mini dalam kurang dari 2% konsolidasi. Tingkat kegagalan total: secara efektif nol.

Hasil Produksi

Kami menerapkan ini pada dua instance LemonClaw dan mengujinya dengan percakapan Telegram yang nyata.

Deployment pertama (hanya fallback satu lapis):

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."

Lapisan transport menangkap kegagalan pertama dan melakukan fallback. Namun qwen3-32b mengembalikan teks tanpa memanggil tool. Fallback satu lapis tidak bisa menangani ini. Ini adalah skenario tepat di mana framework lain akan kehilangan memori secara diam-diam.

Deployment kedua (fallback dua lapis):

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

Model yang sama, volume pesan yang sama. Kali ini berhasil pada percobaan pertama. Sifat kegagalan tool calling yang intermiten adalah alasan mengapa Anda membutuhkan rantai fallback daripada hanya satu model cadangan.

Ketika model utama gagal, rantai tersebut menangkapnya:

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

Empat model dicoba, memori tersimpan. Pengguna melihat "Sesi baru dimulai." dan tidak tahu bahwa semua ini terjadi.

Kesenjangan Arsitektur

Sistem memori LemonClaw vs. alternatif lainnya, fitur demi fitur:

Kemampuan Framework AI Agent Biasa LemonClaw
Model konsolidasi Sama dengan percakapan (mahal, lambat) Rantai model independen, diakselerasi Groq
Penanganan kegagalan Catat peringatan, memori hilang Fallback dua lapis, sedalam 5 model
Fallback transport Retry model yang sama 3x Fallback berantai di berbagai model
Fallback logika bisnis Tidak ada Verifikasi pemanggilan tool + pergantian model
Perlindungan timeout Tidak ada (Cloudflare 524 memblokir sesi) asyncio.wait_for(timeout=30) + fallback
Pemangkasan sesi Tidak ada (context tumbuh selamanya) Pangkas pesan lama setelah konsolidasi
Pencarian riwayat Tidak ada Rolling window HISTORY.md, dapat dicari dengan grep
Model internal Tidak didukung hidden=True untuk model khusus sistem
Pencegahan siklus Tidak diperlukan (tidak ada rantai) Set visited mencegah loop Aโ†’Bโ†’A
Resolusi gateway Diasumsikan format API tunggal Gateway per-model dengan deteksi protokol

Setiap baris dalam tabel ini mewakili kegagalan produksi yang kami alami sendiri atau kami amati di pelacak masalah framework lain. Fallback dua lapis, katalog model tersembunyi, resolusi gateway per-model, fallback yang dipicu timeout: semua ini tidak ada di nanobot atau framework agent open-source lainnya yang kami periksa.

Apa yang Kami Pelajari

"Permintaan berhasil" bukanlah "tugas berhasil." Mesin retry generik beroperasi pada tingkat HTTP. Mereka tidak tahu bahwa respons 200 dengan JSON yang valid sebenarnya adalah kegagalan karena model tidak menggunakan tool yang Anda minta. Operasi bisnis yang kritis membutuhkan kriteria keberhasilan dan logika fallback mereka sendiri.

Model kecil gagal dengan cara yang berbeda dari model besar. Model besar (GPT-4.1, Claude Sonnet) hampir selalu memanggil tool saat diminta. Model kecil pada mesin inference cepat terkadang menghasilkan respons yang terlihat valid tetapi mengabaikan skema tool sepenuhnya. Ini bukan bug yang bisa Anda perbaiki dengan prompt engineering. Ini adalah kesenjangan kemampuan yang membutuhkan mitigasi arsitektural.

Uji dengan data produksi, bukan data sintetis. Pengujian awal kami dengan 6 pesan sintetis berhasil pada setiap model. Sesi 60 pesan yang nyata dengan riwayat pemanggilan tool, timestamp, dan bahasa campuran gagal pada dua dari tiga model Groq. Kompleksitas data nyata mengekspos mode kegagalan yang tidak akan pernah ditemukan oleh data uji yang bersih.

Inilah sebabnya mengapa panduan rate limiting API AI sangat penting di sini. Sistem memori tidak hanya membutuhkan "model yang lebih baik." Ia membutuhkan kebijakan transport, pemeriksaan keberhasilan logika bisnis, dan tangga fallback yang tidak runtuh di bawah kegagalan penyedia layanan yang biasa terjadi.


LemonClaw adalah framework AI agent open-source dengan perutean multi-model bawaan, memori persisten, dan 10+ integrasi platform chat. Seluruh sistem fallback dua lapis yang dijelaskan di sini tersedia dalam rilis open-source. Jalankan di server Anda sendiri: github.com/hedging8563/lemonclaw

Butuh 300+ model AI melalui satu API key? lemondata.cc menyediakan akses terpadu ke OpenAI, Anthropic, Google, DeepSeek, Groq, dan banyak lagi.

Share: