tiempo de lectura : 12 minutes

Tu base de código crece. Las dependencias entre módulos se multiplican. La documentación de la arquitectura se vuelve obsoleta incluso antes de ser escrita. ¿Y si tu build de Gradle pudiera automáticamente generar diagramas actualizados a partir de la estructura real del código? Eso es exactamente lo que hace el pipeline Graphify + PlantUML Gradle Plugin :`graphify . --no-viz`extrae el Knowledge Graph,`./gradlew generateKnowledgeGraphDiagram`lo convierte en diagramas PlantUML. Cero LLM, cero manual, 100% determinista.

El problema: diagramas siempre atrasados respecto al código

Todo proyecto que supera varios miles de líneas conoce este síndrome:

  1. Se dibuja un diagrama de arquitectura al inicio del proyecto

  2. El código evoluciona, las dependencias cambian

  3. El diagrama se convierte en una mentira decorativa

  4. Nadie lo actualiza porque es tedioso

  5. Los recién llegados se basan en ello y cometen errores

@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #FDEDEC
skinparam ActivityDiamondBackgroundColor #FFF3CD

start

:Diagrama de arquitectura creado\n(manualmente, a mano);

:El código evoluciona\n(nuevas clases, nuevas dependencias);

:Diagrama obsoleto\n(ya no refleja el código);

if (Qui met à jour ?) then (Personne)
    :Documentación mentirosa;
    note right: Los nuevos desarrolladores\nse basan en eso... y cometen errores
