Saltar al contenido
Volver a todas las notas knowledge · 9 min

Grafo de conocimiento vs búsqueda vectorial para código: cuándo gana cada uno

Embeber todo el codebase y confiar en que vuelvan los trozos buenos es lo que hace todo el mundo. Funciona, hasta que la pregunta va de relaciones y no de parecido.

búsqueda vectorial

  • recupera por parecido
  • recall difuso
  • barato de montar
  • tira las aristas

grafo de conocimiento

  • recupera por relación
  • multi-salto exacto
  • análisis de impacto
  • guarda la procedencia
Dos formas de recuperar código: una encuentra lo que se parece, la otra recorre las aristas que el embedding tiró.
nota de campo 9 min

El movimiento por defecto, cuando quieres que un agente entienda un codebase, es embeberlo entero. Trocea los ficheros, conviértelos en vectores, guárdalos, y en la consulta trae de vuelta los trozos que más se parecen a la pregunta. Esto es retrieval-augmented generation, y para código es lo primero a lo que casi todo el mundo echa mano.

Funciona más veces de lo que los escépticos admiten. También falla de una forma concreta y repetible que ninguna mejora de embeddings arregla, porque el fallo no va de calidad. Va de qué puede y qué no puede representar un vector. Así que la pregunta de verdad no es “grafo o RAG”. Es cuál usas, para qué pregunta, y por qué.

El RAG vectorial recupera por semejanza

Un embedding convierte un trozo de código en un punto de un espacio de muchas dimensiones, colocado de forma que las cosas que significan cosas parecidas caen cerca. La recuperación es entonces una búsqueda de proximidad. Embebes la pregunta, encuentras los trozos más cercanos, se los das al modelo.

En lo que esto es genuinamente bueno es en recall difuso. No sabes el nombre exacto de la función, tienes un codebase grande y desconocido, y quieres “el código que gestiona los casos raros de reembolso” o “cualquier cosa de rate limiting”. La semejanza es justo la herramienta ahí. Es barata de montar, tolera frases desordenadas, y brilla justo cuando no puedes nombrar lo que buscas. Y no para de mejorar. Técnicas como el contextual retrieval, que antepone contexto explicativo a cada trozo antes de embeberlo, cierran buena parte del hueco que deja el troceado ingenuo.

Qué tira la semejanza

Aquí está el límite estructural. Cuando cortas un codebase en trozos y los embebes, borras las aristas. El hecho de que chargeCard llame a validatePayment, que se importa de un servicio del que dependen otros tres módulos, toda esa telaraña de relaciones no sobrevive al viaje al espacio vectorial. Los trozos caen cerca si se leen parecido. Caen lejos si están cableados juntos pero redactados distinto.

Así que el RAG vectorial es fuerte en “encuéntrame código como este” y flojo en “encuéntrame código conectado a este”. Pídele “qué llama a deleteAccount” y te devuelve cosas que parecen borrado, no los llamadores reales. Pídele “qué se rompe si cambio este tipo de retorno” y no puede contestar, porque el impacto es un recorrido de grafo y no guardó ningún grafo. La información se tiró en el momento de indexar, y ningún reranker recupera lo que nunca se almacenó.

Esto no es un ataque a los embeddings. Es un hecho de categoría. Semejanza y conectividad son relaciones distintas, y un índice vectorial codifica una de las dos.

Un grafo de conocimiento recupera por relación

Un grafo de conocimiento del código guarda las aristas a propósito. Funciones, ficheros, servicios, y también las cosas de más alto nivel: una decisión, un criterio de aceptación, la historia que un trozo de código satisface. Las relaciones son explícitas. Llama. Importa. Depende-de. Implementa. Decidido-por. La recuperación es recorrido, no proximidad.

Eso vuelve baratas las preguntas antes imposibles. ¿Qué llama a esto? Sigue las aristas llama hacia dentro. ¿Qué se rompe si lo toco? Recorre los dependientes. ¿Por qué existe esto? Sigue la arista del código a la decisión que lo produjo. Son exactas, y son de varios saltos, y son justo las preguntas que los vectores no pueden contestar porque la respuesta es la estructura, no la redacción.

El coste también es real. Un grafo hay que construirlo y mantenerlo al día según se mueve el código, y solo conoce las relaciones que elegiste modelar. No te va a sorprender con un acierto semántico difuso como hace un embedding. Contesta lo que preguntaste, con precisión, y nada más.

Cuándo gana cada uno

Sin dogma. Dos herramientas, dos formas de pregunta.

Tira de búsqueda vectorial cuando la pregunta es difusa y el codebase te es desconocido. Onboarding a un repo enorme. “Dónde hay algo de facturación.” “Muéstrame handlers parecidos a este.” Búsqueda de una sola pasada en lenguaje natural donde no puedes nombrar el objetivo. Los vectores son más baratos de levantar y perdonan la entrada vaga.

