Memori
Memori OpenClaw adalah file Markdown biasa di workspace agen. File-file ini adalah sumber kebenaran (source of truth); model hanya “mengingat” apa yang tertulis di disk. Alat pencarian memori disediakan oleh plugin memori yang aktif (default:memory-core). Nonaktifkan plugin memori dengan plugins.slots.memory = "none".
File Memori (Markdown)
Tata letak workspace default menggunakan dua lapisan memori:memory/YYYY-MM-DD.md- Log harian (hanya untuk penambahan/append-only).
- Dibaca untuk hari ini + kemarin saat sesi dimulai.
MEMORY.md(opsional)- Memori jangka panjang yang dikurasi.
- Hanya dimuat dalam sesi utama dan pribadi (tidak pernah dalam konteks grup).
agents.defaults.workspace, default ~/.openclaw/workspace). Lihat Workspace Agen untuk tata letak lengkapnya.
Kapan Harus Menulis Memori
- Keputusan, preferensi, dan fakta yang tahan lama masuk ke
MEMORY.md. - Catatan harian dan konteks yang sedang berjalan masuk ke
memory/YYYY-MM-DD.md. - Jika seseorang berkata “ingat ini,” tuliskan (jangan hanya menyimpannya di RAM).
- Area ini masih terus berkembang. Membantu untuk mengingatkan model agar menyimpan memori; model akan tahu apa yang harus dilakukan.
- Jika Anda ingin sesuatu tetap diingat, minta bot untuk menulisnya ke dalam memori.
Flush Memori Otomatis (Ping Pra-pemadatan)
Ketika sebuah sesi mendekati pemadatan otomatis (auto-compaction), OpenClaw memicu giliran agen yang senyap (silent turn) yang mengingatkan model untuk menulis memori yang tahan lama sebelum konteks dipadatkan. Prompt default secara eksplisit mengatakan model boleh menjawab, tetapi biasanyaNO_REPLY adalah respons yang benar agar pengguna tidak pernah melihat giliran ini.
Hal ini dikendalikan oleh agents.defaults.compaction.memoryFlush:
- Ambang batas lunak (Soft threshold): flush dipicu saat estimasi token sesi melewati
contextWindow - reserveTokensFloor - softThresholdTokens. - Senyap secara default: prompt menyertakan
NO_REPLYsehingga tidak ada balasan yang dikirim. - Dua prompt: prompt pengguna ditambah prompt sistem yang ditambahkan sebagai pengingat.
- Satu kali flush per siklus pemadatan (dilacak di
sessions.json). - Workspace harus dapat ditulis: jika sesi berjalan di sandbox dengan
workspaceAccess: "ro"atau"none", flush akan dilewati.
Pencarian Memori Vektor (Vector Memory Search)
OpenClaw dapat membuat indeks vektor kecil atasMEMORY.md dan memory/*.md sehingga kueri semantik dapat menemukan catatan terkait bahkan jika kata-katanya berbeda.
Default:
- Diaktifkan secara default.
- Memantau perubahan file memori (dengan debouncing).
- Konfigurasi pencarian memori di bawah
agents.defaults.memorySearch(bukanmemorySearchtingkat atas). - Menggunakan embedding jarak jauh (remote) secara default. Jika
memorySearch.providertidak setel, OpenClaw akan memilih otomatis:localjikamemorySearch.local.modelPathdikonfigurasi dan filenya ada.openaijika kunci OpenAI tersedia.geminijika kunci Gemini tersedia.voyagejika kunci Voyage tersedia.- Jika tidak, pencarian memori tetap dinonaktifkan sampai dikonfigurasi.
- Mode lokal menggunakan node-llama-cpp dan mungkin memerlukan
pnpm approve-builds. - Menggunakan sqlite-vec (jika tersedia) untuk mempercepat pencarian vektor di dalam SQLite.
models.providers.*.apiKey, atau variabel lingkungan. Codex OAuth hanya mencakup obrolan/penyelesaian (chat/completions) dan tidak mencukupi untuk embedding untuk pencarian memori. Untuk Gemini, gunakan GEMINI_API_KEY atau models.providers.google.apiKey. Untuk Voyage, gunakan VOYAGE_API_KEY atau models.providers.voyage.apiKey. Saat menggunakan endpoint kustom yang kompatibel dengan OpenAI, setel memorySearch.remote.apiKey (dan opsional memorySearch.remote.headers).
Backend QMD (Eksperimental)
Setelmemory.backend = "qmd" untuk mengganti pengindeks SQLite bawaan dengan QMD: sebuah sidecar pencarian lokal-terlebih-dahulu yang menggabungkan BM25 + vektor + pemeringkatan ulang (reranking). Markdown tetap menjadi sumber kebenaran; OpenClaw memanggil QMD untuk pengambilan data. Poin utama:
Prasyarat
- Dinonaktifkan secara default. Pilih per konfigurasi (
memory.backend = "qmd"). - Instal CLI QMD secara terpisah (
bun install -g https://github.com/tobi/qmdatau ambil dari rilis resmi) dan pastikan binerqmdada diPATHgateway. - QMD memerlukan build SQLite yang memungkinkan ekstensi (
brew install sqlitedi macOS). - QMD berjalan sepenuhnya secara lokal melalui Bun +
node-llama-cppdan mengunduh model GGUF secara otomatis dari HuggingFace pada penggunaan pertama (tidak memerlukan daemon Ollama terpisah). - Gateway menjalankan QMD dalam XDG home yang mandiri di bawah
~/.openclaw/agents/<agentId>/qmd/dengan menyetelXDG_CONFIG_HOMEdanXDG_CACHE_HOME. - Dukungan OS: macOS dan Linux bekerja langsung setelah Bun + SQLite terinstal. Windows paling baik didukung melalui WSL2.
- Gateway menulis XDG home QMD yang mandiri di bawah
~/.openclaw/agents/<agentId>/qmd/(konfigurasi + cache + DB sqlite). - Koleksi dibuat melalui
qmd collection adddarimemory.qmd.paths(ditambah file memori workspace default), kemudianqmd update+qmd embeddijalankan saat boot dan pada interval yang dapat dikonfigurasi (memory.qmd.update.interval, default 5 menit). - Gateway sekarang menginisialisasi manajer QMD saat startup, sehingga timer pembaruan periodik sudah disiapkan bahkan sebelum panggilan
memory_searchpertama. - Penyegaran saat boot sekarang berjalan di latar belakang secara default agar startup obrolan tidak terhambat; setel
memory.qmd.update.waitForBootSync = truejika ingin mempertahankan perilaku pemblokiran sebelumnya. - Pencarian dijalankan melalui
memory.qmd.searchMode(defaultqmd search --json; juga mendukungvsearchdanquery). Jika mode yang dipilih menolak flag pada build QMD Anda, OpenClaw akan mencoba ulang denganqmd query. Jika QMD gagal atau binernya hilang, OpenClaw secara otomatis beralih kembali ke manajer SQLite bawaan agar alat memori tetap berfungsi. - OpenClaw saat ini tidak mengekspos pengaturan ukuran batch embedding QMD; perilaku batch dikendalikan oleh QMD itu sendiri.
- Pencarian pertama mungkin lambat: QMD mungkin mengunduh model GGUF lokal (reranker/ekspansi kueri) pada saat
qmd querypertama kali dijalankan.-
OpenClaw menyetel
XDG_CONFIG_HOME/XDG_CACHE_HOMEsecara otomatis saat menjalankan QMD. -
Jika Anda ingin mengunduh model secara manual terlebih dahulu (dan memanaskan indeks yang sama dengan yang digunakan OpenClaw), jalankan kueri sekali jalan dengan direktori XDG agen.
Status QMD OpenClaw berada di bawah direktori status Anda (default
~/.openclaw). Anda dapat mengarahkanqmdke indeks yang sama persis dengan mengekspor variabel XDG yang sama:
-
OpenClaw menyetel
memory.qmd.*)
command(defaultqmd): menimpa jalur eksekutabel.searchMode(defaultsearch): memilih perintah QMD yang mendukungmemory_search(search,vsearch,query).includeDefaultMemory(defaulttrue): mengindeks otomatisMEMORY.md+memory/**/*.md.paths[]: menambahkan direktori/file tambahan (path, opsionalpattern, opsionalnameyang stabil).sessions: memilih pengindeksan sesi JSONL (enabled,retentionDays,exportDir).update: mengontrol ritme penyegaran dan eksekusi pemeliharaan: (interval,debounceMs,onBoot,waitForBootSync,embedInterval,commandTimeoutMs,updateTimeoutMs,embedTimeoutMs).limits: membatasi payload pemanggilan (maxResults,maxSnippetChars,maxInjectedChars,timeoutMs).scope: skema yang sama dengansession.sendPolicy. Defaultnya adalah hanya DM (denysemua,allowobrolan langsung); longgarkan untuk menampilkan hasil QMD di grup/saluran.match.keyPrefixmencocokkan kunci sesi yang dinormalisasi (huruf kecil, dengan awalanagent:<id>:yang dihapus). Contoh:discord:channel:.match.rawKeyPrefixmencocokkan kunci sesi asli (huruf kecil), termasukagent:<id>:. Contoh:agent:main:discord:.- Legacy:
match.keyPrefix: "agent:..."masih diperlakukan sebagai awalan kunci asli, tetapi lebih disarankan menggunakanrawKeyPrefixuntuk kejelasan.
- Ketika
scopemenolak pencarian, OpenClaw mencatat peringatan denganchannel/chatTypeterkait agar hasil kosong lebih mudah didebug. - Potongan teks (snippets) yang bersumber dari luar workspace akan muncul sebagai
qmd/<collection>/<relative-path>dalam hasilmemory_search;memory_getmemahami awalan tersebut dan membaca dari akar koleksi QMD yang dikonfigurasi. - Saat
memory.qmd.sessions.enabled = true, OpenClaw mengekspor transkrip sesi yang telah dibersihkan (User/Assistant turns) ke dalam koleksi QMD khusus di bawah~/.openclaw/agents/<id>/qmd/sessions/, sehinggamemory_searchdapat memanggil kembali percakapan terbaru tanpa menyentuh indeks SQLite bawaan. - Cuplikan
memory_searchsekarang menyertakan catatan kakiSource: <path#line>jikamemory.citationsdiatur keauto/on; setelmemory.citations = "off"untuk menjaga metadata jalur tetap internal (agen tetap menerima jalur untukmemory_get, tetapi teks cuplikan tidak menyertakan catatan kaki dan prompt sistem memperingatkan agen untuk tidak mensitasinya).
memory.citationsberlaku apa pun backend-nya (auto/on/off).- Saat
qmdberjalan, kami menandaistatus().backend = "qmd"sehingga diagnostik menunjukkan mesin mana yang melayani hasil tersebut. Jika subproses QMD keluar atau output JSON tidak dapat diurai, manajer pencarian mencatat peringatan dan kembali ke penyedia bawaan (embedding Markdown yang ada) sampai QMD pulih.
Jalur Memori Tambahan
Jika Anda ingin mengindeks file Markdown di luar tata letak workspace default, tambahkan jalur eksplisit:- Jalur dapat berupa absolut atau relatif terhadap workspace.
- Direktori dipindai secara rekursif untuk file
.md. - Hanya file Markdown yang diindeks.
- Symlink diabaikan (baik untuk file maupun direktori).
Embedding Gemini (Asli)
Setel penyedia kegemini untuk menggunakan API embedding Gemini secara langsung:
remote.baseUrlopsional (default ke base URL API Gemini).remote.headersmemungkinkan Anda menambahkan header tambahan jika diperlukan.- Model default:
gemini-embedding-001.
remote dengan penyedia OpenAI:
memorySearch.provider = "local" atau setel memorySearch.fallback = "none".
Fallback:
memorySearch.fallbackdapat berupaopenai,gemini,local, ataunone.- Penyedia fallback hanya digunakan ketika penyedia embedding utama gagal.
- Dinonaktifkan secara default. Setel
agents.defaults.memorySearch.remote.batch.enabled = trueuntuk mengaktifkan pengindeksan korpus besar (OpenAI, Gemini, dan Voyage). - Perilaku default akan menunggu penyelesaian batch; atur
remote.batch.wait,remote.batch.pollIntervalMs, danremote.batch.timeoutMinutesjika diperlukan. - Setel
remote.batch.concurrencyuntuk mengontrol berapa banyak pekerjaan batch yang dikirim secara paralel (default: 2). - Mode batch berlaku saat
memorySearch.provider = "openai"atau"gemini"dan menggunakan kunci API yang sesuai. - Pekerjaan batch Gemini menggunakan endpoint batch embedding asinkron dan memerlukan ketersediaan Gemini Batch API.
- Untuk pengisian data besar (backfills), OpenAI biasanya merupakan pilihan tercepat yang kami dukung karena kami dapat mengirimkan banyak permintaan embedding dalam satu pekerjaan batch dan membiarkan OpenAI memprosesnya secara asinkron.
- OpenAI menawarkan harga diskon untuk beban kerja Batch API, sehingga proses pengindeksan besar biasanya lebih murah daripada mengirim permintaan yang sama secara sinkron.
- Lihat dokumentasi dan harga OpenAI Batch API untuk lebih jelasnya:
memory_search— mengembalikan cuplikan dengan file + rentang baris.memory_get— membaca konten file memori berdasarkan jalur.
- Setel
agents.defaults.memorySearch.provider = "local". - Berikan
agents.defaults.memorySearch.local.modelPath(GGUF atau URIhf:). - Opsional: setel
agents.defaults.memorySearch.fallback = "none"untuk menghindari fallback ke jarak jauh.
Bagaimana Alat Memori Bekerja
memory_searchmencari secara semantik dalam potongan-potongan Markdown (target ~400 token, tumpang tindih 80 token) dariMEMORY.md+memory/**/*.md. Ia mengembalikan teks cuplikan (dibatasi ~700 karakter), jalur file, rentang baris, skor, penyedia/model, dan apakah beralih ke embedding jarak jauh (local → remote). Seluruh payload file tidak dikembalikan.memory_getmembaca file Markdown memori tertentu (relatif terhadap workspace), secara opsional dari baris awal dan untuk sejumlah N baris. Jalur di luarMEMORY.md/memory/akan ditolak.- Kedua alat tersebut hanya diaktifkan ketika
memorySearch.enabledbernilai true untuk agen tersebut.
Apa yang Diindeks (dan Kapan)
- Tipe file: hanya Markdown (
MEMORY.md,memory/**/*.md). - Penyimpanan indeks: SQLite per agen di
~/.openclaw/memory/<agentId>.sqlite(dapat dikonfigurasi melaluiagents.defaults.memorySearch.store.path, mendukung token{agentId}). - Kesegaran data: pemantau (watcher) pada
MEMORY.md+memory/menandai indeks sebagai kotor (debounce 1.5 detik). Sinkronisasi dijadwalkan saat sesi dimulai, saat pencarian, atau pada interval tertentu dan berjalan secara asinkron. Transkrip sesi menggunakan ambang batas delta untuk memicu sinkronisasi latar belakang. - Pemicu pengindeksan ulang: indeks menyimpan penyedia/model embedding + sidik jari endpoint + parameter pemotongan (chunking). Jika salah satu di antaranya berubah, OpenClaw akan mereset dan mengindeks ulang seluruh penyimpanan secara otomatis.
Pencarian Hibrida (BM25 + Vektor)
Saat diaktifkan, OpenClaw menggabungkan:- Kemiripan vektor (kecocokan semantik, kata-kata boleh berbeda)
- Relevansi kata kunci BM25 (token eksak seperti ID, variabel lingkungan, simbol kode)
Mengapa Hibrida?
Pencarian vektor sangat bagus untuk “ini artinya sama”:- “Mac Studio gateway host” vs “mesin yang menjalankan gateway”
- “debounce pembaruan file” vs “menghindari pengindeksan di setiap penulisan”
- ID (
a828e60,b3b9895a…) - Simbol kode (
memorySearch.query.hybrid) - String kesalahan (“sqlite-vec unavailable”)
Bagaimana Kami Menggabungkan Hasil (Desain Saat Ini)
Sketsa implementasi:- Ambil sekumpulan kandidat dari kedua sisi:
- Vektor: top
maxResults * candidateMultiplierberdasarkan kemiripan kosinus. - BM25: top
maxResults * candidateMultiplierberdasarkan peringkat BM25 FTS5 (semakin rendah semakin baik).
- Ubah peringkat BM25 menjadi skor berkisar 0..1-ish:
textScore = 1 / (1 + max(0, bm25Rank))
- Gabungkan kandidat berdasarkan ID potongan (chunk ID) dan hitung skor tertimbang:
finalScore = vectorWeight * vectorScore + textWeight * textScore
vectorWeight+textWeightdinormalisasi menjadi 1.0 dalam resolusi konfigurasi, sehingga bobot berperilaku sebagai persentase.- Jika embedding tidak tersedia (atau penyedia mengembalikan vektor nol), kami tetap menjalankan BM25 dan mengembalikan kecocokan kata kunci.
- Jika FTS5 tidak dapat dibuat, kami tetap menggunakan pencarian vektor saja (tidak ada kesalahan fatal).
Alur Pascaproses (Post-processing pipeline)
Setelah menggabungkan skor vektor dan kata kunci, dua tahap pascaproses opsional menyempurnakan daftar hasil sebelum mencapai agen:Pemeringkatan Ulang MMR (Diversitas)
Ketika pencarian hibrida mengembalikan hasil, beberapa potongan mungkin berisi konten yang serupa atau tumpang tindih. Sebagai contoh, mencari “pengaturan jaringan rumah” mungkin mengembalikan lima potongan yang hampir identik dari catatan harian yang berbeda yang semuanya menyebutkan konfigurasi router yang sama. MMR (Maximal Marginal Relevance) mengatur ulang peringkat hasil untuk menyeimbangkan relevansi dengan keberagaman (diversitas), memastikan hasil teratas mencakup berbagai aspek kueri alih-alih mengulangi informasi yang sama. Cara kerjanya:- Hasil diberi skor berdasarkan relevansi asli mereka (skor tertimbang vektor + BM25).
- MMR secara iteratif memilih hasil yang memaksimalkan:
λ × relevansi − (1−λ) × kemiripan_maksimum_terhadap_yang_terpilih. - Kemiripan antar hasil diukur menggunakan kemiripan teks Jaccard pada konten yang telah ditokenisasi.
lambda mengontrol pertukaran (trade-off) tersebut:
lambda = 1.0→ murni relevansi (tanpa penalti keberagaman)lambda = 0.0→ keberagaman maksimum (mengabaikan relevansi)- Default:
0.7(seimbang, sedikit miring ke arah relevansi)
memory_search mengembalikan cuplikan yang redundan atau hampir duplikat, terutama dengan catatan harian yang sering mengulang informasi serupa di berbagai hari.
Peluruhan Temporal (Peningkatan Kebaruan)
Agen dengan catatan harian mengumpulkan ratusan file bertanggal seiring berjalannya waktu. Tanpa peluruhan, catatan yang ditulis dengan baik dari enam bulan lalu bisa mengalahkan pembaruan kemarin tentang topik yang sama. Peluruhan Temporal (Temporal decay) menerapkan pengali eksponensial pada skor berdasarkan usia setiap hasil, sehingga memori terbaru secara alami menempati peringkat lebih tinggi sementara yang lama memudar:λ = ln(2) / waktuParuhHari.
Dengan waktu paruh (half-life) default 30 hari:
- Catatan hari ini: 100% dari skor asli
- 7 hari yang lalu: ~84%
- 30 hari yang lalu: 50%
- 90 hari yang lalu: 12.5%
- 180 hari yang lalu: ~1.6%
MEMORY.md(file memori akar)- File yang tidak bertanggal di
memory/(misalnya,memory/projects.md,memory/network.md) - File-file ini berisi informasi referensi tahan lama yang harus selalu menempati peringkat secara normal.
memory/YYYY-MM-DD.md) menggunakan tanggal yang diekstrak dari nama file. Sumber lain (misalnya, transkrip sesi) menggunakan waktu modifikasi file (mtime).
Contoh — kueri: “apa jadwal kerja Rod?”
Diberikan file memori berikut (hari ini adalah 10 Februari):
Konfigurasi
Kedua fitur tersebut dikonfigurasi di bawahmemorySearch.query.hybrid:
- MMR saja — berguna saat Anda memiliki banyak catatan serupa tetapi usia tidak menjadi masalah.
- Peluruhan temporal saja — berguna saat kebaruan penting tetapi hasil Anda sudah cukup beragam.
- Keduanya — direkomendasikan untuk agen dengan riwayat catatan harian yang besar dan berjalan lama.
Cache Embedding
OpenClaw dapat mencache embedding potongan (chunk embeddings) di SQLite sehingga pengindeksan ulang dan pembaruan yang sering (terutama transkrip sesi) tidak perlu mengenkripsi ulang teks yang tidak berubah. Konfigurasi:Pencarian Memori Sesi (Eksperimental)
Anda secara opsional dapat mengindeks transkrip sesi dan menampilkannya melaluimemory_search. Fitur ini dibatasi di belakang flag eksperimental.
- Pengindeksan sesi bersifat opt-in (nonaktif secara default).
- Pembaruan sesi mengalami debouncing dan diindeks secara asinkron setelah melewati ambang batas delta (upaya terbaik/best-effort).
memory_searchtidak pernah memblokir proses pengindeksan; hasil mungkin sedikit basi sampai sinkronisasi latar belakang selesai.- Hasil tetap mencakup cuplikan saja;
memory_gettetap terbatas pada file memori. - Pengindeksan sesi diisolasi per agen (hanya log sesi agen tersebut yang diindeks).
- Log sesi berada di disk (
~/.openclaw/agents/<agentId>/sessions/*.jsonl). Setiap proses/pengguna dengan akses sistem file dapat membacanya, jadi perlakukan akses disk sebagai batas kepercayaan. Untuk isolasi yang lebih ketat, jalankan agen di bawah pengguna OS atau host yang terpisah.
Akselerasi Vektor SQLite (sqlite-vec)
Ketika ekstensi sqlite-vec tersedia, OpenClaw menyimpan embedding dalam tabel virtual SQLite (vec0) dan melakukan kueri jarak vektor di dalam database. Hal ini menjaga pencarian tetap cepat tanpa memuat setiap embedding ke dalam JS.
Konfigurasi (opsional):
enableddefault ke true; saat dinonaktifkan, pencarian beralih ke kemiripan kosinus dalam proses (in-process) atas embedding yang disimpan.- Jika ekstensi sqlite-vec hilang atau gagal dimuat, OpenClaw mencatat kesalahan dan melanjutkan dengan fallback JS (tanpa tabel vektor).
extensionPathmenimpa jalur sqlite-vec bawaan (berguna untuk build kustom atau lokasi instalasi non-standar).
Unduh Otomatis Embedding Lokal
- Model embedding lokal default:
hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf(~0.6 GB). - Ketika
memorySearch.provider = "local",node-llama-cppmenentukanmodelPath; jika GGUF-nya tidak ada, ia akan mengunduh otomatis ke cache (ataulocal.modelCacheDirjika disetel), lalu memuatnya. Unduhan akan dilanjutkan jika diulang. - Persyaratan build asli: jalankan
pnpm approve-builds, pilihnode-llama-cpp, lalupnpm rebuild node-llama-cpp. - Fallback: jika pengaturan lokal gagal dan
memorySearch.fallback = "openai", kami secara otomatis beralih ke embedding jarak jauh (openai/text-embedding-3-smallkecuali jika ditimpa) dan mencatat alasannya.
Contoh Endpoint Kustom yang Kompatibel dengan OpenAI
remote.*diprioritaskan di atasmodels.providers.openai.*.remote.headersdigabungkan dengan header OpenAI; kunci dari remote menang jika terjadi konflik. Kosongkanremote.headersuntuk menggunakan default OpenAI.