Lewati ke konten utama

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 memoriDisimpan diTujuan
Memori percakapanconversations, messagesMelanjutkan sesi, mempersistenkan giliran pengguna/asisten/tool, mempertahankan sitasi dan metadata
Memori jangka panjang penggunauser_memoryProfil singkat per pengguna (preferensi, konteks kerja) yang dibawa ke setiap percakapan berikutnya; lihat di bawah
Memori retrievaldocuments, chunks, embeddings, lexical textMemori korpus jangka panjang yang digunakan oleh retrieval
Memori auditaudit_logJejak kepatuhan untuk query, jawaban, event Pengaman Kebijakan, dan tindakan review/admin mendatang
Memori prompt/evaluasiLangfuseVersi 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:

  • userId pemilik
  • type: preference atau fact
  • satu kalimat text
  • embedding pgvector
  • importance
  • status: active, superseded, atau deleted
  • asal-usul: sourceConversationId dan sourceMessageIds

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_through di conversations.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_ATTEMPTS kali, 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_ALLOWLIST memegang 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_CONVERSATIONS aktif, karena setiap anggota membaca percakapan itu.
  • Di produksi, memori memerlukan principal terverifikasi JWT (resolver jwt; require_auth dengan 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 di citations.
  • 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 memiliki status = 'active'; baris superseded dan deleted menyimpan asal-usulnya sampai pengguna menghapusnya.
  • Status sweeper berupa dua kunci di conversations.metadata: memory_consolidated_through (waktu pesan terbaru yang sudah diproses) dan memory_extraction_failures. Sweeper yang dibatasi memakai pasangan kuncinya sendiri, memory_scoped_consolidated_through dan memory_scoped_extraction_failures, karena sweeper tanpa batasan pada database yang sama menandai percakapan yang tidak diekstraknya.
  • Migrasi 0027 menambahkan messages_createdAt_idx untuk query lookback sweeper.
  • Menghapus data satu pengguna: DELETE /memories sebagai pengguna itu, atau DELETE 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, dan memory consolidation abandoned
    • baris ai_engine_audit_log dengan "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. Baris reflection tidak 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__…)DefaultMakna
ENABLEDfalseSakelar utama. Off: tanpa sweeper, tanpa recall; rute /memories tetap berfungsi.
WRITE_ENABLED / READ_ENABLEDtrue / trueMemecah sakelar. Hanya-tulis adalah mode bayangan: memori ditulis dan dapat diperiksa, tidak dipakai jawaban.
IDLE_MINUTES30Menit tanpa pesan sebelum percakapan dianggap selesai.
SWEEP_INTERVAL_SECONDS300Seberapa sering sweeper mencari percakapan yang selesai.
SWEEP_BATCH_SIZE20Jumlah percakapan per sweep.
LOOKBACK_HOURS168Hanya percakapan yang aktif dalam rentang ini yang diproses; menyalakan fitur tidak memproses riwayat lama.
MAX_CONCURRENT_WRITES1Panggilan ekstraksi bersamaan; tetap satu per pengguna.
EXTRACT_MODEL(empty)Model untuk panggilan ekstraksi; kosong = LLM utama.
EXTRACT_TIMEOUT_SECONDS60Ekstraksi yang melewati batas waktu tidak menulis apa pun.
MAX_EXTRACTION_ATTEMPTS3Jumlah 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_MESSAGE20 / 2000Batas 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_CONVERSATION3Memori baru yang boleh ditambahkan satu percakapan.
MAX_CHARS_PER_MEMORY300Batas panjang satu memori (sekitar 40 kata).
MAX_ACTIVE_PER_USER30Memori aktif per pengguna; di atas batas ini ekstraksi harus memperbarui atau menghapus.
RECALL_TOP_K5Jumlah memori yang dibawa satu pertanyaan.
RECALL_MAX_CHARS1500Anggaran karakter blok yang disisipkan (sekitar 400 token).
WEIGHT_RELEVANCE / WEIGHT_RECENCY / WEIGHT_IMPORTANCE1.0 / 0.3 / 0.5Bobot peringkat recall.
RECENCY_HALF_LIFE_DAYS30Bobot kebaruan berkurang setengah setiap sekian hari.
SHARED_CONVERSATIONSfalseIzinkan memori pada percakapan dengan lebih dari satu penanya atau anggota.
REQUIRE_VERIFIED_PRINCIPALfalse (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​

KolomTujuan
user_idMengaitkan percakapan dengan pengguna terautentikasi atau pengguna tingkat aplikasi
titleJudul percakapan yang mudah dibaca manusia atau label yang dihasilkan
rolePeran pesan: user, assistant, system, atau tool
contentIsi pesan yang disimpan sebagai teks
source_citationsArray JSON berisi sitasi dokumen/chunk yang dilampirkan pada jawaban asisten
metadataPengaturan retrieval, hasil kebijakan, data kesesuaian sintesis, data tool-call, info channel, dan atribut sesi mendatang
timestampsUrutan 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:

  1. Muat metadata percakapan berdasarkan conversation_id dan user_id yang diotorisasi.
  2. Muat pesan terbaru berdasarkan created_at.
  3. Sertakan hanya jendela giliran terakhir yang dikonfigurasi ke dalam konteks prompt.
  4. Ambil chunk korpus secara terpisah melalui retrieval hybrid.
  5. Lampirkan sitasi dari chunk korpus, bukan dari teks memori tanpa sitasi.
  6. 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.