0Pricing
AI Engineering Academy · Lekcja

Pamięć buforowa i okno kontekstu

Uczestnicy zaimplementują ConversationBufferMemory i ConversationBufferWindowMemory, aby zachowywać w kontekście ostatnich N tur rozmowy, oraz zmierzą wpływ rozmiaru okna na spójność i koszt.

Pamięć buforowa i okno kontekstu to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Pamięć buforowa: zachowaj wszystko

Pamięć buforowa to najprostsza strategia: przechowuje każdą wiadomość z każdej wymiany na liście i dołącza pełną historię do każdego wywołania API. Zapewnia kompletny kontekst — model może odwołać się do dowolnej wypowiedzi. Wadą jest liniowy, nieograniczony wzrost kontekstu. W przypadku krótkich sesji, takich jak wykonanie pojedynczego zadania, pamięć buforowa jest właściwym wyborem i najłatwiejszą opcją implementacji.

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({}))

Integracja pamięci buforowej z łańcuchem

Aby użyć pamięci buforowej z LCEL, należy podłączyć ją za pomocą RunnableWithMessageHistory albo użyć ConversationChain w starszym podejściu. Obiekt pamięci przechowuje historię, a łańcuch korzysta z elementu MessagesPlaceholder w szablonie promptu, aby ją wstrzyknąć. Po każdym wywołaniu pamięć automatycznie dopisuje nową wymianę.

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'
)

Problem z nieograniczonym buforem

Pamięć buforowa działa do momentu, gdy rozmowa stanie się zbyt długa i przekroczy okno kontekstu modelu. Przy oknie kontekstu 128K modelu GPT-4o-mini typowa rozmowa może obejmować 200–400 wymian, zanim dojdzie do przepełnienia. W praktyce już przy 50 wymianach każde żądanie może zawierać ponad 50 tys. tokenów — to znaczny koszt. Potrzebna jest strategia, która pozwoli ograniczyć rozmiar historii.

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')

Pamięć okienkowa: zachowaj ostatnie N wymian

Pamięć okienkowa zachowuje tylko ostatnich K wymian rozmowy, odrzucając starsze wiadomości. Ogranicza to kontekst do K * avg_tokens_per_turn, niezależnie od długości rozmowy. Wadą jest utrata bardzo wczesnego kontekstu — model może zapomnieć informacje podane przez użytkownika wiele wymian wcześniej. W przypadku większości chatbotów ogólnego przeznaczenia okno obejmujące 5–10 wymian zapewnia dobrą spójność przy akceptowalnym koszcie.

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 dropped

Implementacja pamięci okienkowej za pomocą InMemoryChatMessageHistory

Element InMemoryChatMessageHistory z LangChain przechowuje wszystkie wiadomości, ale historię można skrócić przed wstrzyknięciem jej do promptu. Często stosuje się wzorzec polegający na przechowywaniu pełnej historii na potrzeby logowania, a przekazywaniu do LLM tylko ostatnich N wiadomości. Aby pobrać najnowsze okno, należy użyć notacji wycinka języka Python dla history.messages.

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
)

Okno oparte na tokenach a okno oparte na wymianach

Rozmiar okna można określić w wymianach (ostatnie K par wiadomość użytkownika/AI) albo w tokenach (ostatnie T tokenów historii). Okno oparte na tokenach jest bardziej niezawodne, ponieważ długość wymian jest różna — wymiana zawierająca kod może być 10 razy dłuższa niż wymiana z odpowiedzią „tak”. Narzędzie trim_messages() w LangChain obsługuje obie strategie i może zachować prompt systemowy podczas skracania historii.

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')

Pomiar spójności a rozmiar okna

Wybór właściwego rozmiaru okna wymaga zmierzenia, jak spójność rozmowy pogarsza się wraz ze zmniejszaniem okna. Należy uruchomić serię rozmów testowych, w których wymiana N odwołuje się do informacji z wymiany N-5, N-10 i N-20. Następnie trzeba sprawdzić, czy model nadal potrafi poprawnie odpowiedzieć przy oknach obejmujących 5, 10 i 20 wymian. Wynik wskaże minimalny rozmiar okna potrzebny w konkretnym przypadku użycia.

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 results

