|
|
import time
|
|
|
import logging
|
|
|
import numpy as np
|
|
|
from sklearn.metrics.pairwise import cosine_similarity
|
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - CURATOR - %(levelname)s - %(message)s")
|
|
|
|
|
|
class MemoryCuratorHeuristic:
|
|
|
"""
|
|
|
Implementa a curadoria de memória baseada em uma fórmula heurística (RFR-Score),
|
|
|
conforme a arquitetura proposta por Ada.
|
|
|
Este sistema é determinístico, rápido e escalável.
|
|
|
"""
|
|
|
def __init__(self, shorestone_memory, llm_agent=None, alpha=0.5, beta=0.3, gamma=0.2, lambda_decay=0.01):
|
|
|
"""
|
|
|
Inicializa o Curador.
|
|
|
:param shorestone_memory: A instância ativa do sistema de memória ShoreStone.
|
|
|
:param llm_agent: (Opcional) A instância do agente LLM para o modo híbrido.
|
|
|
:param alpha: Peso da Frequência (F).
|
|
|
:param beta: Peso da Recência (R).
|
|
|
:param gamma: Peso da Relevância Geométrica (G).
|
|
|
:param lambda_decay: Taxa de decaimento para o score de Recência. Controla quão rápido o esquecimento acontece.
|
|
|
"""
|
|
|
self.memory = shorestone_memory
|
|
|
self.llm_agent = llm_agent
|
|
|
|
|
|
|
|
|
self.ALPHA = alpha
|
|
|
self.BETA = beta
|
|
|
self.GAMMA = gamma
|
|
|
self.LAMBDA = lambda_decay
|
|
|
|
|
|
logging.info("Curador de Memória Heurístico iniciado com sucesso.")
|
|
|
|
|
|
def _calculate_score(self, mem_meta, mem_embedding, all_embeddings, all_ids):
|
|
|
"""Calcula o RFR-Score para uma única memória."""
|
|
|
|
|
|
|
|
|
access_count = mem_meta.get('access_count', 0)
|
|
|
f_score = np.log(1 + access_count)
|
|
|
|
|
|
|
|
|
now = time.time()
|
|
|
last_accessed = mem_meta.get('last_accessed_at', now)
|
|
|
days_since_access = (now - last_accessed) / (24 * 60 * 60)
|
|
|
r_score = np.exp(-self.LAMBDA * days_since_access)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
similarities = cosine_similarity(mem_embedding.reshape(1, -1), all_embeddings)[0]
|
|
|
|
|
|
nearest_indices = np.argsort(similarities)[::-1][1:6]
|
|
|
|
|
|
if len(nearest_indices) > 0:
|
|
|
|
|
|
g_score = np.mean(similarities[nearest_indices])
|
|
|
else:
|
|
|
g_score = 0
|
|
|
|
|
|
|
|
|
final_score = (self.ALPHA * f_score) + (self.BETA * r_score) + (self.GAMMA * g_score)
|
|
|
|
|
|
return final_score
|
|
|
|
|
|
def run_maintenance_cycle(self, t_delete=0.2, t_archive=0.4):
|
|
|
"""
|
|
|
Executa um ciclo de verificação, pontuação e poda da memória.
|
|
|
"""
|
|
|
logging.info("Iniciando ciclo de manutenção da memória...")
|
|
|
collection = self.memory.collection
|
|
|
if not collection or collection.count() == 0:
|
|
|
logging.info("Nenhuma memória para manter.")
|
|
|
return
|
|
|
|
|
|
|
|
|
all_mems = collection.get(include=["metadatas", "embeddings"])
|
|
|
|
|
|
if len(all_mems['ids']) < 10:
|
|
|
logging.info("Poucas memórias, pulando ciclo de manutenção.")
|
|
|
return
|
|
|
|
|
|
all_ids = all_mems['ids']
|
|
|
all_embeddings = np.array(all_mems['embeddings'])
|
|
|
all_metadatas = all_mems['metadatas']
|
|
|
|
|
|
ids_to_delete = []
|
|
|
|
|
|
logging.info(f"Avaliando {len(all_ids)} memórias...")
|
|
|
for i in range(len(all_ids)):
|
|
|
mem_id = all_ids[i]
|
|
|
mem_meta = all_metadatas[i]
|
|
|
mem_embedding = all_embeddings[i]
|
|
|
|
|
|
score = self._calculate_score(mem_meta, mem_embedding, all_embeddings, all_ids)
|
|
|
|
|
|
|
|
|
if score < t_delete:
|
|
|
|
|
|
if "meu criador" in mem_meta.get('text', '').lower() or "gabriel yogi" in mem_meta.get('text', '').lower():
|
|
|
logging.warning(f"SCORE BAIXO [{score:.2f}] para memória potencialmente fundamental '{mem_id}'. IGNORANDO EXCLUSÃO.")
|
|
|
continue
|
|
|
|
|
|
logging.info(f"Memória '{mem_id}' marcada para exclusão com score [{score:.2f}]")
|
|
|
ids_to_delete.append(mem_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ids_to_delete:
|
|
|
logging.info(f"Excluindo {len(ids_to_delete)} memórias obsoletas...")
|
|
|
collection.delete(ids=ids_to_delete)
|
|
|
logging.info("Exclusão concluída.")
|
|
|
else:
|
|
|
logging.info("Nenhuma memória atingiu o threshold para exclusão. Ciclo concluído.") |