Memori Jangka Panjang
Memori Jangka Panjang adalah kapabilitas platform yang memungkinkan pengguna melanjutkan percakapan sebelumnya dan memungkinkan AI menggunakan giliran sebelumnya sebagai konteks sambil menjaga jawaban akhir tetap berbasis sumber dokumen yang diambil.
Jenis memori
| Jenis memori | Disimpan di | Tujuan |
|---|---|---|
| Memori percakapan | conversations, messages | Melanjutkan sesi, mempersistenkan giliran pengguna/asisten/tool, mempertahankan sitasi dan metadata |
| Memori jangka panjang pengguna | user_memory | Profil singkat per pengguna (preferensi, konteks kerja) yang dibawa ke setiap percakapan berikutnya; lihat di bawah |
| Memori retrieval | documents, chunks, embeddings, lexical text | Memori korpus jangka panjang yang digunakan oleh retrieval |
| Memori audit | audit_log | Jejak kepatuhan untuk query, jawaban, event Pengaman Kebijakan, dan tindakan review/admin mendatang |
| Memori prompt/evaluasi | Langfuse | Versi prompt, trace, dataset evaluasi, catatan LLM-as-judge |
Memori jangka panjang per pengguna
Memori percakapan berakhir bersama percakapannya. Memori jangka panjang membawa profil singkat setiap pengguna ke setiap percakapan berikutnya (ADR-0047; KAK §2 "memori jangka panjang yang aman dan berbasis semantik"). Memori disimpan di user_memory (migrasi 0004/0005). Setiap baris menyimpan satu memori:
userIdpemiliktype:preferenceataufact- satu kalimat
text embeddingpgvectorimportancestatus:active,superseded, ataudeleted- asal-usul:
sourceConversationIddansourceMessageIds
Apa yang disimpan:
- preferensi: bahasa, panjang, format, dan tingkat detail jawaban
- konteks kerja: regulasi, sektor, atau dataset yang sering ditanyakan
- fakta yang dibagikan pengguna tentang dirinya
Apa yang tidak pernah disimpan:
- fakta tentang dokumen atau hukum (itu diambil dan dikutip)
- klaim pengguna tentang hukum
- apa pun tentang orang lain
- data pribadi sensitif
Kapan ditulis. Percakapan dianggap selesai setelah IDLE_MINUTES tanpa pesan.
- Sweeper berjalan di dalam proses API (produksi menjalankan satu replika API).
- Sweeper mencatat
memory_consolidated_throughdiconversations.metadata, sehingga percakapan yang dilanjutkan hanya memproses giliran barunya. - Ekstraksi melihat giliran penanya sendiri dan balasan yang lolos Policy Guard, tidak pernah passage hasil retrieval itu sendiri. Balasan dipotong menjadi 500 karakter dan dapat mengutip teks korpus: prompt ekstraksi melarang menyimpan fakta korpus, dan judge recall diinstruksikan untuk menolaknya.
- Balasan yang rusak, ID memori yang tidak dikenal, atau batas yang terlampaui tidak menulis apa pun.
- Jika model sedang tidak tersedia, percakapan dibiarkan untuk sweep berikutnya, paling banyak
MAX_EXTRACTION_ATTEMPTSkali, sehingga gangguan singkat tidak menghilangkan apa pun dan percakapan yang selalu gagal tidak menghambat antrean. - Hanya satu proses yang menjalankan sweep pada satu database dalam satu waktu (advisory lock Postgres), dan penulisan memori setiap percakapan dilakukan dalam satu transaksi. Sweeper yang dibatasi
SUBJECT_ALLOWLISTmemegang lock sendiri, sehingga tidak pernah menunda sweeper tanpa batasan.
Siapa yang mendapat memori. Memori dikaitkan dengan penanya setiap pesan (messages.metadata.author_id).
- Subject sentinel bersama yang dipakai pemanggil tanpa identitas tidak mendapat memori.
- Percakapan dengan lebih dari satu penanya, atau di workspace dengan lebih dari satu anggota, tidak mendapat memori kecuali
SHARED_CONVERSATIONSaktif, karena setiap anggota membaca percakapan itu. - Di produksi, memori memerlukan principal terverifikasi JWT (resolver
jwt;require_authdengan header klaim yang dapat dipalsukan ditolak).
Bagaimana jawaban memakainya. Memori masuk ke satu pesan sistem sebagai latar untuk nada, format, dan cakupan, bukan sebagai bukti. Pengguna yang belum memiliki memori mendapat catatan singkat, sehingga "apa yang kamu ingat tentang saya?" dijawab "belum ada yang disimpan" alih-alih "saya tidak bisa mengingat antar percakapan". Selama penulisan aktif, nama atau detail pekerjaan yang tidak ada di catatan maupun di percakapan dijawab "mungkin belum tersimpan" (catatan baru ditulis setelah percakapan menganggur), tidak pernah "saya tidak menyimpan nama"; data pribadi yang sensitif tidak pernah disimpan. Memori ditulis dalam bahasa yang dipakai pengguna. Judge terpisah memeriksa setiap kalimat yang menyatakan ulang memori; judge itu hanya melihat kalimat tersebut dan catatan memori.
- Kalimat yang didukung dikutip sebagai
kind: "memory"di claim map, tidak pernah dicitations. - Kalimat yang ditolak tidak ditampilkan.
Kendali pengguna. GET /memories menampilkan memori aktif pengguna; DELETE /memories/{id} dan DELETE /memories menghapusnya secara permanen (API). Penghapusan juga menghapus baris yang sudah digantikan. Meminta asisten melupakan sesuatu hanya menutup baris itu; teksnya tetap ada sampai dihapus di sini. Menghapus percakapan tidak menghapus memori yang ditulis darinya.
Yang dilihat penguji. Memori baru ada setelah percakapannya diam selama IDLE_MINUTES ditambah paling lama satu SWEEP_INTERVAL_SECONDS, sekitar 35 menit secara default. Untuk demo atau UAT, setel IDLE_MINUTES=2 dan SWEEP_INTERVAL_SECONDS=30. Meminta asisten "lupakan X" di chat juga baru berlaku setelah percakapan itu diam; DELETE /memories/{id} berlaku seketika.
Untuk administrator database.
- Baris disimpan di
user_memory. Baris aktif memilikistatus = 'active'; barissupersededdandeletedmenyimpan asal-usulnya sampai pengguna menghapusnya. - Status sweeper berupa dua kunci di
conversations.metadata:memory_consolidated_through(waktu pesan terbaru yang sudah diproses) danmemory_extraction_failures. Sweeper yang dibatasi memakai pasangan kuncinya sendiri,memory_scoped_consolidated_throughdanmemory_scoped_extraction_failures, karena sweeper tanpa batasan pada database yang sama menandai percakapan yang tidak diekstraknya. - Migrasi
0027menambahkanmessages_createdAt_idxuntuk query lookback sweeper. - Menghapus data satu pengguna:
DELETE /memoriessebagai pengguna itu, atauDELETE FROM user_memory WHERE "userId" = '<uuid>'. - Pemantauan:
SELECT status, count(*) FROM user_memory GROUP BY status- baris log API
memory consolidated,memory extraction rejected,memory extraction unavailable, danmemory consolidation abandoned - baris
ai_engine_audit_logdengan"entityType" = 'user_memory'
- Sebelum mengaktifkan pada database yang pernah menjalankan fitur #110 yang sudah dihapus, periksa sisa baris:
SELECT type, status, count(*) FROM user_memory GROUP BY 1, 2. Barisreflectiontidak pernah ditampilkan, tetapi ikut terhapus bersama penggunanya.
Konfigurasi. Setiap pengaturan adalah variabel lingkungan; memori mati secara default. Di produksi, memori aktif (tulis dan baca) sejak 19 Oktober 2026. JWT mitra kini aktif: memori memakai subjek token yang telah diverifikasi dan mewajibkan ACEH_RAG_MEMORY__REQUIRE_VERIFIED_PRINCIPAL=true. Nilai deployment produksi di repositori mempertahankan pengaturan ini.
Env var (ACEH_RAG_MEMORY__…) | Default | Makna |
|---|---|---|
ENABLED | false | Sakelar utama. Off: tanpa sweeper, tanpa recall; rute /memories tetap berfungsi. |
WRITE_ENABLED / READ_ENABLED | true / true | Memecah sakelar. Hanya-tulis adalah mode bayangan: memori ditulis dan dapat diperiksa, tidak dipakai jawaban. |
IDLE_MINUTES | 30 | Menit tanpa pesan sebelum percakapan dianggap selesai. |
SWEEP_INTERVAL_SECONDS | 300 | Seberapa sering sweeper mencari percakapan yang selesai. |
SWEEP_BATCH_SIZE | 20 | Jumlah percakapan per sweep. |
LOOKBACK_HOURS | 168 | Hanya percakapan yang aktif dalam rentang ini yang diproses; menyalakan fitur tidak memproses riwayat lama. |
MAX_CONCURRENT_WRITES | 1 | Panggilan ekstraksi bersamaan; tetap satu per pengguna. |
EXTRACT_MODEL | (empty) | Model untuk panggilan ekstraksi; kosong = LLM utama. |
EXTRACT_TIMEOUT_SECONDS | 60 | Ekstraksi yang melewati batas waktu tidak menulis apa pun. |
MAX_EXTRACTION_ATTEMPTS | 3 | Jumlah sweep yang boleh gagal pada satu percakapan sebelum ditandai selesai tanpa ekstraksi, sehingga percakapan yang selalu gagal tidak menghambat antrean. |
EXTRACT_MAX_MESSAGES / EXTRACT_MAX_CHARS_PER_MESSAGE | 20 / 2000 | Batas transkrip per penanya. Setiap pertanyaan sejak sapuan terakhir dibaca, yang terbaru lebih dulu, dalam anggaran setengah dari EXTRACT_MAX_MESSAGES × EXTRACT_MAX_CHARS_PER_MESSAGE karakter (20.000 secara bawaan; masing-masing dipotong ke EXTRACT_MAX_CHARS_PER_MESSAGE); balasan hanya dalam EXTRACT_MAX_MESSAGES pesan terakhir. |
MAX_NEW_PER_CONVERSATION | 3 | Memori baru yang boleh ditambahkan satu percakapan. |
MAX_CHARS_PER_MEMORY | 300 | Batas panjang satu memori (sekitar 40 kata). |
MAX_ACTIVE_PER_USER | 30 | Memori aktif per pengguna; di atas batas ini ekstraksi harus memperbarui atau menghapus. |
RECALL_TOP_K | 5 | Jumlah memori yang dibawa satu pertanyaan. |
RECALL_MAX_CHARS | 1500 | Anggaran karakter blok yang disisipkan (sekitar 400 token). |
WEIGHT_RELEVANCE / WEIGHT_RECENCY / WEIGHT_IMPORTANCE | 1.0 / 0.3 / 0.5 | Bobot peringkat recall. |
RECENCY_HALF_LIFE_DAYS | 30 | Bobot kebaruan berkurang setengah setiap sekian hari. |
SHARED_CONVERSATIONS | false | Izinkan memori pada percakapan dengan lebih dari satu penanya atau anggota. |
REQUIRE_VERIFIED_PRINCIPAL | false (prod template: true) | Memori hanya untuk penanya terverifikasi JWT; menolak start jika memori aktif kecuali require_auth menyala dengan resolver jwt. |
SUBJECT_ALLOWLIST | [] | Daftar JSON UUID kanonis. Jika diisi: hanya subjek ini yang mendapat memori (recall, penulisan, dan sweeper, yang lalu memakai penanda progres dan lock sendiri). Subjek yang tidak terdaftar tidak melihat memori di GET /memories dan tidak menghapus apa pun. Hanya mempersempit; tidak pernah melonggarkan REQUIRE_VERIFIED_PRINCIPAL. Memori tanpa REQUIRE_VERIFIED_PRINCIPAL menolak start kecuali daftar ini diisi, di produksi atau saat SECURITY__REQUIRE_AUTH=false. Dipakai oleh API uji aistudio tanpa JWT (amandemen ADR-0047). |
Skema memori percakapan
conversations (
id,
user_id,
title,
metadata,
created_at,
updated_at
)
messages (
id,
conversation_id,
role,
content,
source_citations,
metadata,
created_at
)
Platform mempersistenkan percakapan, pesan pengguna, pesan asisten, sitasi jawaban, dan metadata untuk Pengaman Kebijakan dan sintesis.
Apa yang disimpan
| Kolom | Tujuan |
|---|---|
user_id | Mengaitkan percakapan dengan pengguna terautentikasi atau pengguna tingkat aplikasi |
title | Judul percakapan yang mudah dibaca manusia atau label yang dihasilkan |
role | Peran pesan: user, assistant, system, atau tool |
content | Isi pesan yang disimpan sebagai teks |
source_citations | Array JSON berisi sitasi dokumen/chunk yang dilampirkan pada jawaban asisten |
metadata | Pengaturan retrieval, hasil kebijakan, data kesesuaian sintesis, data tool-call, info channel, dan atribut sesi mendatang |
| timestamps | Urutan pembuatan dan pembaruan untuk resume dan retensi |
Model organisasi
Memori diorganisasi berdasarkan pengguna, percakapan, dan pesan berurutan. Database mengindeks conversations.user_id dan (messages.conversation_id, messages.created_at) sehingga daftar sesi dan pemuatan pesan kronologis efisien.
Perilaku target:
Memory builder menggunakan jendela konteks last-N yang dapat dikonfigurasi, dengan default 10 pesan.
Strategi retrieval dan indexing
Memori percakapan tidak sama dengan retrieval korpus. Retrieval korpus mengindeks chunk dokumen di pgvector dan PostgreSQL full-text search. Memori percakapan terutama bersifat kronologis dan dibatasi pengguna, dengan kemungkinan penambahan peringkasan atau indexing semantik di masa depan jika percakapan menjadi besar.
Urutan retrieval yang direkomendasikan:
- Muat metadata percakapan berdasarkan
conversation_iddanuser_idyang diotorisasi. - Muat pesan terbaru berdasarkan
created_at. - Sertakan hanya jendela giliran terakhir yang dikonfigurasi ke dalam konteks prompt.
- Ambil chunk korpus secara terpisah melalui retrieval hybrid.
- Lampirkan sitasi dari chunk korpus, bukan dari teks memori tanpa sitasi.
- Persistenkan pesan pengguna dan asisten baru dengan metadata retrieval, kebijakan, dan kesesuaian.
Ini membuat memori jangka panjang tetap berguna tanpa membiarkan riwayat chat tanpa sitasi menjadi sumber kebenaran yang tidak didukung.
Siklus hidup pembaruan
Publikasi query yang terkonfirmasi menyimpan giliran percakapan, jawaban asisten, sitasi sumber, dan event audit untuk penanganan kebijakan, query, dan jawaban. Pengecualian persistensi timeout mengikuti ADR-0041.
Kebijakan retensi
Kebijakan retensi untuk riwayat percakapan dan log audit dapat dikonfigurasi dan bersifat konservatif: simpan secukupnya untuk melanjutkan sesi, audit, dan evaluasi, sambil tetap memungkinkan penghapusan atau pengarsipan berdasarkan kebijakan.
Dimensi kebijakan yang direkomendasikan:
- Durasi retensi berdasarkan kelas data: konten percakapan, sitasi, event audit, trace, unggahan, riwayat review OCR.
- Legal hold dan pengecualian audit untuk kepatuhan pemerintah.
- Perilaku penghapusan atau anonimisasi pengguna ketika kebijakan mengizinkannya.
- Jalur pengarsipan ke OBS untuk percakapan lama jika tekanan penyimpanan PostgreSQL meningkat.
- Pemisahan yang jelas antara menghapus tampilan percakapan dan mempertahankan event audit yang tidak dapat diubah.
Keamanan dan akses
Memori Jangka Panjang harus menghormati RBAC dan ABAC. Pengguna hanya boleh melihat percakapan dan pesan yang berhak mereka akses. Sitasi dokumen dalam pesan lama harus tetap diperiksa otorisasinya karena akses tingkat dokumen dapat berubah setelah jawaban dibuat.
Aturan keamanan:
- Batasi daftar percakapan berdasarkan pengguna terautentikasi dan peran.
- Periksa akses dokumen sebelum merender sitasi tersimpan atau menggunakan kembali chunk.
- Pertahankan log audit append-only dari perspektif aplikasi.
- Simpan metadata sebagai JSON terstruktur, bukan blob teks prompt yang melewati pemeriksaan kebijakan.
- Jangan perlakukan riwayat percakapan sebagai instruksi tepercaya; dokumen yang di-ingest dan giliran sebelumnya masih dapat mengandung prompt injection.
Integrasi dengan platform AI
Memori Jangka Panjang terintegrasi pada service layer, bukan sebagai fitur khusus frontend. UI chatbot memanggil endpoint API; backend memuat memori, mengambil chunk korpus, memanggil model, menerapkan Pengaman Kebijakan, menyimpan pesan, dan mengaudit hasil.
Synthesizer tetap harus mengembalikan sitasi sumber dari chunk yang diambil. Memori dapat memperjelas intent pengguna, tetapi tidak menggantikan retrieval berbasis sumber.