
Yo, durante mucho tiempo, pensé que los modelos de lenguaje eran para programar y poco más. Escribir código, arreglar un bug, que me explicaran una función que no terminaba de entender. Y ahí se me acababa la imaginación. Hasta que un verano monté un asistente para el viaje que hicimos por el sur de Italia, por Puglia, y me cambió la mirada. Porque tener algo que te responde dónde puedes comer, qué merece la pena ver y qué es ese monumento que tienes delante está muy bien, pero a los dos días me di de bruces con la pared de siempre, con que no recordaba absolutamente nada. Y un asistente que no recuerda nada no es un asistente, es un buscador con modales. Muy educado, muy correcto, pero cada mañana te saluda como si fuera la primera vez que te ve. Ese fue el punto de partida de Valet, el asistente en el que llevo un tiempo trabajando, y de este artículo, donde te voy a contar las cinco capas de memoria que le he ido poniendo, por qué todo cabe en un solo fichero y qué pasa cuando quieres olvidar algo. Porque eso último, te lo adelanto, es la parte difícil.
Un asistente que no recuerda nada es un buscador con modales
Cada vez que me voy de vacaciones monto algo. Unas veces un blog para ir anotando lo que queremos ver, y el blog acaba muriendo en la segunda entrada. Otras veces, como el verano pasado, me lié la manta a la cabeza y monté un asistente para que nos hiciera de guía por el sur de Italia. Le preguntabas dónde podíamos ir a comer, le preguntabas qué había que ver al día siguiente, y cuando estabas delante de una iglesia o de un monumento le preguntabas qué era eso que tenías enfrente.
Durante el viaje me di cuenta de dos cosas fundamentales. La primera fue que había puesto Matrix como centro de toda aquella herramienta y que se quedaba corto para lo que yo necesitaba. Quería que supiera siempre dónde estaba, para que luego fuera tan sencillo como preguntarle qué tengo delante, y con Matrix yo tenía que enviarle la ubicación a mano. Todo aquello se volvía un poco loco.
La segunda, y esta es la que importa hoy, fue la memoria. En cuanto me descuidaba, el asistente ya no sabía lo que habíamos hecho un momento antes, ni lo del día anterior, porque sencillamente no lo había guardado en ninguna parte. Fue una experiencia buenísima para centrarme, para ver cómo se usan las herramientas y cómo se encadenan las operaciones, pero me topé con la pared que te encuentras siempre. No recuerda nada.
Y ojo, que el listo es muy listo. Le preguntas algo y te responde de maravilla, con un estilo impecable. Pero a las dos horas, cuando ya se ha ido la ventana de contexto, le preguntas por algo reciente y no sabe ni quién eres. Es un modelo con una memoria cortísima y unas formas exquisitas, y eso no es lo que buscamos en algo que va a acompañarte durante años.
Piensa en cualquiera de esas series de televisión donde una secretaria de Estado tiene varios asistentes, incluido uno personal que le quita de encima las cosas del día a día. No es que esas tareas no tengan importancia, es que le quitan el foco de las que sí la tienen. Alguien que está al frente de un ministerio no puede estar pendiente de si hay que comprar pan. Y cuando ves ese tipo de cosas dices, ojalá tuviera yo también un asistente.
Así que, una vez probadas las mieles de tener el asistente en Puglia, decidí dar un paso más. Montar uno de verdad, con su memoria y sus herramientas, todo dentro de un contenedor Docker, con una parte en Rust en el backend y otra en React en el frontend. El frontend es lo que me resuelve los inconvenientes que tuve en el viaje, el plano con la ubicación, la distancia a los siguientes puntos, dónde está la iglesia más cercana. Hoy voy a centrarme solo en la memoria, porque es la mitad del problema.
La memoria no vive en el modelo, vive alrededor
Cuando decimos «quiero que mi asistente tenga memoria», casi todo el mundo piensa en el modelo, como si dentro del modelo hubiera un cajón donde se fuera guardando todo lo que le cuentas. Y no funciona así.
El modelo no recuerda nada entre pregunta y pregunta. Literalmente. Lo que ocurre es que tú le estás enviando toda la conversación una y otra vez, y conforme esa conversación crece, crece también lo que le mandas. En el momento en que abres una sesión nueva, todo eso se ha perdido. Si el modelo no tiene memoria, lo que tienes es un modelo muy listo con una memoria muy corta.
Entonces, ¿por qué parece que te recuerda? Porque la memoria no vive dentro del modelo, vive alrededor. Antes de que responda, hay algo que le pone delante la ficha correcta. El modelo no se sabe el guion, tiene un apuntador excelente. Y el mérito, cuando acierta, no es del actor, es del apuntador.
Y aquí entra un detalle que aprendí a base de tortas. Más contexto no es mejor contexto. Chroma evaluó dieciocho modelos frontera y todos, sin excepción, empeoraron conforme crecía la entrada, incluso con distracciones tan tontas como meter un par de frases que no venían a cuento. Anthropic lo llama presupuesto de atención y recomienda meter el conjunto más pequeño posible de tokens con señal. Vamos, que la tentación de decir «le paso todo lo que sé del usuario y que él decida» es justo la que peor funciona.
Con lo cual la pregunta correcta no es cómo hago que el modelo recuerde, sino qué le pongo delante y cuándo. Y cuando te pones a responderla, resulta que no hay una respuesta, hay cinco. Y se toman en orden, de lo mecánico a lo humano. Uno, ¿qué guardo? Dos, ¿cómo lo encuentro después? Tres, ¿cómo sé cómo eres? Cuatro, ¿qué pasó y cuándo? Y cinco, ¿cómo fue el día?
En Valet esas cinco preguntas son cinco capas, A, B, C, D y E. Las cuatro primeras se escriben en el mismo acto, o entran todas o no entra ninguna. La quinta es distinta, tiene vida propia, y ya te contaré por qué. Hoy, cuando le hablo a Valet, le estoy enviando unos quince mil tokens, y la mayor parte de eso es System Prompt, es decir, memoria inyectada.
Capa A, lo que dijiste, en bruto
La respuesta más obvia a «¿qué guardo?» es «todo». Y eso es exactamente lo que hago en la capa A, guardar la conversación en bruto, lo que yo digo y lo que responde el modelo, sin resumir y sin interpretar. Es la transcripción literal, lo que en un juicio sería la grabación completa.
Todo eso vive en SQLite, una base de datos muy sencilla, en un solo fichero. Y la capa lleva un interruptor que parece de fontanería y lo cambia todo, cada mensaje tiene una marca de «ya lo he procesado» o «todavía no». Eso, que suena a detalle tonto, es en realidad la lista de tareas del asistente, lo que aún no ha mirado y está esperando turno.
Enseguida te asalta la duda de si eso no es demasiado. ¿Guardar toda la conversación para siempre? Pues piénsalo en frío. Un día movido son cien mensajes. Al año, como mucho, treinta y seis mil. Y de todo eso, en cada consulta tú lo que vas a hacer es sacar un trozo. Lo que guardas no es lo que metes en la ventana de contexto. Eso es la gracia.
Y aquí llega la primera grieta de verdad, la incómoda. Yo creía que el problema era que guardaba poco, así que me puse a guardarlo todo. Y seguía sin servir. Porque quinientos sesenta y tres mensajes no son un recuerdo, son un montón. Guardar no es recordar. Si dentro de un año le preguntas qué te conté del viaje a Italia, no quieres que te devuelva los tres mil mensajes que habéis cruzado. Quieres que te devuelva el resumen que importa.
Capa B, fichas que se buscan por significado
Para eso hacen falta dos cosas juntas, algo que guarde el sentido y una forma de encontrarlo. La primera es la capa B. Cada vez que hay material suficiente, el asistente escribe una ficha de lo importante, con la fecha, los temas, los hechos y una síntesis de un par de frases. No guarda el ruido, guarda el sentido. Cuando empecé, el umbral que puse fue de dos mil tokens, y hoy tengo ochenta y una fichas. Te leo una de verdad, para que veas de qué hablo,
Resumen y selección de artículos de RSS pendientes. Temas, RSS, Docker Compose, cifrado de disco, monitorización de servidores, alternativas a Dropbox. Hechos y decisiones, el usuario pidió un resumen de los artículos.
Y la segunda pieza es la que hace que tu asistente parezca que recuerda. No busca por palabra, busca por significado. Imagínate un bibliotecario que no entiende de títulos sino de ideas. Le pides algo sobre el miedo a hablar en público y no te trae el libro que se titula así, te trae la carpeta de la ansiedad antes de una presentación, porque entiende que es lo mismo dicho de otra forma. Si preguntas por el coche y la ficha dice automóvil, un buscador normal no lo encuentra. Este sí.
En el mundo real esto se hace traduciendo cada ficha a una lista de números, un vector, de forma que dos textos que hablan de lo mismo acaban con números parecidos. Es la búsqueda semántica, aunque la veas por ahí con mil siglas de moda. Y hay un detalle que me parece de los más elegantes de todo el diseño. La ficha guarda los identificadores de los mensajes de los que salió, así que en cualquier momento puede desplegarse y volver a la conversación original. Es la diferencia entre un resumen y un resumen que puedes abrir.
Y fíjate en que eso no es una ocurrencia mía de fin de semana. En febrero de este año se publicó un trabajo, Lossless Context Management, que propone exactamente eso, una jerarquía de resúmenes con punteros sin pérdida a cada original, y define los resúmenes como vistas materializadas sobre el historial inmutable. La regla que lo resume es que el historial en bruto sigue siendo la única fuente de verdad. Cuando lo leí me dio bastante tranquilidad, porque es una de las dos o tres formas serias que existen de hacer esto.
Aquí tengo que hacer un hueco para la parte que no me gusta de mi propio diseño. Tengo FTS5 dentro del mismo fichero, que es la búsqueda de texto de SQLite, y en el chat estoy usando solo la búsqueda por vectores. Y la literatura dice que eso es quedarse a medias. La búsqueda densa falla justo donde acierta la literal, porque tiende a despreciar los tokens cortos y exactos, una dirección IP, un código de error, el nombre de un flag de configuración. Lo que recomiendan es búsqueda híbrida, texto más vector, fusionando los dos resultados con una técnica que se llama Reciprocal Rank Fusion. Lo tengo apuntado como la siguiente cosa que voy a meter.
Capa C, el retrato
Llegamos a la capa que más me gusta de todo el proyecto. La tercera pregunta es cómo sé cómo eres, y la respuesta se cuenta en una frase. Esta capa no guarda qué hiciste, guarda cómo eres.
Piensa en la diferencia. La capa anterior guarda que el martes fuiste al dentista, y eso es un dato que sirve para responder qué hice el martes. Esta no guarda el dentista, guarda que odias el cilantro. No son hechos de un día, son verdades sobre ti que se van destilando de todo lo que dices durante semanas. Es como cuando conoces a alguien. Al principio apuntas lo que te cuenta, y con el tiempo ya no apuntas, simplemente sabes cómo es.
Y hay una decisión de diseño que me parece muy inteligente. El asistente no puede inventarse apartados. La página tiene sus apartados ya impresos, por un lado quién eres, por otro las normas de casa, cómo quieres que se comporte, y si al reescribir decide añadir un apartado de notas varias porque le apetece, ese apartado se descarta. No entra. La estructura la fija el diseño, no el modelo. Porque a un modelo al que le dejas un folio en blanco acabas leyéndole cosas que no querías.
Y todavía mejor. Si la nueva versión de esa página no cabe, porque la ha hecho más larga de lo que debe, no se recorta, se queda la versión anterior. Prefiero una página vieja pero coherente a una nueva cortada por la mitad y llena de frases sin terminar. Son esas decisiones las que demuestran que alguien se sentó a pensar en el caso raro y no solo en el camino bonito.
¿Y cuánto cabe ahí? Hoy, diecinueve normas. Y no son abstractas, son reglas de casa destiladas de todo lo que le he pedido en tres semanas. Te pongo tres tal cual,
No inventes ni rellenes contenidos no disponibles, informa con honestidad sobre limitaciones de acceso.
Verifica antes y después de crear recordatorios o eventos.
No registres afirmaciones subjetivas o no verificables como hechos.
Ahí está también el carácter, que es el momento divertido del episodio. Valet es británico, eficiente, impecable en las formas, pero seco, irónico y mordaz. Y le pido explícitamente una cosa, nada de servilismo. Nada de «por supuesto, estaré encantado de ayudarle». A cambio, desdén elegante. El ejemplo que lleva dentro es maravilloso,
Sorprendente. Un clima digno de Londres. Le sugiero llevar paraguas, a menos que desee probar su resistencia al neumococo.
Ahí lo tienes. Te dice si hace falta paraguas, sí, pero con retranca. Y por eso esta capa importa tanto, porque es lo que convierte una herramienta en alguien con quien hablas. Una memoria persistente no guarda solo datos tuyos, guarda también cómo quieres que suene tu asistente. Y esa página se reescribió hoy mismo.
En la literatura esto tiene parientes claros. Letta, que viene de MemGPT, usa bloques de memoria de texto etiquetado que el propio agente edita. Y mem0 guarda preferencias del usuario. La diferencia que me importa es que aquí el esquema lo fija el diseño y un apartado inventado se descarta, mientras que en otros sitios el agente decide qué guarda y con qué forma.
Capa D, los hechos con fecha
La cuarta pregunta es qué pasó y cuándo, y aquí no hay párrafos. Hay hechos sueltos con la fecha pegada. Hoy tengo diez, ocho de deporte, uno social y uno de sistema. Uno de los de verdad, «Corrí 9,00 km con 119 m de desnivel y ritmo medio de 6:44 min/km». Y uno de sistema, «corregí el nombre en la ficha del asistente».
Esta capa es humilde a propósito. No te dice qué sentiste corriendo, te dice que corriste, cuánto y cuándo. No interpreta, no opina, ordena. Y tiene un detalle muy bonito. Si el mismo hecho se repite el mismo día, porque lo cuentas en dos conversaciones distintas, no se duplica. Lo apunta una vez, como harías tú al tomar notas.
Igual te preguntas por qué no basta con la capa B si también guarda lo que pasó. La B cuenta la historia de una conversación, la D es el esqueleto cronológico, hechos ordenados uno detrás de otro. Preguntar qué hice la semana pasada es una consulta de línea del tiempo, no una búsqueda semántica.
Y si quieres comparar, en sistemas como Zep o Graphiti los hechos tienen validez temporal y se superponen unos a otros, de forma que un hecho viejo queda con su fecha de fin y el nuevo ocupa su lugar. Eso es más rico que lo que tengo, hechos planos sin grafo. Es una de las cosas que sé que algún día voy a mejorar.
Capa E, el diario que se escribe solo
Y llegamos a la quinta, la que cierra el arco y, para mí, la mejor historia de todo esto. La pregunta es cómo fue el día. Fíjate en el cambio, porque las anteriores catalogan. Qué hiciste, cómo eres, qué y cuándo. Esta no pide una lista, pide un relato.
¿Alguna vez has intentado escribir un diario? Yo lo he intentado en innumerables ocasiones y he fallado siempre. El primer día escribo, «este es el comienzo de un bonito diario que me llevará lejos», y el segundo día ya no continúo. Pues piénsalo un momento. ¿Por qué tienes que hacerlo tú, si todos los días estás manteniendo una conversación con tu asistente? Que lo escriba él.
Y eso es literalmente lo que hace. Una vez al día, de madrugada, coge todo lo del día, los hechos de la línea del tiempo, los mensajes que hemos cruzado y el diario de ayer, para no repetirse, y escribe. Sin que se lo pidas. Si le he contado que he terminado el entrenamiento, lo extrae y lo guarda. Si le he preguntado cómo se cocinan esos espaguetis de arroz, pues también. Y al final del día, con todo eso delante, escribe la entrada.
Y aquí está la parte de otro nivel. Con todo delante, puede escribir el relato del día o puede decidir que ese día no tiene nada que contar. Y eso no es un error, es una respuesta válida. Existe un «no escribo» explícito, el asistente juzga si la jornada merece una entrada. Te leo un trozo de las instrucciones para que veas el tono que se le pide,
Escribe el relato del día en primera persona, como lo contaría su propio autor. Describe en vez de diagnosticar. No inventes nada que no esté en el material. Y los hechos del día ya están registrados, no los enumeres otra vez, descríbelos con tus palabras.
Descríbeme, no me hagas un informe. Y no me repitas la lista de hechos, que ya la tengo. Cuéntame cómo fue.
¿Y qué queda escrito? Hoy tengo seis entradas, del 18 al 24 de octubre, una por día como máximo, y hubo un día sin nada que contar en el que la bitácora se calló. Te leo el arranque de la primera, tal cual,
Hoy ha sido un día de esos en los que la lluvia y las decisiones se entrelazan de manera inesperada.
Y debajo los matices. Como logros, ajustar el plan de entrenamiento a la lluvia y decidir una tirada de cuarenta minutos en lugar de una larga de trece kilómetros. Como dificultad, condiciones adversas. Y etiquetas, entrenamiento, meteorología, decisiones. El ánimo, buen día. De las seis, cinco son buen día y una es neutro. O sea, no solo el qué, también el cómo te sentó.
Fíjate en un detalle del contador de llamadas al modelo que lo dice todo sin explicar nada. De mil trescientas cincuenta y cinco llamadas, seis son de la bitácora. Eso te está diciendo que esta quinta memoria no va al ritmo de la conversación, va al ritmo del día. Es una memoria con vida propia.
Esto tampoco me lo he inventado yo. Los Generative Agents de Stanford ya usaban una fase de reflexión para sintetizar memorias en ideas de nivel superior, y Letta habla de cómputo mientras duermes. Lo que no he encontrado en ningún sitio comercial es el «no escribo» explícito y el día como unidad de tiempo. Y me parece una pena, porque es lo que convierte una base de datos en un relato.
Un solo fichero, una sola transacción y la edad que reordena
Ya tienes las cinco capas. Ahora vienen las decisiones que no son de ninguna capa, sino de todas a la vez, porque lo que de verdad sostiene una memoria no está en las capas, está en cómo se guarda.
La primera es la que más me importa. Todo cabe en un solo fichero, en tu propia máquina. Lo que dijiste, las fichas, el retrato, la línea del tiempo y la bitácora viven en un único fichero SQLite. Parece un detalle y es la decisión más gorda del proyecto, porque significa que tus recuerdos no salen de tu casa. No hay un servicio al que llamar, no hay una nube a la que subir nada, no hay tres programas que levantar antes de poder preguntarle algo a tu asistente. Es un fichero, lo copias a un pendrive y te llevas tu memoria entera en el bolsillo, lo borras y no queda rastro en ningún sitio, y si mañana quieres saber qué sabe tu asistente de ti, lo abres y lo lees.
Lo que sí te digo es dónde está el techo. La pieza que uso para los vectores, sqlite-vec, está en versión pre-1.0 y su propio README avisa de que habrá cambios que rompan cosas. Su autor habla de un límite práctico para aplicaciones sensibles a la latencia en el rango de los cientos de miles de vectores. Con ochenta y una fichas estoy a años luz de ese techo, pero prefiero saber dónde está antes de que me lo encuentre.
La segunda decisión es una sola transacción. Cuando el asistente procesa lo que hemos hablado, no escribe una capa, luego otra, luego otra a ver si no falla. Escribe las cuatro capas de la vida de golpe, como un solo acto. La bitácora va por su cuenta. Si algo falla a mitad, no queda un recuerdo cojo. O está completo, o no está.
Y esto importa más de lo que parece, porque una memoria a medias es peor que no tener memoria. Si el asistente guardara que fuiste al dentista pero olvidara qué te dijo el dentista, tendrías un recuerdo partido y encima creerías que es verdad. Y una memoria en la que no puedes confiar acaba siendo un rumor.
La tercera es sutil y me parece preciosa. La edad no borra los recuerdos, los reordena. Cuando el asistente busca para contestarme, trae unos veinte recuerdos de la búsqueda semántica y después los pondera en función de cuándo se produjeron, de forma que algo reciente pesa más que algo de hace dos semanas. Lo viejo no desaparece, baja puestos en la lista.
Imagínate una biblioteca con los libros recientes en la mesa y los viejos en las estanterías del fondo. Buscas algo y el bibliotecario mira primero la mesa. Pero si lo que buscas está clarísimo que está en un libro del fondo, va al fondo y te lo trae. No te dice que ese es muy viejo y ya no lo tiene. La antigüedad cambia el orden, nunca la existencia. Y es una apuesta consciente, prefiero un recuerdo ruidoso, que me lo traiga aunque no hiciera falta, a un recuerdo perdido, que no me lo traiga cuando sí hacía falta.
El enrutador de habilidades
Hay una pieza más que no es memoria pero la sostiene, y de ella va el episodio siguiente, así que te la dejo solo apuntada porque es la que más me ha hecho pensar.
Valet tiene ahora mismo once habilidades, agenda, pendientes, recuerdos, entorno, web, widgets, running, línea del tiempo, correo, RSS y blog. Y no las tengo todas puestas de golpe. En cada turno, antes de llamar al modelo principal, hay un modelo de decisiones que responde una pregunta de sí o no por cada habilidad, «¿hace falta esta?», y devuelve una probabilidad. Las que superan un umbral se activan y solo esas herramientas se le exponen al modelo.
Lo que uso para eso no es un modelo de chat. Es Jev, de TypeSafe, que no genera texto ni trazas de razonamiento, recibe un estado y una o dos preguntas tipadas y devuelve una respuesta tipada con probabilidades. Una llamada por turno, y si falla o tarda más de ochocientos milisegundos, se exponen todas las herramientas. Eso es deliberado, el fallo reproduce el comportamiento sin router en vez de dejar al asistente manco.
Y aquí hay una comparación que me parece honesta hacer. La literatura llama a esto enrutado de herramientas y casi siempre lo resuelve con búsqueda semántica, indexando las descripciones de las herramientas y recuperando las tres o cinco mejores. Hay un caso publicado de PayPal con más de dos mil herramientas que baja el consumo de tokens de herramientas de un setenta por ciento del contexto a menos del uno por ciento. Mi enfoque es otro, es clasificación tipada, no recuperación por similitud. Con once habilidades es determinista, barato y auditable, y decidir en código con una probabilidad y un umbral es muy cómodo. Con mil, no escala. Las dos cosas son verdad a la vez y no pienso disfrazarlo.
Un par de datos de la puesta a punto que no han salido en el podcast. La primera medición sobre historial real dio un 59,1 % de cobertura, y como esta pieza lo que hace es retirar herramientas, me pareció insuficiente y la dejé apagada por defecto. En el ajuste también se cayó por los datos una hipótesis mía, resultó que los criterios escritos en español rinden mejor que en inglés en casi todo el rango. Y la varianza medida es de dos o tres puntos, así que una sola muestra no decide nada y el umbral para encenderlo tiene que ser un rango, no un número.
Lo que cuesta todo esto
Tengo una parte de la interfaz que es puro vicio, la de estadísticas. Ahí ves todas las llamadas, el consumo de tokens, y una tabla con la última llamada donde se ve exactamente qué le envías. Ahora mismo, cuando le hablo, le estoy mandando unos quince mil tokens, y la mayoría es System Prompt, o sea memoria inyectada.
La instancia lleva en marcha desde el seis de octubre, así que esto no es una demo de fin de semana, lleva casi tres semanas trabajando todos los días. Y las cifras que te doy son las de mi instancia, te las cuento como lo que son, lo que dice mi propio panel. Llevo nueve millones de tokens y eso me ha costado aproximadamente un euro. En los últimos siete días, dieciséis céntimos de dólar. Y en total, hasta la fecha, mil trescientas cincuenta y cinco llamadas al modelo.
Vale, ¿y por qué sale tan barato? Porque lo que he implementado es el uso de distintos modelos según lo que toca. Ahora mismo estoy usando DeepSeek 4.1 Flash, Qwen 3, Meta Llama y Mistral Small 24B, más el modelo de decisiones de antes. Ninguno es un modelo frontera. Son, literalmente, el suelo de precio de este año. Mistral Small 24B está en cinco céntimos por millón de tokens de entrada, y las decisiones de Jev se facturan a unos cuatro céntimos por millón de entrada con la salida gratis. Para un asistente personal que hace cientos de llamadas al día, la mayoría cortas y de extracción, la frontera del momento es de dos a tres órdenes de magnitud más cara, y no hace falta.
Y aquí está el cálculo que me parece más interesante del episodio, aunque te lo doy como estimación mía sobre precios de lista, no como una auditoría. Multiplica las llamadas de conversación por los quince mil tokens del System Prompt y tienes el orden de magnitud entero. Cuatrocientas llamadas de chat a quince mil tokens son seis millones de tokens, y seiscientas son nueve. Es decir, el gasto del asistente es, en la práctica, el precio de reenviar la memoria en cada turno. Y por eso la palanca de coste dominante es el caché de prompt, más que cambiar a un modelo más barato. DeepSeek cobra la entrada cacheada a tres milésimas de dólar por millón, cincuenta veces más barata. Con caché, los dieciséis céntimos de siete días son perfectamente alcanzables. Sin caché, la misma conversación se multiplica por cincuenta.
El titular honesto no es «una IA que cuesta un euro». Es que lo que pagas es reexpedir tu memoria cada vez que preguntas. Y de ahí salen dos consecuencias de diseño que no había visto venir. La primera, que conviene que la parte estable del System Prompt vaya siempre delante y sin cambios, para que se pueda cachear. La segunda, que meter más memoria no es gratis aunque parezca que sí, porque cada token de más se paga en cada turno, para siempre.
No hay botón de olvidar
He hablado largo de lo que el asistente recuerda. He dejado para el final lo que no puede olvidar, y quiero ser preciso, porque la frase fácil no es del todo cierta y la verdad es más incómoda.
Sí hay una herramienta para borrar un hecho de la línea del tiempo. El asistente tiene timeline_delete_event a mano, y la instrucción es explícita, borra solo cuando el usuario lo pida y confirme cuál, y localiza el identificador con timeline_get_events en el mismo turno. Por debajo, además, la API tiene endpoints de borrado por identificador para memorias y para entradas de bitácora, y hay un borrado global de la memoria persistente.
Pero nada de eso es un botón de olvidar para lo que el asistente ha aprendido de ti. No puedo decirle «aquella ficha del dentista, bórrala». No puedo borrar una norma de mi retrato. No puedo pedirle que se olvide de la entrada de bitácora del martes. No hay caducidad en los recuerdos, solo en las estadísticas. Y no hay ninguna forma de comprobar que un dato ha salido del disco. Y ojo con una trampa fina, borrar el hecho no borra el mensaje del que salió. El eco se queda.
El único botón que existe para empezar de nuevo es brutal. Borra todo. No borra un recuerdo, no borra un día, borra la memoria entera, como si acabaras de instalar el asistente y nunca le hubieras contado nada. Entre «lo recuerdo absolutamente todo, incluido lo que me arrepiento» y «no recuerdo nada de ti» no hay término medio.
Y esto no es un tecnicismo, porque la ley europea lleva años hablando del derecho al olvido. El artículo 17 del RGPD te da derecho a que supriman un dato personal concreto cuando ya no hace falta, no a que te borren la cuenta entera. Y los principios de minimización y de limitación de la conservación van justo en esa dirección, los datos se conservan solo durante el tiempo necesario. Cuando algo lo guardas para ti y no sale de tu máquina, el riesgo es distinto del de un servicio en la nube, y hay una excepción doméstica en el propio reglamento. Pero esa excepción se rompe en el momento en que el asistente sale de casa, lo usa más gente o se sincroniza con algún sitio. Y entonces tendríamos una memoria que crece sola, que no puedes podar, en un mundo donde se te exige poder podarla.
Y no me consuelo pensando que los grandes lo hacen mejor, porque no lo hacen. Un sistema de memoria popular borra el recuerdo y guarda su texto íntegro en un registro de historial, en una tabla que además no tiene identificador de usuario, así que no puedes depurar por persona a posteriori. En el asistente de moda puedes borrar memorias de una en una, pero borrar una memoria no borra la conversación de la que salió, y quien lo opera puede conservar registros de lo borrado hasta treinta días. En los asistentes que ordenan la memoria como un mapa de relaciones, si borras la conversación, el hecho que había quedado invalidado se queda marcado como invalidado. Y en la plataforma de nube más seria la caducidad mínima es de treinta y un días y el borrado va en segundo plano, con lo cual un registro ya caducado todavía puede aparecer en una lectura.
Selectivo, inmediato y verificable. Las tres cosas a la vez, hoy, no las da nadie. Que Valet no tenga botón de olvidar no lo pone por debajo de la industria, lo pone dentro.
El eco
Hay una imagen que explica mejor que nada lo que es una memoria, incluso una memoria humana. Es el eco.
Imagínate que consigues borrar el texto de un recuerdo, pero la huella que el buscador tiene anotada para poder encontrarlo se queda. Ahora pregunta por ese recuerdo. El buscador lo huele, sabe que estaba ahí, y no hay nada que leer detrás. Es exactamente la palabra en la punta de la lengua, sabes que estaba, no la alcanzas.
Y cuando me pasó a mí, pensé que era un bug mío. No lo era. La pieza sobre la que se apoya la memoria por debajo tenía un fallo documentado, titulado DELETE is not deleting vector blobs, que viene a decir «borrar no está borrando los datos», en un informe de enero del año pasado, y no se cerró hasta marzo de este año. O sea que durante mucho tiempo, la extensión que guardaba esta memoria tampoco sabía borrar.
Y hay un trabajo de investigación reciente, ojo, un preprint que todavía no ha pasado revisión por pares, que le pone nombre a los fantasmas. Sobre tres implementaciones distintas de índices vectoriales, cuando borras, el sistema solo marca el recuerdo como borrado. El dato sigue en el disco y se puede reconstruir. Con una técnica de inversión de vectores recuperaron un veinticinco por ciento de los nombres y un cuarenta y seis por ciento de las ubicaciones de vectores que ya estaban borrados. Y el fantasma sigue votando, porque en el recorrido del índice el nodo borrado se filtra de lo que te devuelve, pero no del camino por el que busca. El noventa y cinco por ciento de los conjuntos de resultados cambian entre un borrado lógico y uno real.
Dicho de otra forma, y esta es la frase que me llevo, en un almacén vectorial delete es una petición y erasure es una prueba. Hay incluso un estándar técnico que separa dos niveles, clear y purge, y recomienda el segundo siempre que se pueda. Lo que hace un DELETE de base de datos es, en el mejor de los casos, clear.
Recuerdas demasiado y por eso recuerdas peor
Y hay una última vuelta de tuerca que no tiene nada que ver con el disco y sí con la cabeza. El olvido no va solo de espacio ocupado.
En un experimento con tres agentes, el que guardaba todo rendía peor que el que no guardaba nada nuevo, un trece por ciento de acierto frente a casi un diecisiete por ciento. El que hacía una adición selectiva y estricta casi triplicaba el acierto. Y borrando de forma periódica se quedaban con un setenta por ciento menos de memoria y encima mejoraban, con unos cuatro puntos más de acierto. No es mi caso, no era un asistente conversacional, pero la dirección es esta. Un montón de recuerdos viejos compitiendo por el mismo hueco hace que los relevantes pierdan sitio.
No es que se llene el disco, es que se ensucia la señal. Recuerdas demasiado y por eso recuerdas peor.
Y ojo con la tentación de arreglarlo poniéndole fecha de caducidad a todo. Un TTL arregla «recuerda tarde», porque lo que caduca se poda solo. No arregla «recuerda mal», porque un hecho que deja de ser cierto no se vuelve falso con el tiempo, se vuelve falso porque el mundo ha cambiado en otro sitio. Eso no lo detecta ningún reloj, lo detecta una revisión explícita. Son dos problemas distintos y los resolví como si fueran uno durante bastante tiempo.
Un asistente que no olvida es alguien que nunca te perdona
Así que no dramatizo, pero tampoco lo escondo. Si algún día esto sale de mi máquina, el primer cambio no sería añadir una capa nueva. Sería un botón de olvidar de verdad, para olvidar un dato concreto. Porque un asistente que lo recuerda todo pero no sabe olvidar nada no es un buen asistente, es alguien que nunca te perdona nada.
Lo que me llevo de todo este recorrido se resume en una frase. Una memoria no es guardar cosas, es decidir qué hacer con ellas. Y la decisión más difícil no es qué guardas, es qué pasa cuando quieres olvidar.
Valet es público y tiene licencia MIT, lo tienes en github.com/atareao/valet-ai. Hoy no hemos instalado nada, eso llega en el episodio siguiente, y te dejo en las notas del episodio los cuatro ejemplos que se ejecutan sin instalar nada, con Python 3 a secas, para que veas la idea con las manos. Se ejecutan así,
cd ejemplos-la-memoria-de-valet
python3 01-un-solo-fichero.py # las cinco capas dentro de un fichero
python3 02-buscar-por-significado.py # buscar por palabra vs por significado
python3 03-la-bitacora.py # el diario que se escribe solo
python3 04-el-olvido-y-el-eco.py # el botón que falta y el eco
Y si quieres trastear con el mecanismo del «no escribo», en el ejemplo de la bitácora está en cinco líneas,
def dia_vacio(material):
"""Un día sin hechos, sin mensajes y sin nada que contar no merece entrada."""
return not material.get("hechos") and not material.get("mensajes")
Y el eco, que es todavía más corto, es esto,
# Borrado chapucero: quitamos el texto pero dejamos la huella.
del memoria.recuerdos[1]["texto"]
A partir de ahí, el buscador sigue oliendo el recuerdo por su huella y ya no hay nada que leer. Todo el problema del olvido en dos líneas.
Y poco más que contarte. Si te ha gustado el episodio y lo has disfrutado tanto como yo al grabarlo, me alegro un montón. Recuerda que este es un podcast de la red de Sospechosos Habituales, donde puedes encontrar fantásticos y maravillosos podcasts, y que me vas a encontrar también hablando de modelos de lenguaje en el último WINTABLET, que es el podcast de la red, en wintablet.info. Puedes participar en su grupo de Telegram entrando en t.me/wintabletinfo, y en el grupo de atareao con Linux buscando ese nombre, donde hablamos de Linux, de modelos de lenguaje, de inteligencia artificial, de Docker, de Podman y de contenedores, y de todo ese tipo de cosas que tanto nos gustan. Y ya puestos, dime una cosa, ¿tú le pondrías un botón de olvidar? Que la vida son dos días y uno ya ha pasado, así que disfruta como si no hubiera un mañana y, si puede ser con Linux y con Valet, mejor que mejor. Un saludo y nos escuchamos el próximo jueves. 🐧
Más información
- Valet en GitHub — El asistente completo, público y con licencia MIT
- Gist — Ejemplos del episodio 843 — Los cuatro ejemplos autocontenidos en Python 3, con las tres jornadas de la bitácora
- sqlite-vec — La extensión de búsqueda vectorial para SQLite, en versión pre-1.0 y con aviso de cambios incompatibles
- Issue #178 de sqlite-vec, «DELETE is not deleting vector blobs» — El fallo del borrado que dejaba los vectores en disco, cerrado en marzo de 2026
- LCM, Lossless Context Management — Los resúmenes como vistas materializadas sobre un historial inmutable, con punteros sin pérdida
- Compaction en Claude — El nombre estándar de lo que yo llamo colapsar, con el fallo típico de compactación documentado
- Anthropic, Effective context engineering for AI agents — El presupuesto de atención y por qué conviene el conjunto más pequeño de tokens con señal
- Chroma, Context Rot — Los dieciocho modelos frontera que empeoran conforme crece la entrada
- Búsqueda híbrida con Reciprocal Rank Fusion — Por qué el vector solo no encuentra una IP, un código de error o un flag de configuración
- Jev, modelo de decisiones de TypeSafe — El modelo tipado que uso para decidir qué habilidades hacen falta en cada turno
- Ghost Vectors — Preprint sobre vectores borrados que siguen siendo reconstruibles y tombstones que siguen votando
- Borrado de datos en Zep — Por qué un hecho invalidado se queda invalidado aunque borres el episodio
- Cómo funciona la memoria en ChatGPT — Borrado de memorias de una en una y los treinta días de retención de registros
- TTL en Amazon Bedrock AgentCore Memory — La caducidad mínima de 31 días y el borrado en segundo plano
- Rendimiento de agentes con memoria selectiva frente a memoria total — El experimento donde guardarlo todo rinde peor que no guardar nada
- Artículo 17 del RGPD, derecho de supresión — El derecho a borrar un dato concreto, no la cuenta entera
- NIST SP 800-88 Rev. 2 — La diferencia entre clear y purge, y por qué un DELETE se queda corto
- Episodio 842 — FFmpeg, afina el oído de tu IA — El episodio anterior, sobre darle sentidos al asistente
- Episodio 835 — Mi propio asistente de viaje con IA — El punto de partida de todo esto, el asistente de Puglia
- Episodio 840 — sqlite-utils, tu navaja suiza para SQLite — Cómo consultar y cacharrear con el fichero donde vive la memoria
- Episodio 841 — GraphRAG III, tus notas por fin responden — La búsqueda semántica sobre tus propias notas, en profundidad