0Pricing
AI Engineering Academy · Aula

Memória de buffer e de janela

Implemente ConversationBufferMemory e ConversationBufferWindowMemory para manter as últimas N interações no contexto e meça como o tamanho da janela afeta a coerência e o custo.

Memória de buffer e de janela é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.

Memória de buffer: mantenha tudo

A memória de buffer é a estratégia mais simples: armazene todas as mensagens de cada turno em uma lista e inclua o histórico completo em cada chamada à API. Ela preserva o contexto integral — o modelo pode fazer referência a qualquer coisa dita em qualquer momento. A desvantagem é o crescimento linear e ilimitado do contexto. Para sessões curtas, como a conclusão de uma única tarefa, a memória de buffer é perfeitamente adequada e a mais fácil de implementar.

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

Integrando a memória de buffer a uma cadeia

Para usar a memória de buffer com LCEL, conecte-a por meio de RunnableWithMessageHistory ou use ConversationChain na abordagem legada. O objeto de memória mantém o histórico, e a cadeia usa um MessagesPlaceholder no modelo de prompt para injetá-lo. Após cada invocação, a memória acrescenta automaticamente o novo turno.

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

O problema do buffer ilimitado

A memória de buffer funciona até que a conversa fique longa demais e exceda a janela de contexto do modelo. Com o contexto de 128K do GPT-4o-mini, um chat típico pode durar de 200 a 400 turnos antes de transbordar. De forma mais prática, mesmo com 50 turnos, você envia mais de 50 mil tokens por solicitação — um custo significativo. Você precisa de uma estratégia para limitar o tamanho do histórico.

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

Memória de janela: mantenha os últimos N turnos

A memória de janela mantém apenas os últimos K turnos da conversa, descartando as mensagens mais antigas. Isso limita o contexto a K * avg_tokens_per_turn, independentemente da duração da conversa. A desvantagem é que o contexto muito antigo se perde — o modelo pode esquecer coisas que o usuário disse muitos turnos antes. Para a maioria dos chatbots de uso geral, uma janela de 5 a 10 turnos oferece boa coerência a um custo aceitável.

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

Implementando a memória de janela com InMemoryChatMessageHistory

InMemoryChatMessageHistory do LangChain mantém todas as mensagens, mas você pode reduzir o histórico antes de injetá-lo no prompt. Um padrão comum é armazenar o histórico completo para fins de registro, mas passar apenas as últimas N mensagens ao LLM. Use a notação de fatias do Python em history.messages para obter a janela mais recente.

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
)

Janela baseada em tokens ou em turnos

O tamanho da janela pode ser especificado em turnos (os últimos K pares de mensagens humana/IA) ou em tokens (os últimos T tokens do histórico). A janela baseada em tokens é mais confiável porque a duração dos turnos varia — um turno com código é 10 vezes mais longo que um turno com 'sim'. O utilitário trim_messages() do LangChain é compatível com as duas estratégias e pode preservar o prompt do sistema enquanto reduz o histórico.

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

Medindo a coerência em relação ao tamanho da janela

Escolher o tamanho correto da janela exige medir como a coerência da conversa se deteriora à medida que a janela diminui. Execute um conjunto de conversas de teste em que o turno N faça referência a informações dos turnos N-5, N-10 e N-20. Teste se o modelo ainda consegue responder corretamente com janelas de 5, 10 e 20 turnos. A resposta fornece o tamanho mínimo de janela necessário para o seu caso de uso específico.

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

Combinando o prompt do sistema com a memória de janela

Ao usar a memória de janela, preserve sempre o prompt do sistema — ele define a persona e as regras da IA. Sem ele, o modelo pode perder sua persona depois que a janela ultrapassar o primeiro turno. Use a opção include_system=True nas funções de redução ou sempre insira a mensagem do sistema antes do histórico em janela no seu modelo de prompt.

# 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

Guia para decidir entre memória de buffer e de janela

Use a memória de buffer quando: as conversas forem curtas e delimitadas (uma tarefa única, um assistente de preenchimento de formulários), o contexto completo for essencial (análise jurídica, revisão de código) e o orçamento de tokens não for uma preocupação. Use a memória de janela quando: as conversas puderem ser arbitrariamente longas (atendimento ao cliente, assistentes gerais), o contexto recente for mais importante que o contexto distante e você precisar de custos de tokens previsíveis e limitados.

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

Persistindo a janela no Redis

Para uso em produção, armazene o histórico completo da conversa no Redis (para recuperação rápida) e reduza-o ao tamanho da janela no momento da leitura. O Redis com um TTL garante que as sessões antigas expirem automaticamente. Use um conjunto ordenado ou uma lista com LRANGE para buscar com eficiência apenas as últimas N mensagens, sem carregar todo o histórico.

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

Monitorando a saúde da memória em produção

Acompanhe estas métricas em produção para detectar problemas relacionados à memória: média de tokens do histórico por solicitação, para detectar sessões que estão crescendo demais; utilização da janela de contexto (emita um alerta se for superior a 80%); quantidade de sessões no armazenamento, para detectar vazamentos de memória no armazenamento de sessões; e taxa de acerto do cache para sessões recarregadas do Redis. Emita um alerta quando a média de tokens do histórico ultrapassar um limite configurável.

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

Verificação rápida

Teste sua compreensão das estratégias de memória de buffer e de janela.

Recapitulação da lição

Nesta lição, você aprendeu que: a memória de buffer preserva o histórico completo, mas cresce sem limite, sendo adequada apenas para conversas curtas e delimitadas; a memória de janela mantém apenas os últimos K turnos, garantindo um custo previsível e limitado à custa do contexto distante; e a redução baseada em tokens com trim_messages() é mais confiável que as janelas baseadas em turnos, porque o tamanho das mensagens varia. A seguir, exploraremos a memória de resumo para conversas longas e abertas.

Perguntas Frequentes

A aula “Memória de buffer e de janela” é grátis?

Sim — o texto completo de “Memória de buffer e de janela” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.

O que vou aprender em “Memória de buffer e de janela”?

Implemente ConversationBufferMemory e ConversationBufferWindowMemory para manter as últimas N interações no contexto e meça como o tamanho da janela afeta a coerência e o custo. Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Engineering Academy?

Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Memória de buffer e de janela”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Engineering Academy?

Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que LLMs sem estado precisam de memória externa
  2. Memória de buffer e de janela
  3. Memória de resumo e truncamento consciente dos tokens
  4. Persistindo o histórico de conversas no Redis e no PostgreSQL
← Voltar para AI Engineering Academy