Tira del grafo cuando la respuesta es una relación, y equivocarse sale caro. Análisis de impacto antes de un refactor. “Cuáles son todos los llamadores reales.” Trazar un requisito hasta el código que lo implementa, o un trozo de código de vuelta a la decisión que lo justifica. Cualquier cosa que un agente deba acertar exactamente en vez de aproximadamente, porque está a punto de cambiar código en base a la respuesta.

El error es tratar una preferencia como un principio. Si alguien te dice que el RAG está muerto o que los grafos son sobreingeniería, está describiendo su último proyecto, no el tuyo. La pregunta decide.

Un fallo concreto

Aquí está el fallo en una sola escena, porque es fácil asentir a la teoría y publicar el bug igual.

Estás a punto de renombrar una columna de base de datos y le preguntas a tu asistente con RAG qué depende de ella. Embebe la pregunta, busca, y te devuelve tres ficheros que mencionan la columna por su nombre en una cadena. Seguro, específico, incompleto. Se dejó los dos módulos que llegan a la columna por una relación de ORM y una propiedad computada, porque esos ficheros nunca escriben el nombre de la columna, así que nunca cayeron cerca de tu consulta en el espacio vectorial. Renombras, los tests que conocías pasan, y un job de informes se rompe en producción una semana después.

Un grafo habría contestado la misma pregunta recorriendo las aristas lee y escribe hacia esa columna, indirección de ORM incluida, y habría devuelto el conjunto completo. La diferencia no fue calidad de modelo ni redacción del prompt. Fue que un sistema guardó la dependencia y el otro la tiró en el momento de indexar.

La respuesta de verdad suele ser las dos

El montaje más fuerte no es una competición. Es por capas. Usa los vectores para el recall, para encontrar la región candidata de un codebase grande a partir de un prompt vago. Luego usa el grafo para la precisión, para expandir desde esos candidatos por aristas reales y traer los llamadores, dependientes y decisiones exactos. Difuso para llegar al barrio, estructural para acertar.

Es más o menos la intuición detrás de la línea de trabajo de Graph RAG, que construye un grafo sobre un corpus y lo recorre para responder preguntas que una búsqueda vectorial plana gestiona mal.

Para código en concreto, el grafo lleva algo que los vectores nunca llevarán: procedencia y el “porqué”. Un almacén vectorial te puede decir que este trozo parece relevante. Un grafo te puede decir que este código existe por esa decisión, y aquí está la historia que satisface. Esa es la capa que convierte la recuperación en leer la forma de tu producto en vez de una lista de features, y es por lo que un cerebro de producto que se mantiene solo se construye sobre un grafo y no solo sobre embeddings.

Dónde encaja PaellaDoc

PaellaDoc construye el grafo, en tu máquina, desde tu repo y su historial: código relacionado con las decisiones y criterios que lo explican, con las aristas explícitas para que un agente pueda recorrer en vez de adivinar. No te pide tirar la búsqueda vectorial. Le da a tus agentes la capa estructural que la búsqueda vectorial no puede representar, para que las preguntas que dependen de relaciones dejen de devolver cosas que solo parecen correctas.

Local-first y gratis, sin nube y sin cuenta.

↓ Descargar PaellaDoc · macOS

¿Cuál es la última pregunta sobre tu codebase que el RAG contestó con seguridad y mal? Cuéntame en el foro.

Preguntas frecuentes

¿Cuál es la diferencia entre un grafo de conocimiento y RAG vectorial para código?

El RAG vectorial recupera por semejanza: embebe el código en vectores y devuelve los trozos más parecidos a una consulta. Un grafo de conocimiento recupera por relación: guarda aristas explícitas (llama-a, importa, depende-de, decidido-por) y responde recorriéndolas. Uno es bueno para recall difuso, el otro para preguntas estructurales de varios saltos.

¿Cuándo gana la búsqueda vectorial a un grafo para código?

Cuando necesitas recall difuso sobre un codebase grande y desconocido y la pregunta es casi lenguaje natural: encuentra código que haga X, dónde hay algo de facturación, muéstrame handlers parecidos. Los vectores son baratos de montar, toleran entradas desordenadas y son fuertes cuando no sabes los nombres exactos que buscar.

¿Cuándo gana un grafo de conocimiento a la búsqueda vectorial para código?

Cuando la respuesta depende de relaciones que el embedding tira: qué llama a esto, qué se rompe si lo cambio, por qué existe esto, traza esta decisión hasta el código que la implementa. Son preguntas exactas, de varios saltos y estructurales, y un grafo las responde recorriendo en vez de adivinar por parecido.