Handbücher · Wissensgraphen
Build: Den Graphen abfragen
Lernziele
- Du lädst
edges.csvundtyped_edges.csvin einen gemeinsamen Graphen und erklärst, warum typisierte Kanten die einfachen überschreiben. - Du beantwortest mit vier Befehlen Fragen nach Nachbarn, Wegen, Themen-Clustern und Verbindungen.
- Du liest eine Kette aus
connectsrichtig, auch wenn eine Kante gegen die Laufrichtung zeigt.
Das ist Teil zwei des Builds. Den Graphen extrahieren hat zwei Dateien im obersten Ordner des Vaults hinterlassen: edges.csv mit den einfachen Links und typed_edges.csv mit dem typisierten Durchgang. Diese Lektion macht daraus Antworten, mit einem Python-Skript von rund 80 Zeilen.
Der Store ist NetworkX im Arbeitsspeicher. Das Skript lädt den Graphen bei jedem Aufruf frisch aus den CSV-Dateien. Das ist die zweite Stufe auf der Leiter aus Graph-Stores. Du brauchst weder Server noch Schema-Migration, und bei einem persönlichen Vault dauert das Laden Millisekunden. Du brauchst ein einziges Paket:
python3 -m pip install networkx
Stand Nov. 2026 ist NetworkX 3.7 aktuell. Es verlangt Python 3.12 oder neuer, mit älterem Python installiert pip eine Version 3.6 oder 3.5. Jede Version der Reihe 3.x reicht. Wir haben das Skript mit NetworkX 3.7 unter Python 3.13 und mit 3.5 unter Python 3.11 laufen lassen, die Ausgaben waren gleich. Meldet pip externally-managed-environment, wie bei Python aus Homebrew, legst du ein virtuelles Environment an (python3 -m venv .venv) und startest die Skripte mit .venv/bin/python.
Das Skript
Speichere es im Vault als scripts/graph_query.py:
#!/usr/bin/env python3
"""Fragt den Vault-Graphen ab. Liest edges.csv und typed_edges.csv
aus dem aktuellen Ordner.
Aufruf:
python3 graph_query.py neighbors "Seite"
python3 graph_query.py path "Seite A" "Seite B"
python3 graph_query.py communities
python3 graph_query.py connects "Seite A" "Seite B"
"""
import csv
import os
import sys
import networkx as nx
FILES = ["edges.csv", "typed_edges.csv"]
SKIP = {"index", "log"}
def load():
g = nx.DiGraph()
for name in FILES:
if not os.path.exists(name):
continue
with open(name, encoding="utf-8") as fh:
for row in csv.DictReader(fh):
if row["source"] in SKIP or row["target"] in SKIP:
continue
g.add_edge(row["source"], row["target"],
type=row.get("type", "links-to"))
return g
def neighbors(g, node):
out = [f"-> {t} ({g.edges[node, t]['type']})" for t in sorted(g.successors(node))]
out += [f"<- {s} ({g.edges[s, node]['type']})" for s in sorted(g.predecessors(node))]
return "\n".join(out) or "Keine Links."
def path(g, a, b):
try:
return nx.shortest_path(g.to_undirected(as_view=True), a, b)
except (nx.NetworkXNoPath, nx.NodeNotFound):
return None
def communities(g):
found = nx.community.label_propagation_communities(g.to_undirected())
groups = sorted((sorted(c) for c in found), key=len, reverse=True)
return "\n".join(f"[{len(c)}] " + ", ".join(c) for c in groups)
def connects(g, a, b):
p = path(g, a, b)
if p is None:
return f"Nichts verbindet {a} und {b}."
hops = []
for s, t in zip(p, p[1:]):
d = g.get_edge_data(s, t)
hop = f"{s} -[{d['type']}]-> {t}" if d else f"{s} <-[{g.edges[t, s]['type']}]- {t}"
hops.append(hop)
return "\n".join(hops)
if __name__ == "__main__":
g = load()
cmd, args = (sys.argv[1:] or ["hilfe"])[0], sys.argv[2:]
missing = [a for a in args if a not in g]
if missing:
print("Keine Kante kennt diese Seite: " + ", ".join(missing))
elif cmd == "neighbors":
print(neighbors(g, args[0]))
elif cmd == "path":
print(" -> ".join(path(g, args[0], args[1]) or ["Kein Weg."]))
elif cmd == "communities":
print(communities(g))
elif cmd == "connects":
print(connects(g, args[0], args[1]))
else:
print(__doc__)Zeilen 1-10
Vier Befehle, jeder mit Seitennamen in Anführungszeichen. Der Hilfetext ist zugleich die Ausgabe, wenn du keinen oder einen unbekannten Befehl angibst.
Zur Bauweise, kurz. Die typisierten Kanten kommen nach den einfachen, also gewinnt die bessere Beschreibung desselben Links. In unserem Test-Vault aus der letzten Lektion wurde so aus Jerry Liu → LlamaIndex (links-to) die Kante built. Wege laufen über eine ungerichtete Sicht, weil die Frage „Wie hängen die zusammen?“ keine Richtung kennt. Und Label Propagation steht für den Leiden-Schritt aus GraphRAG. Das Verfahren ist gröber, braucht aber nur NetworkX und ist bei dieser Größe sofort fertig. In unserem Test lieferte es bei drei Läufen dreimal dieselben Cluster.
Drei Stellen haben wir nach dem Test ergänzt: das Überspringen von index und log, die Meldung für unbekannte Seiten und den Hilfetext ohne Argument. Ohne den ersten Punkt meldete das Skript eine einzige Community mit 15 Seiten, und der Weg von „Nelson Liu“ zu „Neo4j“ lief über den Index.
Was jeder Befehl beantwortet
Alle Ausgaben stammen aus dem Test-Vault der letzten Lektion:
$ python3 scripts/graph_query.py neighbors "RAG"
-> GraphRAG (links-to)
-> LlamaIndex (uses)
<- GraphRAG (extends)
<- Jerry Liu (links-to)
<- Lange Kontexte ersetzen RAG (links-to)
<- LlamaIndex (links-to)
<- Lost in the Middle (links-to)
$ python3 scripts/graph_query.py communities
[7] Darren Edge, From Local to Global, GraphRAG, Graphen helfen bei Multi-Hop-Fragen, Neo4j, NetworkX, Wissensgraph
[6] Jerry Liu, Lange Kontexte ersetzen RAG, LlamaIndex, Lost in the Middle, Nelson Liu, RAG
neighbors zeigt eine Seite mit allen direkten Verbindungen in beide Richtungen und benennt jede Beziehung. communities ist die Themenebene: eine Zeile pro Community · engl. communityEine Gruppe von Knoten, die untereinander dicht verbunden sind und zum Rest des Graphen wenige Kanten haben. Algorithmen wie Leiden finden sie automatisch.Im Glossar, die größte zuerst. Die Seite „Notiz Zettel“ fehlt in beiden Clustern, weil sie keinen Link hat. Fragst du nach ihr, antwortet das Skript „Keine Kante kennt diese Seite“.
Welcher Befehl?
Ordne jede Frage dem Befehl zu, der sie beantwortet.
Noch offen (4)
- Welche Seiten verlinken auf „RAG“, und mit welchem Typ?
- Über welche Seiten komme ich von „Nelson Liu“ zu „Neo4j“? Die Typen sind mir egal.
- Welche Themen hat mein Vault, und welches ist das größte?
- Warum hängen „Darren Edge“ und die These „Lange Kontexte ersetzen RAG“ zusammen?
neighbors (0)
path (0)
communities (0)
connects (0)
Was X und Y verbindet
Für diese Frage gibt es den Build. connects liefert die kürzeste Kette zwischen zwei Seiten, jede Etappe mit Typ:
$ python3 scripts/graph_query.py connects "Nelson Liu" "Neo4j"
Nelson Liu -[authored]-> Lost in the Middle
Lost in the Middle -[links-to]-> RAG
RAG -[links-to]-> GraphRAG
GraphRAG -[links-to]-> Wissensgraph
Wissensgraph -[uses]-> Neo4j
$ python3 scripts/graph_query.py connects "Jerry Liu" "Lost in the Middle"
Jerry Liu -[links-to]-> RAG
RAG <-[links-to]- Lost in the Middle
Das ist ein berechneter Multi-Hop-Frage · engl. multi-hop questionEine Frage, deren Antwort Fakten aus mehreren Dokumenten verknüpft. Kein einzelner Textabschnitt enthält sie.Im Glossar-Join. Genau an dieser Frage scheitert reine Vektorsuche, wie Warum Wissensgraphen zeigt. Lies die zweite Zeile der zweiten Kette genau: RAG <-[links-to]- Lost in the Middle heißt, dass „Lost in the Middle“ auf „RAG“ verlinkt.
Der kürzeste Weg zählt Etappen und achtet nicht auf Typen. Gibt es eine typisierte Kette über drei Etappen und einen einfachen Link über zwei, gewinnt der Link. Im Test lief die Kette von „Jerry Liu“ deshalb über den Link auf „RAG“ und ließ die Kante built zu LlamaIndex liegen. Die Kette ist trotzdem richtig, sie beschreibt nur weniger. Je mehr typisierte Kanten der Extraktions-Durchgang findet, desto öfter enthalten die kürzesten Wege Typen.
connects ist eine einfache Funktion: zwei Zeichenketten hinein, eine Zeichenkette heraus. Genau diese Form braucht ein Tool · engl. toolEin Werkzeug, das das Modell aufrufen kann: eine API, eine Datenbankabfrage, ein Shell-Befehl, eine Suche. Über Tools wirkt das Modell auf die Welt.Im Glossar für einen Agenten. Wie du es anschließt, zeigt Den Graphen in den Loop holen.
Merksätze
- NetworkX im Arbeitsspeicher reicht für einen persönlichen Vault. Das Skript lädt beide CSV-Dateien bei jedem Aufruf neu.
- Typisierte Kanten überschreiben die einfachen Links zwischen demselben Paar, weil sie die Beziehung genauer beschreiben.
- index und log gehören vor jeder Abfrage aus dem Graphen, sonst laufen Wege über sie, und alle Themen verschmelzen.
- connects liefert eine berechnete Kette mit Typen.
<-bedeutet, dass die Kante gegen die Leserichtung zeigt. - Der kürzeste Weg bevorzugt keine typisierten Kanten. Mehr Typen in der Extraktion machen die Ketten aussagekräftiger.
Prüf dich selbst
Denkfrage
Warum sucht das Skript Wege über eine ungerichtete Sicht des Graphen?
Die Frage, wie zwei Seiten zusammenhängen, hängt nicht davon ab, wer wen verlinkt hat. Im gerichteten Test-Graphen führt von „Jerry Liu“ aus keine Kette von Kanten zu „Lost in the Middle“, nur umgekehrt. Die Richtung geht trotzdem nicht verloren: connects schreibt sie in jede Etappe.
Denkfrage
Was passiert, wenn du index und log nicht überspringst?
Der Index verlinkt jede Seite. Fast jeder kürzeste Weg führt dann in zwei Schritten über den Index, und Label Propagation legt alle Seiten in eine Community. Im Test-Vault ergab das eine einzige Community mit 15 Seiten statt zwei Themen.
Prüf dich selbst
Selbst nachweisen
0 von 3 erledigt
Quellen
- NetworkX auf PyPI
Version 3.7 vom September 2026, verlangt Python 3.12 oder neuer.
- NetworkX: shortest_path
- NetworkX: label_propagation_communities
Semi-synchrone Label Propagation.
- PEP 668: Python-Umgebungen als extern verwaltet markieren
Hintergrund zur Meldung externally-managed-environment.