Skip to main content

Memory Management

O módulo memory_management fornece uma interface estruturada e segura para manipular a memória de sessões de conversação. Oferece métodos organizados para armazenar, recuperar e gerenciar dados da sessão com controle rigoroso de limites e suporte a objetos Pydantic estruturados.

Visão Geral

O sistema de memória funciona como um dicionário hierárquico que permite:

  • Armazenamento estruturado de dados da sessão
  • Categorização automática por tipo de informação
  • Validação com modelos Pydantic
  • Controle de limites para evitar sobrecarga
  • Operações aninhadas de qualquer profundidade

🏗️ Estrutura e Conceitos Básicos

MemoryCategories

Chaves padrão para organização da memória:

class MemoryCategories:
USER_INFO = "informacoes_usuario" # Dados pessoais do usuário
CONVERSATION_FACTS = "fatos_da_conversa" # Fatos coletados durante a conversa
WORKFLOW_PROGRESS = "progresso_workflow" # Estado de workflows em andamento
USER_PREFERENCES = "preferencias_usuario" # Preferências configuradas
CONTEXT_HINTS = "dicas_contexto" # Dicas para o LLM
Chaves Personalizadas

As categorias acima são apenas facilitadores. Você pode criar e usar qualquer chave que faça sentido para seu caso de uso:

# Exemplos de chaves personalizadas
memory_manager.update("historico_transacoes", transacoes)
memory_manager.update("configuracoes_produto", config)
memory_manager.update("dados_integracoes.api_externa", resultado)
memory_manager.update("metricas_performance", stats)

MemoryLimitExceededException

Exceção lançada quando operações excederiam o limite de memória:

try:
memory_manager.update("dados", dados_grandes)
except MemoryLimitExceededException as e:
print(f"Limite excedido: {e.attempted_chars} chars (máx: {e.max_chars})")

🔧 Métodos Principais

get(path, default=None, model_class=None)

Recupera valores da memória com suporte a caminhos aninhados e conversão para objetos Pydantic.

Parâmetros:

  • path (str|list): Caminho para o valor (ex: "usuario.documento.cpf" ou ["usuario", "documento", "cpf"])
  • default (Any): Valor padrão se não encontrar (padrão: None)
  • model_class (Type[BaseModel]): Classe Pydantic para conversão automática (opcional)

Quando utilizar:

  • Recuperar dados específicos da memória
  • Converter dados para objetos estruturados
  • Navegação em estruturas aninhadas
  • Obter valores com fallback seguro

Resultado esperado:

  • Valor encontrado no caminho especificado
  • Objeto Pydantic se model_class fornecido
  • default se caminho não existe

Exemplos:

# Recuperação simples
user_name = memory_manager.get("informacoes_usuario.nome")

# Com valor padrão
telefone = memory_manager.get("informacoes_usuario.telefone", "Não informado")

# Navegação aninhada profunda
documento = memory_manager.get("informacoes_usuario.documentos.cpf.numero")

# Conversão para objeto Pydantic
from pydantic import BaseModel

class UserInfo(BaseModel):
nome: str
email: str
telefone: str

user_obj = memory_manager.get("informacoes_usuario", model_class=UserInfo)
# Retorna: UserInfo(nome="João", email="joao@email.com", telefone="11999999999")

# Lista de caminhos
status = memory_manager.get(["progresso_workflow", "cadastro", "current_step"])

update(path, value, model_class=None)

Atualiza ou insere valores na memória com validação automática de limites.

Parâmetros:

  • path (str|list): Caminho onde inserir o valor
  • value (Any|BaseModel): Valor a ser armazenado (pode ser objeto Pydantic)
  • model_class (Type[BaseModel]): Classe para validação antes do armazenamento (opcional)

Quando utilizar:

  • Armazenar novos dados na memória
  • Atualizar informações existentes
  • Criar estruturas aninhadas automaticamente
  • Validar dados antes do armazenamento

