Membuat agent yang ingat: ringkas dan simpan riwayat percakapan, memakai thread_id untuk sesi paralel, serta LangGraph Checkpointer untuk snapshot dan resume percakapan lintas request.

Di episode 6 kalian menguasai output parsers dan output terstruktur. Tapi ada satu masalah besar yang belum kita pecahkan: model tidak punya ingatan. Setiap invoke() diperlakukan sebagai percakapan baru, padahal aplikasi chat yang bagus harus ingat siapa lawan bicaranya dan apa yang sudah dibahas. Itulah fokus episode ini.
Kita akan membangun ingatan di dua lapisan. Pertama, chat history: menyimpan, merangkum, dan menyuntikkan riwayat percakapan ke prompt. Kedua, LangGraph checkpoints: mekanisme persisten yang menyimpan seluruh state graph per thread_id, lengkap dengan kemampuan snapshot dan resume. Di akhir episode, kalian punya agent yang bisa melanjutkan percakapan walaupun aplikasi sudah restart.
LLM adalah fungsi stateless: input token masuk, output token keluar. Konteks "ingatan" yang kalian lihat di chat model hanya karena semua riwayat dikirim ulang setiap request sebagai message. Artinya, kualitas percakapan ditentukan oleh dua hal: seberapa banyak riwayat yang dikirim, dan seberapa baik riwayat itu diatur.
Dua pola umum yang dipakai:
Cara paling sederhana menangani riwayat adalah membiarkan LangGraph mengelola list messages di dalam state. Setiap percakapan mendapat thread_id sendiri, dan semua pesan baru di-append ke daftar tersebut melalui reducer bawaan add_messages.
from typing import Annotated
from langgraph.graph import StateGraph, START, END, MessagesState
graph = StateGraph(MessagesState)MessagesState adalah state khusus yang sudah dilengkapi reducer add_messages untuk field messages. Berkat reducer ini, ketika sebuah node mengembalikan pesan baru, LangGraph menggabungkannya dengan riwayat yang sudah ada — bukan menimpanya. Inilah fondasi ingatan di sisi state.
thread_id adalah identitas sebuah thread percakapan. Dengan menaruhnya di config, kalian bisa menjalankan ribuan percakapan paralel dalam satu instance tanpa saling mencampuri.
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_agent
model = ChatOpenAI(model="gpt-4o-mini")
agent = create_agent(
model=model,
tools=[],
checkpointer=MemorySaver(),
)
config_a = {"configurable": {"thread_id": "percakapan-a"}}
config_b = {"configurable": {"thread_id": "percakapan-b"}}
agent.invoke({"messages": [("human", "Halo, nama saya Arman")]}, config=config_a)
agent.invoke({"messages": [("human", "Nama saya Budi")]}, config=config_b)
hasil = agent.invoke({"messages": [("human", "Siapa nama saya?")]}, config=config_a)
print(hasil["messages"][-1].content)Karena thread percakapan-a dan percakapan-b dipisah oleh checkpointer, jawaban untuk pertanyaan "Siapa nama saya?" pada config_a adalah Arman — bukan Budi. Ini pola inti untuk layanan chat multi-user: satu thread_id per user per session.
Di balik thread_id ada checkpointer. Ia menyimpan snapshot state setelah setiap langkah graph selesai. MemorySaver menyimpan semuanya di RAM — cepat untuk pengembangan, tapi hilang saat proses mati. Untuk produksi, gunakan penyimpanan persisten.
from langgraph.checkpoint.memory import MemorySaver
from langgraph.checkpoint.sqlite import SqliteSaver
# RAM: cepat, hilang saat restart
memory_saver = MemorySaver()
# SQLite: persisten di file, cocok untuk single-node
sqlite_saver = SqliteSaver.from_conn_string("checkpoints.db")SqliteSaver menyimpan checkpoint ke file SQLite sehingga riwayat bertahan meskipun aplikasi dimulai ulang. Untuk lingkungan multi-instance yang terskalakan, PostgresSaver dari langgraph-checkpoint-postgres menjadi pilihan — kita bedah lebih dalam di episode 17 soal LangGraph lanjutan.
Warning
MemorySaver hanya untuk development. Begitu Anda butuh resume lintas restart atau horizontal scaling, segera pindah ke SqliteSaver atau PostgresSaver.
Kelebihan checkpointer adalah snapshot: kalian bisa membaca state percakapan kapan pun, dan resume dari titik terakhir tanpa harus menyalin ulang seluruh history secara manual.
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
agent = create_agent(model=model, tools=[], checkpointer=checkpointer)
config = {"configurable": {"thread_id": "thread-resume"}}
agent.invoke({"messages": [("human", "Ingat angka 42")]}, config=config)
# Snapshot: ambil riwayat lengkap thread ini
state_sekarang = checkpointer.get(config)
print(len(state_sekarang["messages"])) # jumlah pesan tersimpan
# Resume: melanjutkan tanpa kehilangan konteks
resume = agent.invoke(
{"messages": [("human", "Angka apa yang saya sebut tadi?")]},
config=config,
)
print(resume["messages"][-1].content)checkpointer.get(config) mengembalikan snapshot state thread saat itu — berguna untuk audit, pembuatan ringkasan, atau menampilkan riwayat ke frontend. Resume cukup memanggil invoke lagi dengan config yang sama; graph meneruskan dari checkpoint terakhir sehingga konteks angka 42 tetap tersedia.
Percakapan yang terlalu panjang akan memakan context window. Solusinya: kurasi riwayat dengan ringkasan. Anda bisa memotong pesan lama menjadi satu pesan ringkasan system sehingga konteks tetap terjaga tanpa membawa semua token.
from langchain_core.messages import SystemMessage, TrimMessage
from langgraph.prebuilt import create_agent
agent = create_agent(
model=model,
tools=[],
checkpointer=MemorySaver(),
before_model=TrimMessage(
strategy="last",
max_tokens=2000,
token_counter=model,
include_system=True,
),
)TrimMessage memangkas pesan tertua ketika total token melewati max_tokens, sambil tetap menyimpan pesan system. Kombinasi pemangkasan plus ringkasan berkala adalah strategi standar untuk percakapan panjang di produksi — konteks tetap ringkas dan biaya token terkendali.
Memory bukan fitur tersembunyi di dalam model, melainkan lapisan yang Anda bangun sendiri. Kalian sekarang bisa menyimpan riwayat percakapan, memisahkan sesi lewat thread_id, memakai checkpointer untuk snapshot dan resume, serta meringkas percakapan panjang agar tetap hemat token.
Inti yang harus dibawa pulang:
MessagesState dengan reducer add_messages menjadi fondasi state percakapan di LangGraph.thread_id memisahkan sesi percakapan sehingga banyak user bisa berjalan paralel tanpa tercampur.MemorySaver untuk development; SqliteSaver dan PostgresSaver untuk produksi yang persisten dan scalable.TrimMessage untuk memangkas dan ringkasan untuk memadatkan konteks.Di episode 8 kita naik kelas: Tools & Function Calling — memberi agent kemampuan bertindak lewat dekorator @tool, mengikat tools ke model dengan bind_tools, dan memahami loop pemilihan serta eksekusi tool. Sampai jumpa!