Inyecté memoria 1.112 veces y no sé si sirvió para algo

Hay una idea que aparece siempre que alguien construye un sistema con agentes: darle memoria. Que aprenda de lo que ya pasó, que no repita los mismos errores, que acumule experiencia entre sesiones.
La construí en mayo. Para junio se estaba inyectando 1.112 veces en 30 días. Y cuando fui a evaluarla, me encontré con que no tenía forma de responder la pregunta más básica: ¿sirve?
Qué hace exactamente
El sistema guarda dos tipos de cosas. Patrones que funcionaron —formas de resolver algo que dieron buen resultado— y fallas conocidas —cosas que salieron mal, para no repetirlas—. Al momento de medir había 127 patrones y 180 fallas registradas.
Cuando un agente arranca una tarea, el sistema busca en esa base lo que se parezca al trabajo que está por hacer y se lo inyecta en el contexto. La búsqueda es por similitud de trigramas, con un umbral de 0,30 y un tope de tres resultados por consulta.
Es simple, es barato y funciona sin errores. Ese último punto resultó ser el problema.
El componente que nunca se queja
Todo lo demás en el sistema entra en mi lista de cosas a revisar porque hace ruido. El control de calidad falla y frena una tarea. El watchdog mata un proceso. Un agente se queda sin turnos. La cola se traba. Cada uno de esos eventos genera una señal que me obliga a mirarlo.
La memoria, no. Se inyecta, el agente trabaja, la tarea se cierra. No hay error, no hay alerta, no hay nada que revisar. Se volvió invisible por buen comportamiento.
Y así pasó un mes largo con más de mil inyecciones acumuladas, sin que nadie —yo— se preguntara si esas inyecciones estaban mejorando algo o simplemente ocupando espacio en el contexto de cada agente.
La respuesta técnica de manual, y por qué no la tomé
Cuando finalmente me senté a mirarla, la primera reacción fue la obvia: la búsqueda por trigramas es primitiva, habría que pasar a embeddings.
Es cierto que es primitiva. Compara secuencias de caracteres, no significado. Es la clase de retrieval que cualquiera reemplazaría hoy por una búsqueda vectorial, y hay librerías para hacerlo en una tarde.
No lo hice, y creo que fue la decisión correcta. Mejorar la recuperación sin una métrica de impacto es apostar a ciegas, y encima pagando: los embeddings tienen costo por consulta, así que estaría gastando más para mejorar algo que ni siquiera sé si aporta.
La pregunta correcta no era "¿cómo hago mejor el retrieval?" sino "¿el retrieval está haciendo alguna diferencia?". Y esa segunda pregunta no la había hecho nunca.
La infraestructura para medirlo ya existía
Acá viene lo que más me sorprendió: podía medirlo, y no lo sabía.
Cada inyección de memoria guarda el identificador de la sesión en la que ocurrió. Eso, que había puesto ahí sin pensarlo demasiado, habilita un experimento natural: hay sesiones con memoria inyectada y sesiones sin ella, sobre el mismo sistema, en el mismo período, haciendo trabajo comparable.
Es un A/B que ya está corriendo hace meses. Solo faltaba mirarlo.
El cruce que hay que hacer es contra dos cosas que también están registradas: los incidentes de cada sesión y el resultado del control de calidad. Las preguntas son concretas. ¿Las sesiones con memoria inyectada repiten menos lecturas del mismo archivo? ¿Hacen menos búsquedas que no encuentran nada? ¿Aprueban más seguido en el primer intento?
Si la respuesta es sí, la memoria sirve y ahí sí tiene sentido invertir en mejorar el retrieval, con el costo justificado por el efecto medido.
La pregunta que casi nadie se hace
Pero hay un tercer resultado posible, y es el que me parece más interesante: que la memoria no mueva la aguja.
Si ese fuera el caso, la conclusión correcta no es mejorarla. Es hacer lo contrario: subir el umbral de similitud, bajar el tope de resultados, inyectar menos. Porque cada inyección tiene un costo que sí es seguro —ocupa contexto, y el contexto es finito— contra un beneficio que sería nulo.
Eso es lo incómodo de medir en serio: uno de los resultados posibles es que haya que desarmar algo que costó trabajo construir. Creo que la resistencia a medir viene bastante de ahí, y no de la dificultad técnica.
El criterio que me quedó
Un componente que nunca falla no es lo mismo que un componente que sirve. Son dos cosas distintas y es fácil confundirlas, porque en el día a día operás por excepción: mirás lo que se queja.
Ahora, antes de agregar cualquier pieza nueva al sistema, trato de responder de antemano: ¿cómo se vería el mundo si esta pieza no existiera? Si no tengo forma de contestarlo, no es que la pieza esté mal — es que voy a quedar atado a ella sin poder justificarla nunca.
Con la memoria llegué tarde a esa pregunta. Llevo 1.112 inyecciones y sigo sin la respuesta.
Lo que vino después
Para julio el sistema corría rápido y verificaba bien. Pero cada tarea seguía costando cerca de una hora de controles antes de poder cerrarse, y eso hacía que el backlog avanzara a paso de tortuga.
El problema ya no era qué chequear. Era otro, más incómodo: qué debía frenar el trabajo y qué no. De eso trata la próxima entrega.