Resultado esperado:

  • True se operação bem-sucedida
  • Estrutura aninhada criada automaticamente se necessário
  • Dados validados e convertidos se model_class fornecido

Erros:

  • MemoryLimitExceededException: Se exceder limite de memória
  • ValidationError: Se validação Pydantic falhar

Exemplos:

# Atualização simples
memory_manager.update("informacoes_usuario.nome", "João Silva")

# Criação de estrutura aninhada automática
memory_manager.update("usuario.documentos.cpf.numero", "123.456.789-00")
# Cria automaticamente: usuario -> documentos -> cpf -> numero

# Com objeto Pydantic
class UserData(BaseModel):
nome: str
idade: int
email: str

user = UserData(nome="Maria", idade=30, email="maria@email.com")
memory_manager.update("informacoes_usuario", user)

# Com validação
class DocumentoInfo(BaseModel):
tipo: str
numero: str
valido: bool = True

# Valida antes de armazenar
memory_manager.update(
"documentos.rg",
{"tipo": "RG", "numero": "12.345.678-9"},
model_class=DocumentoInfo
)

# Estruturas complexas
progress_data = {
"step": "validacao_documento",
"completed": ["dados_pessoais", "endereco"],
"next": "confirmacao"
}
memory_manager.update("progresso_workflow.cadastro", progress_data)

delete(path)

Remove valores da memória com navegação aninhada.

Parâmetros:

  • path (str|list): Caminho do valor a ser removido

Quando utilizar:

  • Limpar dados desnecessários
  • Remover informações sensíveis
  • Resetar estado de workflows
  • Limpeza seletiva da memória

Resultado esperado:

  • Valor removido (se existia)
  • None se valor não existia

Exemplos:

# Remoção simples
removed_phone = memory_manager.delete("informacoes_usuario.telefone")

# Remoção aninhada
removed_doc = memory_manager.delete("usuario.documentos.cpf")

# Remoção de workflow
progress = memory_manager.delete("progresso_workflow.cadastro")

# Limpeza de categoria inteira
all_facts = memory_manager.delete("fatos_da_conversa")

merge(path, data)

Faz merge de dicionários na memória, combinando dados existentes com novos.

Parâmetros:

  • path (str|list): Caminho onde fazer o merge
  • data (Dict|BaseModel): Dados para combinar

Quando utilizar:

  • Atualizar parcialmente estruturas existentes
  • Combinar configurações
  • Adicionar campos sem sobrescrever existentes
  • Merge de objetos Pydantic

Resultado esperado:

  • True se operação bem-sucedida
  • Dados combinados preservando valores existentes
  • Novos campos adicionados aos existentes

Erros:

  • MemoryLimitExceededException: Se exceder limite de memória

Exemplos:

# Merge básico
existing_user = {"nome": "João", "idade": 30}
memory_manager.update("informacoes_usuario", existing_user)

new_data = {"email": "joao@email.com", "telefone": "11999999999"}
memory_manager.merge("informacoes_usuario", new_data)
# Resultado: {"nome": "João", "idade": 30, "email": "joao@email.com", "telefone": "11999999999"}

# Merge de estruturas aninhadas
workflow_data = {
"cadastro": {"step": "dados_pessoais", "completed": ["inicio"]},
"onboarding": {"step": "apresentacao"}
}
memory_manager.update("progresso_workflow", workflow_data)

update_data = {
"cadastro": {"completed": ["inicio", "dados_pessoais"]},
"tutorial": {"step": "primeiro_acesso"}
}
memory_manager.merge("progresso_workflow", update_data)

# Merge com objeto Pydantic
class ContactUpdate(BaseModel):
telefone: str
endereco: str

contact = ContactUpdate(telefone="11888888888", endereco="Rua A, 123")
memory_manager.merge("informacoes_usuario", contact)

📝 Métodos de Conveniência

Fatos da Conversa

store_conversation_fact(fact, metadata=None)

Armazena fatos importantes coletados durante a conversa.