else (Quelqu'un)
    :Actualización manual\n(2-3 horas de trabajo);
    note right: Ya obsoleto\npara la próxima PR
endif

stop

@enduml

La pregunta no es ¿se necesitan diagramas? — todo el mundo sabe que sí. La pregunta es :¿Quién los mantiene al día?

La respuesta: nadie. A menos que sea automático.

La solución: un pipeline determinista Knowledge Graph → PlantUML

El principio es simple : en lugar de dibujar los diagramas a mano, nosotros losgenera desde la estructura real del código.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur
component "Graphify\n(pip install graphifyy)" as Graphify
collections "graphify-out/graph.json\n(Gráfico de conocimiento)" as KGJSON
component "PlantUML Gradle Plugin\n(generateKnowledgeGraphDiagram)" as Plugin
component "KnowledgeGraphParser" as Parser
component "KnowledgeGraphRenderer" as Renderer
component "PlantumlService\n(validación + renderizado PNG)" as PS
collections "diagrams/knowledge-graph/\n(.puml + .png)" as Output

Développeur --> Graphify : graficar . --no-viz
Graphify --> KGJSON : extrae la estructura\ndel código fuente
Développeur --> Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --> Parser : parse(graph.json)
Parser --> Plugin : KnowledgeGraph\n(nodos + aristas + comunidades)
Plugin --> Renderer : render(graph, filters)
Renderer --> Plugin : código PlantUML\ndeterminista
Plugin --> PS : validateSyntax + generateImage
PS --> Output : .puml + .png

note bottom of Plugin
Pipeline DÉTERMINISTE
Ninguna llamada LLM
Resultado reproducible
end note

@enduml

Dos comandos. Eso es todo.

# Étape 1 : extraire le Knowledge Graph
graphify . --no-viz

# Étape 2 : générer les diagrammes PlantUML
./gradlew generateKnowledgeGraphDiagram

¿El resultado? Archivos`.puml` et .png`en`diagrams/knowledge-graph/, versionados en Git, siempre actualizados con el código.

Paso 1: Instalar Graphify y extraer el Knowledge Graph

Instalación

Graphify es una herramienta de Python que analiza tu código base y construye un grafo de conocimientos estructurado:

# Méthode recommandée
uv tool install graphifyy && graphify install --platform opencode

# Alternative avec pip
pip install graphifyy && graphify install --platform opencode

Configurar las exclusiones

Crear un archivo`.graphifyignore`en la raíz del proyecto para excluir los archivos que no forman parte de la lógica de negocio:

# Secrets — JAMAIS dans le graphe
*-context.yml
*.env

# Fichiers générés
build/
.gradle/

# Tests fonctionnels
src/functionalTest/

Extraer el Knowledge Graph

graphify . --no-viz

La bandera`--no-viz`Salta la generación de HTML (inútil en un pipeline Gradle). El resultado es un archivo`graphify-out/graph.json`conteniendo :

  • Nudos: clases, funciones, archivos — con su tipo y comunidad

  • Aristas: relaciones entre nodos (EXTRACTED desde el código, INFERRED por el LLM)

  • Comunidades: agrupaciones automáticas de nodos vinculados

Ejemplo de estructura`graph.json`
{
  "nodes": [
    {"id": "0", "label": "LlmService", "file_type": "code", "community": 0},
    {"id": "1", "label": "ApiKeyPool", "file_type": "code", "community": 0},
    {"id": "2", "label": "PlantumlService", "file_type": "code", "community": 1}
  ],
  "links": [
    {"source": "1", "target": "0", "relation": "uses", "confidence": "EXTRACTED", "weight": 0.9},
    {"source": "0", "target": "2", "relation": "calls", "confidence": "INFERRED", "weight": 0.7}
  ]
}

El código fuente (.kt, .java) es analizado localmente por tree-sitter,sin apelación LLM. Sólo los archivos de documentación(.adoc, .md) requieren una llamada LLM para la extracción semántica. Entonces`--update`en el código Kotlin es casi instantáneo.

Paso 2: El plugin Gradle transforma el Knowledge Graph en PlantUML

Arquitectura del pipeline

El plugin`com.cheroliv.plantuml`integra una tarea`generateKnowledgeGraphDiagram`que transforma`graph.json`en diagramas PlantUML de maneratotalmente determinista:

@startuml
skinparam backgroundColor #FEFEFE

participant "Gradle" as G
participant "GenerateKnowledgeGraphDiagramTask" as Task
participant "KnowledgeGraphParser" as Parser
participant "KnowledgeGraphRenderer" as Renderer
participant "PlantumlService" as PS

collections "graphify-out/graph.json" as JSON

G -> Task : execute
Task -> JSON : leer
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph\n(nodos + aristas + comunidades)
Task -> Renderer : render(graph, filters)
Renderer --> Task : código PlantUML\n(determinista)
Task -> PS : validateSyntax(plantumlCode)
alt syntaxe valide
    Task -> PS : generateImage → .png
else syntaxe invalide
    Task -> Task : guardar .puml con advertencia
end

@enduml

Los componentes internos

Componente Rol

KnowledgeGraphParser

Parsear`graph.json`— admite 3 formatos: graphify nativo (nodes+links), legacy (communities), flat. Resuelve los IDs numéricos en etiquetas.

KnowledgeGraphRenderer

Transforma determinísticamente un`KnowledgeGraph`en código PlantUML. Grupos por tipo, comunidades en paquetes, leyenda automática.

GenerateKnowledgeGraphDiagramTask

Tarea Gradle que orquesta: parse → render → validate → PNG. Configurable vía propiedades Gradle.

kgmodels.kt

Modelos de datos:`KnowledgeGraph`, KnowledgeGraphNode, KnowledgeGraphEdge, KnowledgeGraphCommunity, EdgeType.

PlantumlService

Validación sintáctica + renderizado PNG (reutilizado por todas las tareas del plugin).

Reglas de renderizado

El renderer aplica convenciones visuales deterministes:

Tipo de arista Notación PlantUML Significado

extraído

-→(línea continua, negra)

Relación extraída del código fuente (certidumbre)

DEDUCIDO

..>(línea punteada)

Relación inferida por el LLM (puntuación de confianza)

ambiguo

--x(línea roja punteada)

Relación ambigua (por verificar)

Las comunidades se representan como paquetes PlantUML con una paleta de colores automática.

Paso 3: Uso diario

Diagrama completo

# Générer le diagramme du Knowledge Graph complet
./gradlew generateKnowledgeGraphDiagram

Sortie : diagrams/knowledge-graph/knowledge-graph-full.puml + .png

Filtrar por comunidad

# Une seule communauté
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0

# Limiter le nombre de noeuds (lisibilité)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0 \
  -Pplantuml.kg.maxNodes=15

Filtrar por tipo de arista

# Uniquement les relations certaines (EXTRACTED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED

# Relations certaines + inférées
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED,INFERRED

Filtrar por tipo de nodo y confianza

# Uniquement les classes de code
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.nodeTypes=code

# Seuil de confiance minimum (pour les INFERRED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.minConfidence=0.7

Directorio de salida personalizado

./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.outputDir=docs/architecture

Referencia completa de las propiedades

Propiedad Defecto Descripción

plantuml.kg.community

(todas)_

Filtrar las comunidades por nombre (coincidencia de subcadena)

plantuml.kg.edgeTypes

(todos)

Tipos de aristas separados por comas :`EXTRACTED`, INFERRED, AMBIGUOUS

plantuml.kg.minConfidence

0.0

Umbral mínimo de confianza para las aristas

plantuml.kg.maxNodes

(ilimitado)

Número máximo de nodos a mostrar

plantuml.kg.nodeTypes

(todos)

Tipos de nodos separados por comas (ej.class, code)

plantuml.kg.outputDir

diagrams/knowledge-graph

Directorio de salida para los archivos`.puml` et .png

El pipeline completo en un workflow Gradle

tipo de flujo de trabajo

@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #E8F4FD
skinparam ActivityDiamondBackgroundColor #FFF3CD
skinparam ActivityBorderColor #2C3E50

start

partition "EXTRACTION" {
    :graficar . --no-viz;
    note right: Analice el código fuente\ntree-sitter (local, sin LLM)

    :graphify-out/graph.json;
    note right: Nodos + aristas\n+ comunidades
}

partition "GÉNÉRATION" {
    :./gradlew generateKnowledgeGraphDiagram;
    note right: Canalización determinista\nparse → render → validate → PNG

    if (Filtres actifs ?) then (Oui)
        :Aplicar filtros\n(community, edgeTypes,\nmaxNodes, nodeTypes);
    else (Non)
        :Diagrama completo;
    endif

    :diagrams/knowledge-graph/\nknowledge-graph-full.puml\nknowledge-graph-full.png;
}

partition "INTÉGRATION" {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Diagramas versionados\nsiempre actualizados con el código
}

stop

@enduml

Integración en el ciclo de desarrollo

El pipeline se integra naturalmente en las etapas clave del desarrollo :

@startuml
skinparam backgroundColor #FEFEFE

state "Desarrollo" as dev
state "Extracción\ngraphify . --no-viz" as extract
state "Generación\n./gradlew generateKnowledgeGraphDiagram" as generate
state "Commit\ndiagramas versionados" as commit

[*] --> dev
dev --> extract : Código modificado
extract --> generate : graph.json al día
generate --> commit : .puml + .png generados
commit --> dev : Diagramas en el repositorio

note right of extract
Casi instantáneo sobre el código Kotlin (tree-sitter, sin LLM)
end note

note right of generate
Deterministic
No LLM
Resultado reproducible
end note

@enduml

Actualización incremental

Cuando el código cambia, no se reconstruye todo el grafo desde cero:

# Mise à jour incrémentale (fichiers modifiés uniquement)
graphify . --update

# Puis régénérer les diagrammes
./gradlew generateKnowledgeGraphDiagram

--update`Reextrae solo los archivos modificados (detectados por SHA256 en`graphify-out/cache/). En código Kotlin, es casi instantáneo porque tree-sitter trabaja localmente sin una llamada al LLM.