Łączenie promptu systemowego z pamięcią okienkową

Podczas korzystania z pamięci okienkowej należy zawsze zachować prompt systemowy — definiuje on osobowość AI i obowiązujące reguły. Bez niego model może utracić swoją osobowość, gdy okno przesunie się poza pierwszą wymianę. Należy użyć opcji include_system=True w funkcjach skracających albo zawsze wstawiać wiadomość systemową przed historią objętą oknem w szablonie promptu.

# 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 window

Jak wybrać między pamięcią buforową a okienkową

Pamięć buforową należy stosować, gdy: rozmowy są krótkie i ograniczone (jednorazowe zadanie, kreator formularza), pełny kontekst ma kluczowe znaczenie (analiza prawna, przegląd kodu), a budżet tokenów nie stanowi problemu. Pamięć okienkową należy stosować, gdy: rozmowy mogą mieć dowolną długość (obsługa klienta, asystenci ogólnego przeznaczenia), najnowszy kontekst jest ważniejszy od odległego oraz potrzebne są przewidywalne i ograniczone koszty tokenów.

# 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'

Zapisywanie okna w Redis

W środowisku produkcyjnym należy przechowywać pełną historię rozmowy w Redis (aby zapewnić szybki odczyt), a przy odczycie skracać ją do rozmiaru okna. Redis z TTL gwarantuje automatyczne wygasanie starych sesji. Należy użyć posortowanego zbioru albo listy z LRANGE, aby efektywnie pobierać tylko ostatnie N wiadomości bez wczytywania całej historii.

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 history

Monitorowanie stanu pamięci w środowisku produkcyjnym

W środowisku produkcyjnym należy śledzić te metryki, aby wykrywać problemy związane z pamięcią: średnią liczbę tokenów historii na żądanie w celu wykrywania zbyt dużych sesji, wykorzystanie okna kontekstu (ostrzeżenie po przekroczeniu 80%), liczbę sesji w magazynie w celu wykrywania wycieków pamięci w magazynie sesji oraz częstotliwość trafień w pamięć podręczną dla sesji wczytywanych ponownie z Redis. Należy skonfigurować alert po przekroczeniu przez średnią liczbę tokenów historii określonego progu.

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
        pass

Szybki test

Sprawdź swoją wiedzę na temat strategii pamięci buforowej i okienkowej.

Podsumowanie lekcji

W tej lekcji nauczyłeś się, że: pamięć buforowa zachowuje pełną historię, ale rośnie bez ograniczeń, dlatego nadaje się tylko do krótkich, ograniczonych rozmów; pamięć okienkowa zachowuje jedynie ostatnie K wymian, zapewniając przewidywalny i ograniczony koszt kosztem odległego kontekstu; a skracanie na podstawie tokenów za pomocą trim_messages() jest bardziej niezawodne niż okna oparte na wymianach, ponieważ długość wiadomości jest różna. W następnej części omówimy pamięć podsumowującą dla długich, otwartych rozmów.

Często zadawane pytania

Czy lekcja „Pamięć buforowa i okno kontekstu” jest bezpłatna?

Tak — pełny tekst „Pamięć buforowa i okno kontekstu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Pamięć buforowa i okno kontekstu”?

Uczestnicy zaimplementują ConversationBufferMemory i ConversationBufferWindowMemory, aby zachowywać w kontekście ostatnich N tur rozmowy, oraz zmierzą wpływ rozmiaru okna na spójność i koszt. Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?

Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Pamięć buforowa i okno kontekstu”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?

Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Dlaczego bezstanowe LLM-y potrzebują pamięci zewnętrznej
  2. Pamięć buforowa i okno kontekstu
  3. Pamięć podsumowań i skracanie uwzględniające tokeny
  4. Trwałe przechowywanie historii czatu w Redis i PostgreSQL
← Powrót do AI Engineering Academy