Parâmetros:

  • fact (str): Fato a ser armazenado
  • metadata (Dict): Metadados adicionais (opcional)

Quando utilizar:

  • Registrar informações importantes mencionadas pelo usuário
  • Manter histórico de decisões
  • Documentar preferências reveladas
  • Tracking de eventos da conversa

Exemplos:

# Fato simples
memory_manager.store_conversation_fact("Cliente prefere atendimento por WhatsApp")

# Com metadados
memory_manager.store_conversation_fact(
"Cliente tem urgência no processo",
metadata={"priority": "alta", "deadline": "2024-01-15"}
)

# Fatos específicos
memory_manager.store_conversation_fact(
"Cliente já possui conta em outro banco",
metadata={"banco": "Banco XYZ", "tipo_conta": "poupança"}
)

get_conversation_facts(limit=None)

Recupera fatos da conversa ordenados cronologicamente.

Parâmetros:

  • limit (int): Número máximo de fatos a retornar (opcional)

Exemplos:

# Todos os fatos
all_facts = memory_manager.get_conversation_facts()
# Retorna: [{"content": "fato1", "timestamp": "...", "metadata": {...}}, ...]

# Últimos 5 fatos
recent_facts = memory_manager.get_conversation_facts(limit=5)

# Processar fatos
for fact in recent_facts:
print(f"[{fact['timestamp']}] {fact['content']}")
if fact['metadata']:
print(f" Detalhes: {fact['metadata']}")

Informações do Usuário

store_user_info(key, value)

Armazena informações pessoais do usuário.

Exemplos:

# Informações básicas
memory_manager.store_user_info("nome", "João Silva")
memory_manager.store_user_info("email", "joao@email.com")
memory_manager.store_user_info("telefone", "11999999999")

# Informações estruturadas
endereco = {
"rua": "Rua das Flores, 123",
"cidade": "São Paulo",
"cep": "01234-567"
}
memory_manager.store_user_info("endereco", endereco)

# Documentos
memory_manager.store_user_info("cpf", "123.456.789-00")
memory_manager.store_user_info("rg", "12.345.678-9")

get_user_info(key=None)

Recupera informações do usuário.

Exemplos:

# Informação específica
nome = memory_manager.get_user_info("nome")

# Todas as informações
user_data = memory_manager.get_user_info()
# Retorna: {"nome": "João Silva", "email": "joao@email.com", ...}

# Com conversão para objeto
class User(BaseModel):
nome: str
email: str
telefone: str

user_obj = memory_manager.get("informacoes_usuario", model_class=User)

Progresso de Workflows

store_workflow_progress(workflow_name, step, data)

Armazena o progresso de workflows em andamento.

Parâmetros:

  • workflow_name (str): Nome do workflow
  • step (str): Etapa atual
  • data (Dict): Dados da etapa

Exemplos:

# Workflow de cadastro
memory_manager.store_workflow_progress(
"cadastro_cliente",
"validacao_documento",
{
"completed_steps": ["dados_pessoais", "endereco"],
"documento_enviado": True,
"documento_aprovado": False
}
)

# Workflow de onboarding
memory_manager.store_workflow_progress(
"onboarding",
"tutorial_navegacao",
{
"tutorials_completed": ["introducao", "menu_principal"],
"current_tutorial": "tutorial_navegacao",
"progress_percentage": 60
}
)

# Workflow de solicitação
memory_manager.store_workflow_progress(
"solicitacao_cartao",
"aguardando_aprovacao",
{
"tipo_cartao": "gold",
"renda_informada": 5000,
"documentos_anexados": ["comprovante_renda", "identidade"],
"protocolo": "CART-2024-001"
}
)

get_workflow_progress(workflow_name=None)

Recupera progresso de workflows.

Exemplos:

# Workflow específico
cadastro_progress = memory_manager.get_workflow_progress("cadastro_cliente")
# Retorna: {"current_step": "validacao_documento", "data": {...}, "updated_at": "..."}