El dogfooding: el plugin se auto-documenta

El plugin PlantUML existe para transformar los prompts en diagramas. También puede transformar el Knowledge Graph de su propre codebase en diagramas de documentación. Es dogfooding : el plugin consume su propio servicio.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "Pipeline normal\n(usuario → diagramas)" as normal {
    [Fichier .prompt] as prompt
    [LlmService\n+ ApiKeyPool] as llm1
    [ProcessPlantumlPromptsTask] as task1
    [Diagramme PNG] as out1

    prompt --> task1
    task1 --> llm1
    llm1 --> out1
}

package "Pipeline Knowledge Graph\n(determinista, sin LLM)" as kg {
    [graphify-out/graph.json] as kgjson
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantumlService] as ps
    [Diagramme PNG\n(documentation du plugin)] as out2

    kgjson --> parser
    parser --> renderer
    renderer --> ps
    ps --> out2
}

package "Dogfooding del pipeline\n(LLM → documentación del plugin)" as dogfood {
    [GraphifyPromptAdapter] as gpa
    [Fichiers .prompt\nauto-générés] as auto_prompt
    [LlmService\n+ ApiKeyPool] as llm2
    [ProcessPlantumlPromptsTask] as task2
    [Diagramme PNG\n(documentation LLM)] as out3

    kgjson --> gpa
    gpa --> auto_prompt
    auto_prompt --> task2
    task2 --> llm2
    llm2 --> out3
}

