Lesezeit : 12 minutes

Deine Codebasis wächst. Die Abhängigkeiten zwischen Modulen vermehren sich. Die Architektur-Dokumentation wird veraltet, bevor sie überhaupt geschrieben ist. Und was wäre, wenn dein Gradle-Build automatisch aktuelle Diagramme aus der tatsächlichen Code-Struktur generieren könnte? Genau das macht das Graphify + PlantUML Gradle Plugin-Pipeline:`graphify . --no-viz`extrahiert den Knowledge Graph,`./gradlew generateKnowledgeGraphDiagram`Er verwandelt es in PlantUML-Diagramme. Kein LLM, kein Handbuch, 100% deterministisch.

Das Problem: Diagramme hinken immer dem Code hinterher

Jedes Projekt, das mehrere tausend Zeilen überschreitet, kennt dieses Syndrom:

  1. Man zeichnet ein Architekturdiagramm am Anfang des Projekts

  2. Der Code entwickelt sich, die Abhängigkeiten ändern sich

  3. Das Diagramm wird zu einer dekorativen Lüge.

  4. Niemand aktualisiert es, weil es mühsam ist.

  5. Die Neuanwärter basieren darauf und machen Fehler.

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

start

:Diagramme d'architecture créé\n(manuellement, à la main);

:Le code évolue\n(nouvelles classes, nouvelles dépendances);

:Diagramme obsolète\n(ne reflète plus le code);

if (Qui met à jour ?) then (Personne)
    :Documentation mensongère;
    note right: Les nouveaux développeurs\nse basent dessus... et font des erreurs
