Un repositorio tiene varias estructuras a la vez
Considera una pregunta relativamente simple:
¿Dónde está implementada la autenticación?
Una búsqueda léxica podría encontrar archivos que contienen auth, login o token. Una búsqueda por embeddings podría encontrar código semánticamente relacionado incluso donde esas palabras exactas no aparecen. Un índice de símbolos puede identificar implementaciones de una interfaz concreta. Un grafo de llamadas puede revelar qué componentes acaban llegando a un servicio de autenticación. El historial de Git podría mostrar que un archivo de middleware aparentemente no relacionado cambia cada vez que cambia la lógica de autenticación. Y un documento de arquitectura podría decirnos que la autenticación está deliberadamente dividida entre un servicio de borde y un servicio de identidad.
Todas estas respuestas describen el mismo repositorio. Ninguna es el repositorio.
Por eso la investigación actual sobre recuperación de repositorios se está volviendo más interesante que un simple debate de grafo contra RAG. Benchmarks recientes de recuperación de contexto para agentes de código muestran que distintas familias de recuperación rinden mejor en distintas preguntas sobre el repositorio. Los mapas de repositorio compactos, además, rinden mucho mejor de lo que cabría esperar cuando el presupuesto de contexto aprieta.
Conviene desconfiar, por tanto, de cualquier arquitectura que prometa resolver la comprensión de un repositorio con una sola representación.
Dónde los grafos ayudan de verdad
Hay, sin embargo, problemas para los que los grafos son inusualmente naturales.
Supón que una interfaz cambia. La pregunta interesante ya no es:
¿Qué archivos mencionan esta interfaz?
Se convierte en:
¿Qué depende de ella?
Eso es relacional. Una función llama a otra función. Un módulo importa otro módulo. Una clase implementa una interfaz. Un test ejercita un componente. Un paquete participa en un target de build.
Estas relaciones forman caminos, y los caminos son precisamente lo que los grafos representan bien.
Varios sistemas explotan esto directamente, y las representaciones de grafo a nivel de repositorio mejoran de forma medible las tareas con muchas dependencias. También dejan claro que un grafo no es un interruptor que de golpe resuelva el razonamiento sobre un repositorio.
Un enfoque particularmente defendible es construir grafos deterministas a partir de evidencia como imports, targets de build, tests y estructura estática. Estas aristas representan hechos que a menudo se pueden reproducir mecánicamente.
Pero la situación cambia en cuanto pasamos de grafos de código a grafos de conocimiento.
La parte seductora de los grafos semánticos
Un grafo estructural puede decirle a un agente que validateContact llama a normalizeAddress. Pero quizá la pregunta real es:
¿Ya tenemos validación de email en algún sitio de este repositorio?
La función relevante podría llamarse checkContactFormat. No hace falta ninguna coincidencia léxica. Puede que ni siquiera haya un camino de llamadas obvio desde el código que se está editando ahora mismo.
Esto motiva añadir una capa semántica: conceptos, entidades de dominio y capacidades del sistema.
Eso está cerca de la arquitectura con la que estamos experimentando en ForgeAI. El diseño actual separa la información estructural del repositorio de los conceptos a nivel de dominio y las capacidades de más alto nivel, de modo que el sistema puede preguntar qué sabe hacer ya el software en lugar de solo qué símbolos existen.
Pero hay un coste escondido dentro de esa abstracción. Alguien —o algún modelo— tiene que decidir que checkContactFormat pertenece al concepto validación de email.
En cuanto permitimos aristas semánticas inferidas, nuestro grafo deja de ser una representación de hechos y se convierte en una mezcla de hechos e hipótesis. Eso puede seguir siendo extremadamente útil. Pero la distinción no debería desaparecer.
Por qué los embeddings son difíciles de reemplazar
La recuperación vectorial resuelve otro problema, y lo resuelve bien. Los embeddings son malos diciéndonos con certeza que la función A llama a la función B. Pero son útiles cuando no conocemos el vocabulario que usa el repositorio.
Un desarrollador pregunta sobre «lógica de reintento de facturación». El código la llama recoverFailedCharge. La recuperación semántica puede cerrar esa brecha sin que nadie haya tenido que codificar de antemano una arista IMPLEMENTS -> billing_retry.
Esto hace que los embeddings sean atractivos para el descubrimiento. Los grafos se vuelven atractivos en cuanto las relaciones importan. La búsqueda léxica sigue siendo atractiva cuando los identificadores dan pistas fuertes. Y la exploración pura del sistema de archivos sigue siendo útil cuando el agente necesita entender detalles de implementación locales.
La dirección más creíble, por tanto, no es grafos contra embeddings. Es recuperación híbrida.
Hay otro problema: los grafos envejecen mal
Toda representación derivada introduce sincronización. Renombra un símbolo. Mueve una clase. Cambia una dependencia. Divide un servicio. Modifica la configuración en tiempo de ejecución.
Algunos grafos se pueden actualizar de forma determinista y barata. Otros requieren reinterpretación semántica. Cuanta más inteligencia codifiquemos en la representación, más cara puede volverse su mantenimiento.
Esto crea un compromiso arquitectónico fácil de subestimar. Puedes gastar computación antes de que el agente empiece a trabajar, manteniendo continuamente un modelo de repositorio rico. O puedes gastar computación durante la tarea, dejando que el agente explore el repositorio en bruto.
Ninguna opción es gratis. Un sistema que trabaja sobre millones de líneas de código puede beneficiarse enormemente del precómputo. Un repositorio pequeño puede que no.
La respuesta probable es la recuperación adaptativa
La dirección actual más interesante es evitar por completo forzar al agente a elegir un único paradigma de recuperación.
Cuando el agente pregunta «¿qué llama a esto?», usa aristas estructurales. Cuando pregunta «¿dónde hemos resuelto algo parecido?», usa recuperación semántica o procedimental. Cuando pregunta «¿qué se rompe si cambio esto?», combina estructura de dependencias, tests y posiblemente historial. Cuando pregunta «¿ya existe esta capacidad?», usa una mezcla de recuperación semántica, conocimiento de dominio y evidencia estructural.
El problema de ingeniería se convierte en decidir qué fuente de evidencia debería responder a qué pregunta.
El verdadero mapa del repositorio
La metáfora de un «mapa del código» es útil, pero los mapas en sí mismos son el contraejemplo. No hay un mejor mapa de la Tierra. Un mapa de carreteras es excelente para conducir y terrible para entender las lluvias. Un mapa geológico muestra relaciones que un mapa político ignora deliberadamente. Un plano de metro distorsiona la geografía física para hacer la conectividad más fácil de razonar.
Los repositorios son iguales. Un grafo de llamadas, un índice de embeddings, una tabla de símbolos, el historial de Git y un modelo de dominio son mapas distintos del mismo territorio.
Así que ya no creo que la pregunta más interesante sea si los agentes de código necesitan grafos de conocimiento. Probablemente los necesiten para algunas cosas. Lo que necesitan más es la capacidad de saber cuándo un grafo es el mapa correcto que usar.