note "Mismo LlmService, mismo ApiKeyPool,\nmismo PlantumlService\n— CERO duplicación" as N

@enduml

Tareas Gradle asociadas :

Tarea LLM ? Descripción

generateKnowledgeGraphDiagram

No

Transforma`graph.json`en PlantUML (determinista)

generateDiagramDocs

Sí

genera`.prompt`desde el grafo, los trata mediante LLM (dogfooding)

# Documentation déterministe (rapide, pas de LLM)
./gradlew generateKnowledgeGraphDiagram

# Documentation LLM (plus riche, consomme des tokens)
./gradlew generateDiagramDocs

Por qué es determinista (y por qué importa)

El punto clave del pipeline`generateKnowledgeGraphDiagram`:No llama a ningún LLM. La transformación`graph.json`→ PlantUML es una función pura.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

rectangle "Pipeline DÉTERMINISTE\n(generateKnowledgeGraphDiagram)" as det {
    [graph.json] as json
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantUML code] as puml

    json --> analizarr : analizar
    parser --> renderer : KnowledgeGraph
    renderer --> puml : render (función pura)
}

rectangle "Pipeline LLM\n(processPlantumlPrompts)" as llm {
    [.prompt] as prompt
    [LlmService] as llmSvc
    [ChatModel] as model
    [PlantUML code] as puml2

    prompt --> llmSvc
    llmSvc --> model : API llamada
    model --> puml2 : respuesta no determinista
}

note bottom of det
Misma entrada → misma salida
Sin latencia de red
Sin costo en tokens
Reproducible en CI
end note

note bottom of llm
Misma entrada → salida variable
Latencia de red (1-5s)
Costo en tokens
Requiere una clave API
end note

@enduml

Los beneficios concretos :

Ventaja Impacto

Reproducibilidad

Incluso`graph.json`→ mismo diagrama. Exactamente. Cada vez.

Costo cero

Sin llamada LLM = sin tokens = sin factura API.

Cero latencia

Parse + render tarda ~100ms, no 1-5 segundos.

Compatible con CI

No se necesita una clave API. No hay pruebas inestables debido a una respuesta de LLM variable.

versionable

Le .puml`generado es texto. Podemos lo`diff, el revisor en PR, versionarlo en Git.

Diagramas del pipeline mismo

Para cerrar el bucle, aquí está el diagrama del pipeline tal como sería generado por el plugin:

@startuml
skinparam backgroundColor #FEFEFE

participant "Desarrollador" as Dev
participant "Gradle" as G
participant "GenerateKnowledgeGraphDiagramTask" as Task
participant "KnowledgeGraphParser" as Parser
participant "KnowledgeGraphRenderer" as Renderer
participant "PlantumlService" as PS
collections "graphify-out/graph.json" as JSON
collections "diagrams/knowledge-graph/" as Out

Dev -> G : ./gradlew generateKnowledgeGraphDiagram
G -> Task : ejecutar
Task -> JSON : leer
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph

alt filtres actifs
    Task -> Task : aplicar filtros\n(community, edgeTypes, maxNodes…)
end

Task -> Renderer : render(graph, filters)
Renderer --> Task : código PlantUML

Task -> PS : validateSyntax()
alt valide
    Task -> PS : generateImage()
    PS --> Out : .puml + .png
else invalide
    Task -> Out : .puml (con advertencia)
end

@enduml

Integración en la gobernanza del proyecto