else (Quelqu'un)
    :Mise à jour manuelle\n(2-3 heures de travail);
    note right: Déjà obsolète\nà la prochaine PR
endif

stop

@enduml

Die Frage ist nicht müssen wir Diagramme haben? — jeder weiß, dass ja. Die Frage ist:Wer hält sie auf dem neuesten Stand?

Die Antwort: niemand. Ausser wenn es automatisch ist.

Die Lösung: ein deterministischer Pipeline Knowledge Graph → PlantUML

Das Prinzip ist einfach: Statt die Diagramme von Hand zu zeichnen, zeichnet man siegeneriert aus der tatsächlichen Code-Struktur.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur
component "Graphify\n(pip install graphifyy)" as Graphify
collections "graphify-out/graph.json\n(Knowledge Graph)" as KGJSON
component "PlantUML Gradle Plugin\n(generateKnowledgeGraphDiagram)" as Plugin
component "KnowledgeGraphParser" as Parser
component "KnowledgeGraphRenderer" as Renderer
component "PlantumlService\n(validation + rendu PNG)" as PS
collections "diagrams/knowledge-graph/\n(.puml + .png)" as Output

Développeur --> Graphify : graphify . --no-viz
Graphify --> KGJSON : extrait la structure\ndu code source
Développeur --> Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --> Parser : parse(graph.json)
Parser --> Plugin : KnowledgeGraph\n(noeuds + arêtes + communautés)
Plugin --> Renderer : render(graph, filters)
Renderer --> Plugin : code PlantUML\ndéterministe
Plugin --> PS : validateSyntax + generateImage
PS --> Output : .puml + .png

note bottom of Plugin
  Pipeline DÉTERMINISTE
  Aucun appel LLM
  Résultat reproductible
end note

@enduml

Zwei Befehle. Das ist alles.

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

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

Das Ergebnis? Dateien`.puml` et .png`in`diagrams/knowledge-graph/, versioniert in Git, immer auf dem neuesten Stand des Codes.

Schritt 1: Graphify installieren und den Knowledge Graph extrahieren

Installation

Graphify ist ein Python-Tool, das Ihre Codebase analysiert und einen strukturierten Wissensgraphen erstellt:

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

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

Ausnahmen konfigurieren

Eine Datei erstellen`.graphifyignore`im Wurzelverzeichnis des Projekts, um Dateien auszuschließen, die nicht zur Geschäftslogik gehören:

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

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

# Tests fonctionnels
src/functionalTest/

Den Knowledge Graph extrahieren

graphify . --no-viz

der Flag`--no-viz`überspringt die HTML-Generierung (unnötig in einem Gradle-Pipeline). Das Ergebnis ist eine Datei`graphify-out/graph.json`enthaltend :

  • Knoten: Klassen, Funktionen, Dateien — mit ihrem Typ und Gemeinschaft

  • GrateBeziehungen zwischen Knoten (EXTRACTED aus dem Code, INFERRED vom LLM)

  • Gemeinschaften: automatische Gruppierungen verbundener Knoten

Beispiel einer Struktur`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}
  ]
}

Der Quellcode (.kt, .java) wird lokal von tree-sitter analysiert,unwiderrufliches LLM. Nur die Dokumentationsdateien (.adoc, .md) erfordern einen LLM-Aufruf für die semantische Extraktion. Also`--update`Auf Kotlin-Code ist es quasi sofort.

Schritt 2: Das Gradle-Plugin transformiert den Knowledge Graph in PlantUML

Architektur des Pipelines

Das Plugin`com.cheroliv.plantuml`integriert eine Aufgabe`generateKnowledgeGraphDiagram`der transformiert`graph.json`in PlantUML-Diagrammen auf welche Weisevollständig deterministisch:

@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 : read
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph\n(noeuds + arêtes + communautés)
Task -> Renderer : render(graph, filters)
Renderer --> Task : code PlantUML\n(déterministe)
Task -> PS : validateSyntax(plantumlCode)
alt syntaxe valide
    Task -> PS : generateImage → .png
else syntaxe invalide
    Task -> Task : save .puml avec warning
end

@enduml

Die internen Komponenten

Komponente Rolle

KnowledgeGraphParser

parsen`graph.json`— unterstützt 3 Formate: nativer Graphify (nodes+links), legacy (communities), flach. Löst die numerischen IDs in Beschriftungen auf.

KnowledgeGraphRenderer

Transformiert deterministisch ein`KnowledgeGraph`im PlantUML-Code. Gruppen nach Typ, Gemeinschaften in Paketen, automatische Legende.

GenerateKnowledgeGraphDiagramTask

Gradle-Task, die orchestriert: parse → render → validate → PNG. Konfigurierbar über Gradle-Eigenschaften.

kgmodels.kt

Datenmodelle :`KnowledgeGraph`, KnowledgeGraphNode, KnowledgeGraphEdge, KnowledgeGraphCommunity, EdgeType.

PlantumlService

Syntaxprüfung + PNG-Rendering (wiederverwendet von allen Aufgaben des Plugins).

Renderregeln

Der Renderer wendet deterministische visuelle Konventionen an:

Kantentyp PlantUML-Notation Bedeutung

EXTRACTED

-→(durchgezogener Strich, schwarz)

Aus dem Quellcode extrahierte Beziehung (Sicherheit)

geschlossen

..>(punktiert)

Vom LLM abgeleitete Beziehung (Vertrauensscore)

mehrdeutig

--x(rote gepunktete Linie)

Ambigue Beziehung (zu überprüfen)

Die Communities werden als PlantUML-Pakete mit einer automatischen Farbpalette dargestellt.

Schritt 3: Tägliche Nutzung

Vollständiges Diagramm

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

Ausgabe:`diagrams/knowledge-graph/knowledge-graph-full.puml`+.png

Nach Gemeinschaft filtern

# 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

Nach Kantenart filtern

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

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

Nach Knotentyp und Vertrauen filtern

# 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

Benutzerdefiniertes Ausgabeverzeichnis

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

Vollständige Referenz der Eigenschaften

Eigenschaft Standard Beschreibung

plantuml.kg.community

(alle)

Gemeinden nach Name filtern (Teilzeichenkette)

plantuml.kg.edgeTypes

(alle)

Kantentypen durch Kommata getrennt:`EXTRACTED`, INFERRED, AMBIGUOUS

plantuml.kg.minConfidence

0.0

Mindestvertrauensschwelle für die Kanten

plantuml.kg.maxNodes

(unbegrenzt)

Maximale Anzahl der anzuzeigenden Knoten

plantuml.kg.nodeTypes

(alle)

Knotentypen durch Kommata getrennt (z.B.class, code)

plantuml.kg.outputDir

diagrams/knowledge-graph

Ausgabeverzeichnis für die Dateien`.puml` et .png

Der vollständige Pipeline in einem Gradle-Workflow

Workflow-Typ

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

start

partition "EXTRACTION" {
    :graphify . --no-viz;
    note right: Analyse le code source\ntree-sitter (local, pas de LLM)

    :graphify-out/graph.json;
    note right: Noeuds + arêtes\n+ communautés
}

partition "GÉNÉRATION" {
    :./gradlew generateKnowledgeGraphDiagram;
    note right: Pipeline déterministe\nparse → render → validate → PNG

    if (Filtres actifs ?) then (Oui)
        :Appliquer filtres\n(community, edgeTypes,\nmaxNodes, nodeTypes);
    else (Non)
        :Diagramme complet;
    endif

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

partition "INTÉGRATION" {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Diagrammes versionnés\ntoujours à jour avec le code
}

stop

@enduml

Integration in den Entwicklungszyklus

Die Pipeline integriert sich natürlich in die Schlüsselphasen der Entwicklung:

@startuml
skinparam backgroundColor #FEFEFE

state "Développement" as dev
state "Extraction\ngraphify . --no-viz" as extract
state "Génération\n./gradlew generateKnowledgeGraphDiagram" as generate
state "Commit\ndiagrammes versionnés" as commit

[*] --> dev
dev --> extract : Code modifié
extract --> generate : graph.json à jour
generate --> commit : .puml + .png générés
commit --> dev : Diagrammes dans le repo

note right of extract
  Quasi instantané sur du code Kotlin
  (tree-sitter, pas de LLM)
end note

note right of generate
  Déterministe
  Pas de LLM
  Résultat reproductible
end note

@enduml

inkrementelles Update

Wenn der Code sich ändert, bauen wir nicht das gesamte Diagramm von Grund auf neu:

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

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

--update`extrahiert erneut nur die geänderten Dateien (durch SHA256 erkannt in`graphify-out/cache/). Bei Kotlin-Code ist es nahezu sofort, da tree-sitter lokal arbeitet, ohne einen LLM-Aufruf zu tätigen.

Dogfooding: Das Plugin dokumentiert sich selbst

Der PlantUML-Plugin existiert, um Prompts in Diagramme zu verwandeln. Er kann auch den Knowledge Graph seiner eigenen codebase in Dokumentationsdiagramme verwandeln. Das ist dogfooding: Der Plugin verbraucht seinen eigenen Dienst.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "Pipeline normal\n(utilisateur → diagrammes)" 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(déterministe, pas de 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 "Pipeline Dogfooding\n(LLM → documentation du 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 "Même LlmService, même ApiKeyPool,\nmême PlantumlService\n— ZÉRO duplication" as N

@enduml

Verknüpfte Gradle-Aufgaben :

Aufgabe LLM ? Beschreibung

generateKnowledgeGraphDiagram

Nein

Transforme`graph.json`in PlantUML (deterministisch)

generateDiagramDocs

Ja

Erzeuge einige`.prompt`von dem Graphen, behandelt sie sie via LLM (dogfooding)

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

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

Warum es deterministisch ist (und warum das wichtig ist)

Der Schlüsselpunkt des Pipelines`generateKnowledgeGraphDiagram`(Because the source text is empty, the translation is also empty.)Er ruft kein LLM auf.. Die Transformation`graph.json`→ PlantUML ist eine reine Funktion.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

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

    json --> parser : parse
    parser --> renderer : KnowledgeGraph
    renderer --> puml : render (fonction pure)
}

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

    prompt --> llmSvc
    llmSvc --> model : API call
    model --> puml2 : réponse non-déterministe
}

note bottom of det
Gleicher Input → gleicher Output
Keine Netzwerklatenz
Keine Token-Kosten
Reproduzierbar in CI
end note

note bottom of llm
Gleicher Input → variabler Output
Netzwerklatenz (1-5s)
Token-Kosten
Erfordert einen API-Schlüssel
end note

@enduml

Die konkreten Vorteile:

Vorteil Impact

Reproduzierbarkeit

gleich`graph.json`→ gleiche Abbildung. Genau. Jedes Mal.

Null Kosten

Kein LLM-Aufruf = keine Tokens = keine API-Rechnung.

Null Latenz

Parse + render dauert ~100ms, nicht 1-5 Sekunden.

CI-kompatibel

Es ist kein API-Schlüssel erforderlich. Kein flaky Test aufgrund einer variablen LLM-Antwort.

Versionierbar

Le .puml`generiert ist Text. Man kann es`diff, der Reviewer im PR, in Git versionieren.

Diagramme des Pipelines selbst

Um den Kreis zu schließen, hier ist das Diagramm des Pipelines, wie es vom Plugin generiert würde :

@startuml
skinparam backgroundColor #FEFEFE

participant "Développeur" 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 : execute
Task -> JSON : read
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph

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

Task -> Renderer : render(graph, filters)
Renderer --> Task : code PlantUML

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

@enduml

Integration in die Projektgovernanz

In unserem Projekt integriert sich diese Pipeline in eine EAGER/LAZY-Kontextverwaltungsstrategie für den KI-Agenten. Der Knowledge Graph ersetzt die manuelle Architektur-Dokumentation durch einen strukturierten, abfragbaren und selbst aktualisierenden Graphen.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "EAGER\n(toujours chargé)" 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 — Stratégie\n(sur demande)" as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

package "LAZY — Graphify\n(requêtes ciblées)" as lazy_graph {
    [graph.json] as gj
    [Queries\n(query/path/explain)] as queries
}

package "Pipeline PlantUML\n(auto-généré)" as puml {
    [generateKnowledgeGraphDiagram] as kgTask
    [generateDiagramDocs] as ddTask
    [Diagrammes PNG] as diagrams
}

Agent --> eager : Lit en début de session
Agent ..> lazy_strat : Charge si type détecté
Agent ..> lazy_graph : Query si besoin structurel
kgTask --> diagrams : Déterministe
ddTask --> diagrams : Via LLM

note right of gr
  Condensé du Knowledge Graph
  God nodes + communautés
  Remplace ECOSYSTEM_OVERVIEW
  (225 lignes → 50 lignes)
end note

@enduml

Die Kombination beider Systeme ist komplementär :

  • Die Strategie regelt das WANN und das WIE— Governance, Workflow, Archivierung

  • Graphify verwaltet das WAS und das WO— Struktur des Codes, Beziehungen, gezielte Abfragen

_ Die Sitzungsstrategie verwaltet daswann et le wie(Governance, Workflow, Schwellen), Graphify verwaltet dasWAS et le WO(Struktur des Codes, Beziehungen, gezielte Anfragen). Die Pipeline PlantUML verwaltet dasMit was(deterministische Diagramme, versioniert, stets aktuell). _

Vorbereitung : Checkliste in 5 Minuten

# Schritt Bestellung

1

Graphify installieren

uv tool install graphifyy

2

Ausnahmen konfigurieren

Erstellen`.graphifyignore`

3

Knowledge Graph extrahieren

graphify . --no-viz

4

Die Diagramme generieren

./gradlew generateKnowledgeGraphDiagram

5

Committe die Ergebnisse

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/

Fallstricke und Gegenmaßnahmen

Falle Beschreibung Minderung

zu dichter Graph

Ein großes Projekt erzeugt Hunderte unlesbare Knoten

verwenden`-Pplantuml.kg.maxNodes=30`und nach Community filtern

Zu weite Ausschlüsse

Zu viele Dateien in`.graphifyignore`verringert den Wert des Graphen

Beginnen Sie damit, nur credentials und build zu ausschließen

Richtung der Pfeile

Die INFERRED-Kanten können eine mehrdeutige Richtung haben

Filtern nach`-Pplantuml.kg.edgeTypes=EXTRACTED`nur für bestimmte Beziehungen

veralteter Graph

Der Code ändert sich, aber der Graph wird nicht rekonstruiert

Verwenden`graphify . --update`regelmäßig oder der Git-Hook`graphify hook install`

Aktualisierte Kosten

Inkrementelle Updates sind quasi kostenlos (tree-sitter lokal)

Nur die docs (.adoc) verbrauchen LLM‑Tokens

Was man am Ende erhält

@startuml
skinparam backgroundColor #FEFEFE

rectangle "AVANT" as avant {
    card "Diagrammes dessinés à la main\nToujours obsolètes\nPersonne ne les met à jour" as av1 #FDEDEC
}

rectangle "APRÈS" as apres {
    card "Diagrammes générés automatiquement\nToujours à jour avec le code\nVersionnés dans Git\nDéterministes et reproductibles" as ap1 #E8F8E8
}

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

@enduml

Die konkreten Vorteile

Vorteil Detail

Immer aktuelle Dokumentation

Die Diagramme spiegeln den aktuellen Code, keinen manuellen Snapshot

Kein Wartungsaufwand

Die Diagramme regenerieren sich bei jedem Build

Reduzierung der technischen Schulden

Es ist nicht mehr nötig, die Diagramme manuell zu pflegen.

Visueller Kontext für die neuen

Ein neuer Entwickler versteht die Architektur, indem er die Diagramme betrachtet.

Feintuning-Potential

Die Paare (Untergraph → Diagramm) sind Beispiele für KI-Training

Automatische Validierung

`PlantumlService.validateSyntax()`Überprüft jedes generierte Diagramm

schnelles Onboarding

5 Diagramme = vollständige Ansicht der Architektur

_ Wer ein Warum hat, kann alle Wie ertragen. _

Das warum : Diagramme stets auf dem neuesten Stand. Das wie : zwei Befehle in einer Gradle-Pipeline.

Verwandte Artikel