IA · 3 min
Claude Code borra las conversaciones a los 30 días: mi base de vectores acabó siendo la única copia
Uso Claude Code como asistente del homelab, y para que se acuerde de lo que hemos hablado otros días le monté una memoria de conversaciones: cada charla se parte en trozos, se convierte en vectores y se guarda en una base que el asistente consulta cuando le pregunto «¿te acuerdas de cuando…?». Funcionaba bien. Hasta que quise mejorarla y descubrí que casi la borro entera.
La trampa: las transcripciones caducan
Claude Code guarda cada conversación en un fichero en tu disco. Lo que no sabía es que los borra él solo a los 30 días. Hay un ajuste, cleanupPeriodDays, que por defecto vale 30, y casi nadie lo toca.
Lo descubrí al cambiar el buscador de la memoria por uno mejor. La idea era sencilla: tirar la base vieja y rehacerla leyendo otra vez todas las conversaciones. Antes de dejar que el proceso escribiera, hice una copia y conté:
sesiones en la base de vectores 193
transcripciones que quedan en disco 50
sesiones que SOLO están en la base 149Tres meses de conversaciones, el 80 % de la memoria, ya no existían en ningún otro sitio. La base de vectores, que yo veía como un índice que se podía regenerar cuando quisiera, se había convertido sin que me diera cuenta en la única copia. Si llego a rehacerla «desde las transcripciones», las habría perdido para siempre.
La lección vale para cualquier índice: si lo que indexas puede desaparecer, el índice deja de ser un índice y pasa a ser el original. Y entonces hay que tratarlo como tal.
Cómo las rescaté: reindexar sin perder nada
La base guarda el texto de cada trozo junto a su vector, así que el contenido seguía ahí. Al proceso de reconstrucción le añadí un paso de rescate:
- Antes de tocar nada, copia la base entera a un fichero aparte.
- Busca las sesiones que están en la base pero ya no tienen transcripción en disco. Son las huérfanas.
- Coge el texto de esos trozos, lo vuelve a partir con las reglas nuevas y lo vectoriza con el modelo nuevo.
- Las sesiones que sí siguen en disco se procesan desde la transcripción, como siempre.
Así el cambio de buscador se hizo sin perder ni una conversación. Además, ahora la base entra en la copia nocturna que sale de casa, porque ya no es algo que se pueda regenerar.
Por qué solo vectorizo lo nuevo
El buscador viejo usaba palabras (TF-IDF) con un vocabulario limitado a las 4.096 más frecuentes. Las palabras raras, que son justo las que buscas cuando preguntas por algo concreto, ni existían para él. El nuevo usa un modelo de vectores pequeño, multilingüe y local (sin API ni coste), que encuentra la conversación por el significado aunque no compartas ni una palabra con ella.
Ese modelo corre en la CPU de un contenedor modesto, y rehacer toda la base, unos miles de trozos, tarda unos 25 minutos. Con TF-IDF rehacerlo todo cada vez daba igual; con un modelo neuronal, no. Así que la ingesta solo procesa lo nuevo: al acabar cada respuesta y, como red, cada media hora, con un cerrojo para que nunca corran las dos a la vez.
Un detalle del modelo que conviene saber: los de la familia e5 dan parecidos altos a todo. Un 0,80 es su nivel más bajo, no algo «muy parecido». Un umbral fijo no filtra nada, así que el corte es relativo: solo se quedan los resultados que sobresalen sobre la media de esa consulta. Y junto a la búsqueda por significado hay otra por palabra literal, para nombres propios y citas exactas, que es donde los vectores flojean.
El truco del venv: comparar sys.prefix, no la ruta
El modelo necesita PyTorch y sentence-transformers, que viven en un entorno virtual aparte. Pero yo quería seguir llamando a los scripts con un simple python3 recall.py "…", sin acordarme de activar nada. La solución típica es que el script se relance solo dentro del venv si no está en él:
import os, sys
VENV = "/ruta/al/venv"
if sys.prefix != VENV:
os.execv(f"{VENV}/bin/python3", [f"{VENV}/bin/python3"] + sys.argv)Mi primera versión comparaba la ruta del intérprete (sys.executable), y no saltaba nunca. Resulta que el python3 de un venv es solo un enlace al del sistema: si resuelves la ruta, las dos acaban en el mismo sitio y el script cree que ya está dentro. Lo que sí cambia es sys.prefix, que dentro del venv apunta a la carpeta del entorno. Comparando eso funciona a la primera.
Lo que me llevo
- Si usas Claude Code y te importa el historial, mira
cleanupPeriodDaysantes de que pasen 30 días. - Antes de «rehacer desde cero» cualquier índice, comprueba que el origen sigue existiendo entero.
- Cuando un derivado se convierte en la única copia, necesita la misma protección que el original: copia antes de tocarlo, guardado seguro y copia fuera de casa.