¿Un agente de código ahorra tokens recordando cambios anteriores? Así busca Singularity
Ayer le pediste a un agente de programación que añadiera un atajo de teclado en un repositorio. Hoy necesitas un cambio parecido. El agente quizá vuelva a buscar los mismos archivos, leer las mismas pruebas y tropezar con dificultades que ya había encontrado. Es lógico pagar el coste de investigar algo por primera vez. Pero ¿por qué deberíamos pagarlo otra vez?
Descubrí Singularity en una publicación de Show HN. El proyecto de código abierto pretende transformar cambios de código ya completados en flujos de trabajo reutilizables: qué archivos tocar, cómo comprobar el resultado y qué errores evitar. Ante una tarea nueva, busca pasos que podrían ser útiles y se los ofrece al agente.
La idea es interesante, aunque mi pregunta era otra: una vez recuperado un recuerdo, ¿qué demuestra que sigue siendo válido para la tarea y el repositorio actuales?
Inspeccioné Singularity en el commit 9d241f2 e hice una pequeña prueba sintética que no llama a ningún modelo. Conviene delimitar el alcance desde el principio: no instalé Singularity para probar su CLI de extremo a extremo, ni comparé costes reales de tokens en Claude Code o Codex. Reproduje de forma independiente una parte de las reglas de coincidencia descritas en el código para investigar sus posibles fallos.
No conserva todo el chat: intenta recordar el camino
Según el README del commit fijado, Singularity acumula experiencias después de modificaciones correctas y utiliza un modelo para condensar experiencias repetidas en flujos de trabajo. Un flujo podría señalar qué archivos suelen intervenir en una función, qué comandos de prueba conviene ejecutar y dónde fallaron intentos anteriores.
No es lo mismo que almacenar una conversación entera. Un chat incluye numerosas exploraciones que solo fueron útiles en aquel momento; un flujo de trabajo procura extraer pasos que merezca la pena repetir. Aquí analizo la recuperación de esos pasos mediante pistas textuales, no todos los mecanismos de caché que el proyecto pueda tener. Aunque un recuerdo apunte a un archivo que existía antes, habrá que verificarlo de nuevo si cambia el repositorio.
También hay que separar dos costes. Aprender un flujo de trabajo puede requerir llamadas a un modelo. Seleccionar pasos a partir de pistas previamente generadas puede hacerse sin él. La vía workflows-cues está diseñada para este segundo caso.
Eso no significa que todo Singularity sea gratuito en términos de modelo. En el código de evaluación fijado, StepSelector.ts llama a un modelo para decidir qué pasos son aplicables. En cambio, Memory.ts presenta workflows-cues como una selección de pistas sin modelo. Una ruta consulta al modelo y otra compara frases previamente preparadas. Tienen estructuras de coste distintas, pero no medí latencia ni consumo total de tokens de ambas rutas sobre tareas reales.
Qué hace realmente la búsqueda sin modelo
Seguí la implementación de apps/cli/src/workflows/Cues.ts.
El procedimiento básico es directo: normaliza el texto de la tarea respecto a las mayúsculas y minúsculas, intenta retirar cláusulas negativas con palabras como not, never o without, y comprueba si el texto restante contiene frases de activación preparadas para un flujo. Se selecciona un flujo si coincide una pista positiva y no coincide ninguna pista de exclusión. Los pasos individuales también pueden filtrarse por sus propias pistas.
Esta parte no pregunta a un modelo si dos tareas tienen un significado parecido. Funciona más como una tabla de reglas de coincidencia de cadenas, con ventajas claras: rapidez, poco coste y resultados reproducibles. El precio es que compartir palabras no implica compartir intención.
Imaginemos que la frase de activación es keyboard shortcut. «Add a keyboard shortcut» debería coincidir. «Review keyboard shortcuts in documentation only» contiene las mismas palabras, pero solo pide revisar documentación, no modificar una función.
El código atiende algunas negaciones explícitas. Eso no equivale a entender todas las negaciones complejas, condiciones implícitas o intenciones expresadas en varias frases. El buscador devuelve recuerdos candidatos, pero por sí solo no demuestra que ejecutar sus pasos sea correcto.
Cinco entradas artificiales para comprobar el límite
Tomé como referencia el Cues.ts fijado y reescribí manualmente y de forma independiente la lógica central de normalización, eliminación de cláusulas negativas y coincidencia de pistas positivas y negativas. La prueba usa únicamente la biblioteca estándar de Node.js. No es la suite oficial ni asegura cubrir todos los casos extremos del proyecto. No instalé Singularity, conecté ningún modelo ni trabajé sobre un repositorio de código real.
El script y los resultados legibles por máquina se conservaron en registros de investigación privados; no hay una copia pública descargable. Estos son los cinco resultados observados. Hablamos de una reproducción sintética de reglas inspiradas en el código, no de una prueba integral de la CLI.
| Entrada artificial | Resultado | Qué muestra |
|---|---|---|
| Añadir un atajo de teclado | Coincide | Recuperación esperada |
| Arreglar la conexión de la base de datos | No coincide | Se excluye una tarea no relacionada |
| Indicar expresamente que no se añada un atajo | No coincide | La negación simple funciona |
| Revisar únicamente el texto sobre atajos en la documentación | Coincide | Las palabras compartidas pueden producir un falso positivo |
| Añadir un atajo cuando el archivo recordado ya fue eliminado | Coincide | El buscador no comprueba que exista el archivo |
Definí las expectativas antes de ejecutar la prueba y según las reglas simplificadas. Una tarea relacionada debería coincidir; una tarea ajena o expresamente negada, no. En cambio, un texto que solo menciona atajos en documentación seguiría conteniendo la frase activadora. También esperaba coincidencia cuando el archivo antiguo se hubiera eliminado, porque la regla no consulta el sistema de archivos.
Las cinco aserciones dieron el resultado previsto. Pero las últimas dos son comportamientos indeseables introducidos a propósito. «5/5 superadas» no es una tasa de acierto ni demuestra que cinco tareas reales se completaran correctamente. Solo indica que las predicciones para este buscador sintético se observaron.
El ejemplo de la ruta antigua me preocupa especialmente. El emparejamiento de texto de cueChoice no sabe si un archivo se ha movido, eliminado o refactorizado. Es posible que el agente posterior vuelva a consultar el repositorio y detecte el problema; aun así, el recuerdo obsoleto puede haber aparecido primero. Encontrar un recuerdo es una sugerencia, no una prueba del estado actual del código.
Cómo interpretar los ahorros de tokens del README
El autor publicó una comparación de tareas de Excalidraw. En una tarea larga estrechamente relacionada con la memoria aprendida, los tokens comunicados pasaron de unos 1,90 millones a 423.000, el coste de aproximadamente 0,81 a 0,30 dólares y la mediana de turnos de 28,5 a 9,5. Cada condición tenía solo unas tres o cuatro ejecuciones y la evaluación se concentró en pocos repositorios.
Son cifras interesantes, pero siguen siendo resultados que el autor comunica para tareas concretas. Los cambios nuevos o una corrección pequeña que solo se hace una vez podrían ahorrar mucho menos. Aprender los flujos también cuesta.
Reducir tokens dedicados a leer archivos tampoco garantiza que disminuya el coste global del desarrollo. Recuperar una ruta equivocada puede requerir nuevas investigaciones, y una memoria anterior a una refactorización importante puede provocar más trabajo.
No repetí las comparaciones con modelos del autor ni medí tokens o gastos reales. Por eso no calculo un porcentaje independiente de ahorro. Para hacerlo haría falta ejecutar las mismas tareas reales con memoria y sin ella, contando llamadas de aprendizaje, reparaciones tras recuperaciones erróneas y coste hasta terminar cada tarea. Mi prueba no proporciona esos datos.
Cómo usaría yo esta memoria
En repositorios con operaciones repetidas, estructura relativamente estable y comandos de verificación previsibles, probaría una memoria de flujos de trabajo. Pero trataría cada recuerdo como un índice que hay que comprobar, nunca como una instrucción que el agente deba seguir a ciegas.
Un registro útil podría incluir el commit de origen, las rutas implicadas, la fecha de la última verificación y las condiciones de aplicación. Antes de seguirlo, comprobaría que los archivos sigan existiendo y que los comandos de prueba todavía sean válidos. Si varios recuerdos llevan repetidamente a correcciones manuales, reaprendería o desactivaría ese flujo. Estas son precauciones que propongo, no capacidades que haya verificado en la versión actual de Singularity.
Tampoco decidiría instalar un sistema de memoria basándome únicamente en un porcentaje espectacular. Si cada encargo usa otros repositorios, lenguajes y problemas, mantener recuerdos puede resultar menos rentable de lo esperado.
Me gustaría ver una comparación pública con el mismo conjunto de tareas reales que incluya recuperaciones útiles, falsos positivos, recuerdos obsoletos, coste de aprendizaje y coste total de finalización. Solo así sabremos si la memoria realmente elimina exploraciones repetidas o si traslada parte de ese coste al mantenimiento del propio recuerdo.
Fuentes: repositorio de Singularity · código fijado del buscador de pistas · resultados y límites declarados por el autor