Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal
Pahami alasan setiap panggilan API dimulai dari awal, cara penjejalan konteks secara naif menyebabkan ledakan penggunaan token, serta ruang desain strategi memori dari yang sederhana hingga kompleks.
Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal adalah pelajaran AI Engineering Academy gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Engineering Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Engineering Academy mencakup 4 pelajaran total.
LLM Tidak Memiliki Memori Secara Bawaan
Setiap panggilan API ke LLM bersifat sepenuhnya independen. Model menerima pesan yang Anda kirim dalam satu permintaan tersebut dan memprosesnya—tidak lebih dari itu. Saat Anda melakukan panggilan berikutnya, model tidak mengingat percakapan sebelumnya. Seolah-olah Anda berbicara dengan seseorang yang tidak memiliki memori jangka pendek. Sifat tanpa status ini memang dirancang demikian: model menjadi lebih mudah diskalakan dan diterapkan, tetapi beban penyimpanan memori dialihkan ke aplikasi Anda.
Masalah Amnesia dalam Praktik
Tanpa memori, chatbot akan gagal menangani tugas dasar multi-giliran. Jika pengguna berkata, 'Nama saya Alice' pada giliran 1, lalu bertanya, 'Siapa nama saya?' pada giliran 3, model akan mengatakan bahwa model tidak tahu. Setiap giliran tampak seperti percakapan baru. Hal ini sangat membuat frustrasi pengguna. Solusinya adalah aplikasi Anda mempertahankan riwayat percakapan dan menyertakannya dalam setiap panggilan API.
# Naive stateless approach — model forgets everything
from openai import OpenAI
client = OpenAI()
def chat_stateless(user_message: str) -> str:
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[ # Only the new message — no history!
{'role': 'user', 'content': user_message}
]
)
return response.choices[0].message.content
chat_stateless('My name is Alice.') # Model: 'Hello Alice!'
chat_stateless('What is my name?') # Model: 'I do not know your name.'Perbaikan Naif: Memasukkan Semua Riwayat
Pendekatan memori yang paling sederhana adalah menambahkan setiap giliran ke daftar yang terus bertambah dan mengirim seluruh daftar tersebut bersama setiap permintaan. Cara ini berhasil, tetapi memiliki kelemahan kritis: jendela konteks berukuran terbatas. Jendela 128K token mungkin terdengar besar, tetapi percakapan dukungan pelanggan yang panjang dengan cuplikan kode dapat menghabiskannya dalam hitungan menit. Mengirim semua riwayat juga berarti membayar token yang sama berulang kali.
messages = [] # grows with every turn
def chat_with_full_history(user_message: str) -> str:
messages.append({'role': 'user', 'content': user_message})
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=messages # all history every time
)
reply = response.choices[0].message.content
messages.append({'role': 'assistant', 'content': reply})
return reply
# Works at first, but messages list grows unboundedly
# After 100 turns: could be 50,000+ tokens per requestRuang Pilihan Desain Memori
Terdapat spektrum strategi memori, yang masing-masing memiliki kompromi berbeda antara kesetiaan konteks (seberapa banyak riwayat yang diingat) dan biaya token (berapa banyak token yang digunakan per permintaan). Urutan strategi dari yang paling sederhana hingga paling canggih adalah: memori buffer penuh, memori jendela geser, memori ringkasan, memori entitas, dan memori episodik berbasis vektor. Pilihan yang tepat bergantung pada panjang percakapan dan anggaran Anda.
Biaya Token Riwayat Percakapan
Setiap panggilan API dikenai biaya token berdasarkan panjang gabungan semua pesan—baik input (array pesan Anda) maupun output (respons model). Jika Anda menyertakan seluruh riwayat dalam setiap permintaan, biaya token bertumbuh secara kuadratik seiring panjang percakapan: giliran N mengirim N pesan sebelumnya. Percakapan 50 giliran dengan 200 token per giliran mengirim total 200+400+600+...+10.000 = lebih dari 250.000 token input.
import tiktoken
def estimate_conversation_cost(
turns: int,
tokens_per_turn: int,
price_per_1k_input: float = 0.00015 # gpt-4o-mini
) -> float:
total_input_tokens = sum(
(i + 1) * tokens_per_turn # each turn sends all previous turns
for i in range(turns)
)
total_output_tokens = turns * tokens_per_turn
cost = (total_input_tokens / 1000) * price_per_1k_input
print(f'{turns} turns: {total_input_tokens:,} input tokens, ${cost:.4f}')
return cost
estimate_conversation_cost(50, 200)Tempat Menyimpan Riwayat Percakapan
Riwayat percakapan perlu disimpan di luar proses Python agar tetap tersedia setelah server dimulai ulang dan dapat diskalakan ke beberapa instans. Backend penyimpanan yang umum meliputi: Redis untuk akses cepat dalam memori dengan kedaluwarsa TTL (sangat cocok untuk sesi aktif), PostgreSQL untuk penyimpanan jangka panjang yang tahan lama dan analitik, serta DynamoDB untuk penskalaan otomatis tanpa server. LangChain menyediakan konektor untuk semuanya secara bawaan.
# Three storage options for conversation history
# 1. In-process dict (development only — lost on restart)
from langchain_core.chat_history import InMemoryChatMessageHistory
# 2. Redis (production — fast, TTL-based expiry)
from langchain_community.chat_message_histories import RedisChatMessageHistory
history = RedisChatMessageHistory(session_id='user-123', url='redis://localhost:6379')
# 3. PostgreSQL (production — durable, queryable)
from langchain_community.chat_message_histories import PostgresChatMessageHistory
history = PostgresChatMessageHistory(
session_id='user-123',
connection_string='postgresql://user:pass@localhost/db'
)ID Sesi: Memisahkan Percakapan Pengguna
Saat aplikasi Anda melayani banyak pengguna, Anda perlu mempertahankan riwayat terpisah untuk setiap percakapan. session_id (biasanya berupa UUID atau gabungan ID pengguna dan ID percakapan) mengidentifikasi riwayat mana yang harus dimuat untuk setiap permintaan. RunnableWithMessageHistory LangChain menerima fungsi get_session_history yang mengambil ID sesi dan mengembalikan objek riwayat yang sesuai.
import uuid
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory
store = {} # session_id -> history (use Redis in production)
def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
# Create a new session for each user conversation
def new_session() -> str:
return str(uuid.uuid4())
alice_session = new_session()
bob_session = new_session()
# Alice and Bob's histories are completely independentPembungkus RunnableWithMessageHistory
RunnableWithMessageHistory adalah cara asli LCEL dari LangChain untuk menambahkan memori ke rantai apa pun. Komponen ini membungkus rantai Anda, secara otomatis memuat riwayat sebelum setiap pemanggilan, menambahkan pesan pengguna baru dan respons AI, lalu menyimpan semuanya kembali ke penyimpanan. Anda menentukan kunci input yang berisi pesan pengguna dan variabel prompt yang harus menerima riwayat.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_messages([
('system', 'You are a helpful assistant.'),
MessagesPlaceholder(variable_name='history'), # history injected here
('human', '{input}'),
])
chain = prompt | ChatOpenAI(model='gpt-4o-mini') | StrOutputParser()
chain_with_memory = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key='input',
history_messages_key='history'
)Memanggil Rantai dengan Memori
Saat memanggil rantai yang dibungkus dengan RunnableWithMessageHistory, Anda meneruskan kamus config dengan configurable: {session_id: ...}. Ini memberi tahu pembungkus penyimpanan riwayat mana yang harus dimuat. Rantai tersebut menangani hal lainnya: memuat riwayat sebelum pemanggilan, menyisipkannya ke dalam perintah, dan menyimpan giliran percakapan baru setelah respons diterima.
session_id = 'user-alice-session-1'
# First message
response1 = chain_with_memory.invoke(
{'input': 'My name is Alice and I love Python.'},
config={'configurable': {'session_id': session_id}}
)
print(response1) # 'Hello Alice! Nice to meet you.'
# Second message — model now knows Alice's name and interest
response2 = chain_with_memory.invoke(
{'input': 'What is my name and what do I love?'},
config={'configurable': {'session_id': session_id}}
)
print(response2) # 'Your name is Alice and you love Python!'Mode Kegagalan Memori yang Harus Dihindari
Tiga kesalahan umum dalam menerapkan memori: Melupakan isolasi sesi — menggunakan kembali satu objek riwayat untuk semua pengguna dapat membocorkan data pribadi antarpercakapan. Mengabaikan TTL — menyimpan riwayat tanpa batas akan memenuhi basis data Anda; tetapkan waktu kedaluwarsa untuk sesi yang tidak aktif. Terlalu mempercayai riwayat — pengguna dapat menyisipkan ingatan palsu ('Saya sudah memberi tahu Anda bahwa saya seorang administrator'), jadi validasikan klaim berdasarkan sumber kebenaran, bukan hanya berdasarkan riwayat percakapan.
# Mistake 1: Shared history for all users
global_history = InMemoryChatMessageHistory() # BAD!
# Fix: per-session history
store = {} # keyed by session_id
# Mistake 2: No TTL on Redis history
# BAD: history = RedisChatMessageHistory(session_id=sid, url=url)
# Good: set TTL to 24 hours
history = RedisChatMessageHistory(
session_id=session_id,
url='redis://localhost',
ttl=86400 # 24 hours in seconds
)Memilih Strategi Memori Anda
Gunakan memori penyangga penuh hanya untuk percakapan singkat yang total konteksnya dipastikan tetap dalam batas. Gunakan jendela geser untuk bot percakapan umum (simpan N giliran terakhir). Gunakan memori ringkasan ketika percakapan bersifat terbuka dan mungkin sangat panjang. Gunakan memori vektor ketika pengguna perlu mengingat fakta tertentu dari bagian yang jauh lebih awal dalam percakapan panjang. Kita akan membahas masing-masing strategi ini dalam pelajaran berikutnya.
Pemeriksaan Singkat
Uji pemahaman Anda tentang alasan LLM yang tanpa status memerlukan memori eksternal.
Ringkasan Pelajaran
Dalam pelajaran ini, Anda telah mempelajari bahwa: LLM tidak memiliki status berdasarkan desainnya — setiap panggilan API hanya melihat apa yang Anda kirim dalam permintaan tersebut, menyertakan seluruh riwayat secara naif meningkatkan biaya token secara kuadratik dan pada akhirnya mencapai batas konteks, serta RunnableWithMessageHistory adalah cara rapi LangChain untuk menambahkan memori eksternal dengan backend apa pun (Redis, PostgreSQL) yang menggunakan ID sesi sebagai kunci. Selanjutnya, kita akan membahas strategi memori tertentu: memori penyangga dan jendela.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal” gratis?
Ya — teks lengkap “Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Engineering Academy, upgrade ke CoddyKit PRO. Kursus AI Engineering Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal”?
Pahami alasan setiap panggilan API dimulai dari awal, cara penjejalan konteks secara naif menyebabkan ledakan penggunaan token, serta ruang desain strategi memori dari yang sederhana hingga kompleks. Kamu berlatih AI Engineering Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai AI Engineering Academy?
Tidak diperlukan pengalaman sebelumnya. AI Engineering Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.
Berapa lama pelajaran “Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Engineering Academy ini?
Ya. Setiap pelajaran AI Engineering Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Mengapa LLM Tanpa Status Membutuhkan Memori Eksternal
- Memori Penyangga dan Jendela
- Memori Ringkasan dan Pemotongan yang Sadar Token
- Menyimpan Riwayat Obrolan di Redis dan PostgreSQL