En nuestro proyecto, este pipeline se integra en una estrategia de gestión de contexto EAGER/LAZY para el agente IA. El Knowledge Graph reemplaza la documentación de arquitectura manual por un grafo estructurado, consultable y autoactualizado.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "EAGER\n(siempre cargado)" as eager {
    [PROMPT_REPRISE.adoc\n(contexte session)] as pr
    [INDEX.adoc\n(vue d'ensemble)] as idx
    [GRAPH_REPORT.adoc\n(~50 lignes)] as gr
}

package "LAZY — Estrategia\n(a petición)" as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

package "LAZY — Graphify\n(consultas dirigidas)" as lazy_graph {
    [graph.json] as gj
    [Queries\n(query/path/explain)] as queries
}

package "Pipeline PlantUML\n(autogenerado)" as puml {
    [generateKnowledgeGraphDiagram] as kgTask
    [generateDiagramDocs] as ddTask
    [Diagrammes PNG] as diagrams
}

Agent --> eager : Lectura al inicio de la sesión
Agent ..> lazy_strat : Cargar si se detecta el tipo
Agent ..> lazy_graph : Consulta si es estructuralmente necesario
kgTask --> diagrams : determinista
ddTask --> diagrams : A través de LLM

note right of gr
Resumen del Knowledge Graph
Nodos God + comunidades
Reemplaza ECOSYSTEM_OVERVIEW
(225 líneas → 50 líneas)
end note

@enduml

El matrimonio de los dos sistemas es complementario:

  • La estrategia gestiona el CUÁNDO y el CÓMO— gobernanza, flujo de trabajo, archivo

  • Graphify gestiona el QUOI y el OÙ— estructura del código, relaciones, consultas específicas

__ La estrategia de sesión gestiona elCUANDO et le CÓMO(gouvernance, workflow, seuils), Graphify gestiona elQUÉ et le dónde(estructura del código, relaciones, consultas dirigidas). El pipeline PlantUML gestiona elCON QUÉ(diagramas deterministas, versionados, siempre actualizados) (Empty)

Puestra en marcha: lista de verificación en 5 minutos

(No output, as the text to translate is empty) Etapa Pedido

1

Instalar Graphify

uv tool install graphifyy

2

Configurar las exclusiones

Crear`.graphifyignore`

3

Extraer el Knowledge Graph

graphify . --no-viz

4

Generar los diagramas

./gradlew generateKnowledgeGraphDiagram

5

Committer los resultados

git add diagrams/knowledge-graph/

# Script complet en 5 commandes
uv tool install graphifyy
cat > .graphifyignore << 'EOF'
*-context.yml
*.env
build/
.gradle/
EOF
graphify . --no-viz
./gradlew generateKnowledgeGraphDiagram
git add graphify-out/GRAPH_REPORT.adoc graphify-out/graph.json diagrams/knowledge-graph/

Trampas y mitigaciones

Trampa Descripción Mitigación

Grafo muy denso

Un proyecto grande genera cientos de nodos ilegibles

usar`-Pplantuml.kg.maxNodes=30`y filtrar por comunidad

Exclusiones demasiado amplias

Demasiados archivos en`.graphifyignore`reduce el valor del grafo

Comenzar por excluir solo credentials y build

Dirección de las flechas

Las aristas INFERRED pueden tener una dirección ambigua

Filtrar por`-Pplantuml.kg.edgeTypes=EXTRACTED`para las relaciones ciertas únicamente

Grafo obsoleto

El código cambia pero el grafo no se reconstruye

Utilizar`graphify . --update`régulièrement o el hook git`graphify hook install`

Costo actualizado

Las actualizaciones incrementales son casi gratuitas (tree-sitter local)

Sólo las docs (.adoc) consumen tokens LLM

Lo que se obtiene al final

@startuml
skinparam backgroundColor #FEFEFE

rectangle "AVANT" as avant {
    card "Diagramas dibujados a mano\nSiempre obsoletos\nNadie los actualiza" as av1 #FDEDEC
}

rectangle "APRÈS" as apres {
    card "Diagramas generados automáticamente\nSiempre actualizado con el código\nVersionados en Git\nDeterministas y reproducibles" as ap1 #E8F8E8
}

avant --> apres : graficar . --no-viz\n+ ./gradlew generateKnowledgeGraphDiagram

@enduml

Los beneficios concretos :

Beneficio Detalle

Documentación siempre actualizada

Los diagramas reflejan el código actual, no una instantánea manual

Cero esfuerzo de mantenimiento

Los diagramas se regeneran en cada build

Reducción de la deuda técnica

No es necesario mantener los diagramas a mano

Contexto visual para los nuevos

Un nuevo desarrollador entiende la arquitectura mirando los diagramas

ajuste fino potencial

Los pares (subgrafo → diagrama) son ejemplos de entrenamiento de IA

Validación automática

`PlantumlService.validateSyntax()`verifica cada diagrama generado

Onboarding rápido

5 diagramas = vista completa de la arquitectura

_ El que tiene un _por qué puede soportar todos los cómo. __

El por qué: diagramas siempre actualizados. El cómo: dos comandos en un pipeline Gradle.

Enlaces

Artículos relacionados