Memori Penyangga dan Jendela
Terapkan ConversationBufferMemory dan ConversationBufferWindowMemory untuk mempertahankan N giliran terakhir dalam konteks, lalu ukur pengaruh ukuran jendela terhadap koherensi dan biaya.
Memori Penyangga dan Jendela adalah pelajaran AI Engineering Academy gratis di CoddyKit. Ini adalah pelajaran 2 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.
Memori Penyangga: Simpan Semuanya
Memori penyangga adalah strategi paling sederhana: simpan setiap pesan dari setiap giliran dalam sebuah daftar dan sertakan seluruh riwayat dalam setiap panggilan API. Strategi ini mempertahankan konteks secara sempurna — model dapat merujuk pada apa pun yang pernah dikatakan. Kekurangannya adalah konteks bertambah secara linear tanpa batas. Untuk sesi singkat seperti menyelesaikan satu tugas, memori penyangga sangat sesuai dan paling mudah diterapkan.
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(
return_messages=True, # return Message objects, not a string
memory_key='history' # key to inject into prompt template
)
# Add messages manually
memory.chat_memory.add_user_message('What is a neural network?')
memory.chat_memory.add_ai_message('A neural network is a system of layers...')
# Load what will be injected
print(memory.load_memory_variables({}))Mengintegrasikan Memori Penyangga dengan Rantai
Untuk menggunakan memori penyangga dengan LCEL, hubungkan memori tersebut melalui RunnableWithMessageHistory atau gunakan ConversationChain untuk pendekatan lama. Objek memori menyimpan riwayat, sedangkan rantai menggunakan MessagesPlaceholder dalam templat perintah untuk menyisipkannya. Setelah setiap pemanggilan, memori secara otomatis menambahkan giliran baru.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
def get_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chain = (
ChatPromptTemplate.from_messages([
('system', 'You are helpful.'),
MessagesPlaceholder('history'),
('human', '{input}')
])
| ChatOpenAI(model='gpt-4o-mini')
| StrOutputParser()
)
with_memory = RunnableWithMessageHistory(
chain, get_history,
input_messages_key='input',
history_messages_key='history'
)Masalah pada Penyangga Tanpa Batas
Memori penyangga berfungsi sampai percakapan menjadi terlalu panjang dan melampaui jendela konteks model. Dengan konteks 128K milik GPT-4o-mini, percakapan biasa mungkin berlangsung selama 200–400 giliran sebelum meluap. Secara lebih praktis, bahkan pada 50 giliran, Anda mengirim lebih dari 50 ribu token per permintaan — biaya yang cukup besar. Anda memerlukan strategi untuk membatasi ukuran riwayat.
import tiktoken
enc = tiktoken.encoding_for_model('gpt-4o-mini')
def count_history_tokens(messages: list) -> int:
total = 0
for msg in messages:
total += len(enc.encode(msg.content))
total += 4 # per-message overhead
return total
# Check how big the history has grown
history = store.get('session-1')
if history:
token_count = count_history_tokens(history.messages)
print(f'History size: {len(history.messages)} messages, {token_count} tokens')Memori Jendela: Simpan N Giliran Terakhir
Memori jendela hanya menyimpan K giliran percakapan terakhir dan membuang pesan yang lebih lama. Strategi ini membatasi konteks pada K * avg_tokens_per_turn, terlepas dari lamanya percakapan. Imbalannya adalah konteks yang sangat awal akan hilang — model mungkin melupakan hal-hal yang dikatakan pengguna beberapa giliran sebelumnya. Untuk sebagian besar bot percakapan serbaguna, jendela berukuran 5–10 giliran memberikan koherensi yang baik dengan biaya yang wajar.
from langchain.memory import ConversationBufferWindowMemory
# Keep last 5 turns (10 messages: 5 user + 5 assistant)
memory = ConversationBufferWindowMemory(
k=5, # number of TURNS to keep (each turn = user + AI)
return_messages=True,
memory_key='history'
)
# After 10 turns, only turns 6-10 will be in context
# Turns 1-5 are silently droppedMenerapkan Memori Jendela dengan InMemoryChatMessageHistory
InMemoryChatMessageHistory milik LangChain menyimpan semua pesan, tetapi Anda dapat memangkas riwayat sebelum menyisipkannya ke dalam perintah. Pola yang umum adalah menyimpan seluruh riwayat untuk pencatatan, tetapi hanya meneruskan N pesan terakhir ke LLM. Gunakan notasi irisan Python pada history.messages untuk memperoleh jendela terbaru.
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables import RunnableLambda
WINDOW_SIZE = 10 # last 10 messages (5 turns)
def get_windowed_history(session_id: str):
full_history = store.get(session_id, InMemoryChatMessageHistory())
store[session_id] = full_history
return full_history
# In the chain, trim before injecting
def trim_history(messages):
return messages[-WINDOW_SIZE:] if len(messages) > WINDOW_SIZE else messages
# Use in prompt with trimming
from langchain_core.messages import trim_messages
trimmer = trim_messages(
max_tokens=2000,
strategy='last',
token_counter=ChatOpenAI(model='gpt-4o-mini'),
include_system=True
)Jendela Berbasis Token vs Berbasis Giliran
Ukuran jendela dapat ditentukan dalam giliran (K pasangan manusia/AI terakhir) atau dalam token (T token terakhir dari riwayat). Pengaturan jendela berbasis token lebih andal karena panjang giliran bervariasi — giliran yang berisi kode bisa 10 kali lebih panjang daripada giliran yang berisi 'ya'. Utilitas trim_messages() milik LangChain mendukung kedua strategi dan dapat mempertahankan perintah sistem saat memangkas riwayat.
from langchain_core.messages import trim_messages, SystemMessage, HumanMessage, AIMessage
# Token-based trimming — keep last 1000 tokens of conversation
trimmer = trim_messages(
max_tokens=1000,
strategy='last', # keep most recent messages
token_counter=len, # approximate: count characters / 4
include_system=True, # always include the system prompt
allow_partial=False, # don't split a message in half
start_on='human' # start window on a human message
)
trimmed = trimmer.invoke(all_messages)
print(f'Trimmed to {len(trimmed)} messages')Mengukur Koherensi dibandingkan Ukuran Jendela
Memilih ukuran jendela yang tepat memerlukan pengukuran tentang bagaimana koherensi percakapan menurun saat ukuran jendela diperkecil. Jalankan serangkaian percakapan uji ketika giliran N merujuk pada informasi dari giliran N-5, N-10, dan N-20. Uji apakah model masih dapat menjawab dengan benar menggunakan jendela 5, 10, dan 20 giliran. Hasilnya memberi tahu ukuran jendela minimum yang diperlukan untuk kasus penggunaan spesifik Anda.
def test_reference_at_distance(chain_with_memory, distances=[5, 10, 20]):
results = {}
for distance in distances:
session_id = f'test-dist-{distance}'
# Fill with filler turns
for i in range(distance):
chain_with_memory.invoke(
{'input': f'Turn {i}: filler message'},
config={'configurable': {'session_id': session_id}}
)
# Ask about something said at the start
first_msg = 'Recall that the user said the magic word is AZURE.'
response = chain_with_memory.invoke(
{'input': 'What was the magic word?'},
config={'configurable': {'session_id': session_id}}
)
results[distance] = 'AZURE' in response.upper()
return resultsMenggabungkan Perintah Sistem dengan Memori Jendela
Saat menggunakan memori jendela, selalu pertahankan perintah sistem — perintah ini menentukan persona dan aturan AI. Tanpanya, model mungkin kehilangan personanya setelah jendela bergeser melewati giliran pertama. Gunakan opsi include_system=True dalam fungsi pemangkasan, atau selalu sisipkan pesan sistem sebelum riwayat berjendela dalam templat perintah Anda.
# Always put system prompt BEFORE the windowed history
prompt = ChatPromptTemplate.from_messages([
('system', 'You are a Python tutor. Always explain with code examples.'),
MessagesPlaceholder('history'), # windowed history injected here
('human', '{input}'),
])
# The system prompt is never trimmed — only the history window is managed
# This ensures the model's persona is always present regardless of windowPanduan Memilih Memori Penyangga atau Jendela
Gunakan memori penyangga ketika: percakapan singkat dan terbatas (tugas satu kali, panduan pengisian formulir), konteks lengkap sangat penting (analisis hukum, peninjauan kode), dan anggaran token bukan masalah. Gunakan memori jendela ketika: percakapan dapat berlangsung tanpa batas tertentu (dukungan pelanggan, asisten umum), konteks terbaru lebih penting daripada konteks yang jauh, dan Anda memerlukan biaya token yang dapat diprediksi serta terbatas.
# Decision matrix in code
def choose_memory_strategy(
expected_turns: int,
max_context_tokens: int = 128000,
avg_tokens_per_turn: int = 200
) -> str:
buffer_tokens = expected_turns * avg_tokens_per_turn
if buffer_tokens < max_context_tokens * 0.5:
return 'buffer' # Safe to keep everything
elif expected_turns <= 20:
return 'window_10' # Keep last 10 turns
else:
return 'summary' # Need summarization for long convos
print(choose_memory_strategy(5)) # 'buffer'
print(choose_memory_strategy(50)) # 'window_10'
print(choose_memory_strategy(200)) # 'summary'Menyimpan Jendela ke Redis
Untuk penggunaan produksi, simpan seluruh riwayat percakapan di Redis (untuk pengambilan cepat) dan pangkas riwayat tersebut ke ukuran jendela saat dibaca. Redis dengan TTL memastikan sesi lama kedaluwarsa secara otomatis. Gunakan set terurut atau daftar dengan LRANGE untuk mengambil hanya N pesan terakhir secara efisien tanpa memuat seluruh riwayat.
from langchain_community.chat_message_histories import RedisChatMessageHistory
def get_windowed_redis_history(session_id: str, window: int = 10):
# RedisChatMessageHistory stores all messages
history = RedisChatMessageHistory(
session_id=session_id,
url='redis://localhost:6379',
ttl=3600 # 1 hour TTL
)
# Trim to window size in-memory before use
all_msgs = history.messages
if len(all_msgs) > window * 2: # window turns = window*2 messages
history.messages = all_msgs[-(window * 2):]
return historyMemantau Kesehatan Memori dalam Produksi
Lacak metrik berikut dalam produksi untuk menemukan masalah terkait memori: rata-rata token riwayat per permintaan untuk mendeteksi sesi yang tumbuh terlalu besar, pemanfaatan jendela konteks (berikan peringatan jika > 80%), jumlah sesi di penyimpanan untuk mendeteksi kebocoran memori dalam penyimpanan sesi, dan rasio keberhasilan tembolok untuk sesi yang dimuat kembali dari Redis. Berikan peringatan ketika rata-rata token riwayat melewati ambang yang dapat dikonfigurasi.
import time
from langchain_core.callbacks import BaseCallbackHandler
class MemoryMonitorCallback(BaseCallbackHandler):
def on_chain_start(self, serialized, inputs, **kwargs):
history = inputs.get('history', [])
token_estimate = sum(len(m.content.split()) * 1.3 for m in history)
if token_estimate > 50000:
print(f'WARNING: Large history {token_estimate:.0f} estimated tokens')
def on_chain_end(self, outputs, **kwargs):
# Log usage for dashboards
passPemeriksaan Singkat
Uji pemahaman Anda tentang strategi memori penyangga dan jendela.
Ringkasan Pelajaran
Dalam pelajaran ini, Anda telah mempelajari bahwa: memori penyangga mempertahankan seluruh riwayat tetapi terus bertambah tanpa batas, sehingga hanya cocok untuk percakapan singkat yang terbatas, memori jendela hanya menyimpan K giliran terakhir untuk menghasilkan biaya yang dapat diprediksi dan terbatas dengan mengorbankan konteks yang jauh, serta pemangkasan berbasis token dengan trim_messages() lebih andal daripada jendela berbasis giliran karena panjang pesan bervariasi. Selanjutnya, kita akan membahas memori ringkasan untuk percakapan panjang yang terbuka.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Memori Penyangga dan Jendela” gratis?
Ya — teks lengkap “Memori Penyangga dan Jendela” 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 “Memori Penyangga dan Jendela”?
Terapkan ConversationBufferMemory dan ConversationBufferWindowMemory untuk mempertahankan N giliran terakhir dalam konteks, lalu ukur pengaruh ukuran jendela terhadap koherensi dan biaya. 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 2 dari 4.
Berapa lama pelajaran “Memori Penyangga dan Jendela” 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