# Todos os workflows
all_progress = memory_manager.get_workflow_progress()

# Verificar etapa atual
if cadastro_progress and cadastro_progress["current_step"] == "validacao_documento":
print("Cliente está na validação de documento")

🏗️ Objetos Pydantic Estruturados

Vantagens dos Objetos Pydantic

✅ Validação Automática:

class UserData(BaseModel):
nome: str
idade: int = Field(ge=0, le=120) # Entre 0 e 120 anos
email: str = Field(pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$')

# Validação automática no armazenamento
try:
memory_manager.update("usuario", UserData(nome="João", idade=-5, email="invalid"))
except ValidationError as e:
print(f"Dados inválidos: {e}")

✅ Type Safety:

# IDE detecta tipos automaticamente
user: UserData = memory_manager.get("informacoes_usuario", model_class=UserData)
print(user.nome) # ✅ IDE sabe que é string
print(user.idade + 10) # ✅ IDE sabe que é int

✅ Documentação Automática:

class DocumentInfo(BaseModel):
"""Informações de documento do usuário"""
tipo: str = Field(description="Tipo do documento (CPF, RG, CNH)")
numero: str = Field(description="Número do documento")
valido: bool = Field(default=True, description="Se o documento foi validado")
data_validacao: Optional[str] = Field(description="Data da validação")

# Schema automaticamente documentado
print(DocumentInfo.model_json_schema())

✅ Conversão Automática:

# Armazenamento automático como dict
doc = DocumentInfo(tipo="CPF", numero="123.456.789-00")
memory_manager.update("documento", doc) # Converte automaticamente para dict

# Recuperação como objeto
doc_obj = memory_manager.get("documento", model_class=DocumentInfo)
print(type(doc_obj)) # <class 'DocumentInfo'>

📝 Como a Memória é Apresentada para o LLM

Conversão Automática: Dicionário → Markdown

O sistema automaticamente converte a memória estruturada em dicionário para um formato markdown legível que o LLM pode compreender facilmente.

Como funciona:

  • Você organiza os dados em dicionário (usando os métodos do MemoryManager)
  • O sistema converte automaticamente para markdown quando necessário
  • O LLM recebe um contexto estruturado e legível

Como sua estrutura vira contexto para o LLM

Exemplos de Conversão

Exemplo 1: Dados do Usuário Simples

Entrada (Dicionário):

memory_dict = {
"informacoes_usuario": {
"nome": "João Silva",
"cpf": "123.456.789-00",
"telefone": "11999999999"
}
}

Saída (Markdown):

## Informacoes Usuario
nome: João Silva
cpf: 123.456.789-00
telefone: 11999999999

Exemplo 2: Estrutura Hierárquica

Entrada (Dicionário):

memory_dict = {
"informacoes_usuario": {
"nome": "Maria Santos",
"endereco": {
"rua": "Rua das Flores, 123",
"cidade": "São Paulo",
"cep": "01234-567",
"complemento": {
"numero": "123",
"andar": "5º andar"
}
}
}
}

Saída (Markdown):

## Informacoes Usuario
nome: Maria Santos

### Endereco
rua: Rua das Flores, 123
cidade: São Paulo
cep: 01234-567

#### Complemento
numero: 123
andar: 5º andar

Exemplo 3: Listas com Tradução Automática

Entrada (Dicionário):

memory_dict = {
"fatos_da_conversa": [
{
"content": "Cliente prefere atendimento por WhatsApp",
"timestamp": "2024-01-15T10:30:00",
"metadata": {"priority": "alta"}
},
{
"content": "Cliente tem urgência no processo",
"timestamp": "2024-01-15T10:32:00"
}
]
}

Saída (Markdown):

## Fatos Da Conversa
• Conteúdo: Cliente prefere atendimento por WhatsApp
Data/Hora: 2024-01-15T10:30:00
Informações Adicionais: {'priority': 'alta'}

• Conteúdo: Cliente tem urgência no processo
Data/Hora: 2024-01-15T10:32:00

Exemplo 4: Workflows Complexos

Entrada (Dicionário):

memory_dict = {
"progresso_workflow": {
"cadastro_cliente": {
"current_step": "validacao_documento",
"created_at": "2024-01-15T10:00:00",
"updated_at": "2024-01-15T10:45:00",
"data": {
"completed_steps": ["dados_pessoais", "endereco"],
"documento_enviado": True,
"documento_aprovado": False
}
},
"onboarding": {
"current_step": "tutorial_concluido",
"updated_at": "2024-01-15T11:00:00",
"data": {
"progress_percentage": 100,
"tutorials_completed": ["intro", "navegacao", "funcionalidades"]
}
}
}
}

Saída (Markdown):

## Progresso Workflow

### Cadastro Cliente
current_step: validacao_documento
Criado em: 2024-01-15T10:00:00
Atualizado em: 2024-01-15T10:45:00

#### Data
completed_steps: ['dados_pessoais', 'endereco']
documento_enviado: True
documento_aprovado: False

### Onboarding
current_step: tutorial_concluido
Atualizado em: 2024-01-15T11:00:00

#### Data
progress_percentage: 100
tutorials_completed: ['intro', 'navegacao', 'funcionalidades']

Exemplo 5: Lista de Strings Simples

Entrada (Dicionário):

memory_dict = {
"preferencias": {
"canais_comunicacao": ["whatsapp", "email", "telefone"],
"horarios_preferidos": ["manha", "tarde"]
}
}

Saída (Markdown):

## Preferencias

### Canais Comunicacao
- whatsapp
- email
- telefone

### Horarios Preferidos
- manha
- tarde

Regras de Apresentação para o LLM

📝 Campos Simples:

# Sua estrutura:
{"nome": "João", "cpf": "123.456.789-00"}

# Vira para o LLM:
# nome: João
# cpf: 123.456.789-00

📁 Estruturas Aninhadas:

# Sua estrutura:
{
"endereco": {
"rua": "Rua das Flores",
"numero": "123"
}
}

# Vira para o LLM:
# ## Endereco
# rua: Rua das Flores
# numero: 123

📋 Listas de Objetos:

# Sua estrutura:
{
"fatos_da_conversa": [
{"content": "Cliente prefere WhatsApp", "timestamp": "2024-01-15"},
{"content": "Tem urgência", "timestamp": "2024-01-15"}
]
}

# Vira para o LLM:
# ## Fatos Da Conversa
# • Conteúdo: Cliente prefere WhatsApp
# Data/Hora: 2024-01-15
#
# • Conteúdo: Tem urgência
# Data/Hora: 2024-01-15

Tradução Automática

Alguns campos são automaticamente traduzidos para o LLM:

  • content → "Conteúdo"
  • timestamp → "Data/Hora"
  • created_at → "Criado em"
  • updated_at → "Atualizado em"

Exemplo Prático Completo

Como você organiza:

memory_manager.store_user_info("nome", "Carlos Silva")
memory_manager.store_conversation_fact("Cliente quer conta empresarial")
memory_manager.store_workflow_progress("abertura_conta", "documentos", {
"cnpj": "12.345.678/0001-90",
"documentos_enviados": ["contrato_social"]
})

Como o LLM recebe:

## Informacoes Usuario
nome: Carlos Silva

## Fatos Da Conversa
• Conteúdo: Cliente quer conta empresarial
Data/Hora: 2024-01-15T14:30:00

## Progresso Workflow
### Abertura Conta
current_step: documentos
Atualizado em: 2024-01-15T14:31:00

#### Data
cnpj: 12.345.678/0001-90
documentos_enviados: ['contrato_social']
Dica Importante

Organize bem sua estrutura de dados - a forma como você armazena na memória é exatamente como o LLM vai interpretar o contexto. Estruturas bem organizadas resultam em contexto mais claro para o LLM tomar decisões!