Veröffentlicht 30. Juli 2026
Warum man einen Störungsorchestrator als Graphen mit Checkpoints bauen sollte
Warum kein Skript
Die Bearbeitung einer Störung auf einer Backbone-Strecke wirkt linear, bis man versucht, sie zu programmieren. Das Monitoring legt ein Ticket an, danach muss man die Beschreibung auswerten, sich mit beiden Enden der Strecke verbinden, optische Messwerte und die Schnittstellenkonfiguration erfassen, eine Einschätzung treffen, den Port deaktivieren, eine Aufgabe für den Außendienst anlegen und warten. Das Warten kann eine Stunde oder drei Tage dauern, bis der Trupp die Spleißmuffe erreicht.
Ein Skript übersteht das nicht. Es bricht beim ersten Deployment des Dienstes ab, und mit ihm geht das Wissen verloren, dass der Port bereits deaktiviert ist und ein Trupp unterwegs ist.
Deshalb ist das Szenario als Zustandsgraph mit LangGraph aufgebaut, und der Graphzustand wird in PostgreSQL-Checkpoints gespeichert. Nach einem Neustart des Dienstes bleibt der Kontext erhalten, und der Prozess setzt an dem Knoten fort, an dem er angehalten hat.
Entscheidung 1: Das LLM verbindet sich nie mit Geräten
Es ist sehr verlockend, dem Modell CLI-Zugriff zu geben, und genau das sollte man vermeiden. Die Zuständigkeiten im System sind streng getrennt:
- deterministischer Code verbindet sich über NETCONF/PyEZ, wertet Ausgaben aus und spielt Konfigurationen ein;
- das Modell arbeitet nur mit Text und einem kompakten JSON-Auszug der Diagnose, aus dem es eine Einschätzung für den Ingenieur erstellt.
Jede Änderung am Netz läuft über Code, den man lesen und mit Tests abdecken kann. Das Modell beeinflusst Formulierungen und Einschätzungen wie „sieht nach einem Faserbruch aus“, führt aber nie einen commit aus.
Der Ansatz hat einen angenehmen Nebeneffekt: Der Auszug benötigt um ein Vielfaches weniger Tokens als die rohe Befehlsausgabe.
Entscheidung 2: commit confirmed
Junos kann Konfigurationen selbstständig zurücksetzen:
# der Rollback-Timer läuft auf dem Gerät selbst
cu.commit(confirm=10, comment="incident <ticket>: deactivate port")
# ... ein Ingenieur bestätigt in der Oberfläche ...
cu.commit() # Festschreiben; ohne diesen Schritt setzt das Gerät zurück
Das verändert das Verhalten des Systems bei Fehlern. Stürzt der Orchestrator ab, verliert er die Verbindung oder irrt er sich, kehrt der Port ohne unser Zutun in den Ausgangszustand zurück, weil der Timer auf dem Gerät selbst läuft. Der Mensch bleibt dabei in der Schleife, denn die Bestätigung der Änderung ist seine Aufgabe.
Entscheidung 3: zuerst Dry-Run
Die erste Projektphase läuft bewusst ohne einen einzigen echten commit. Statt die Konfiguration einzuspielen, berechnet der Orchestrator einen diff und protokolliert, was er getan hätte:
WOULD COMMIT on <device-a>:
[edit interfaces xe-0/0/0]
+ inactive: gigether-options
Diese Phase wirkt langweilig, ist aber sehr nützlich. Im Dry-Run wird sichtbar, wo der Parser an ungewöhnlichen Ticketbeschreibungen scheitert, wo die Diagnose zu falschen Schlüssen kommt und welche Paare von Streckenenden im Inventar fehlen. All das erfährt man besser aus einem Log als aus einem Incident.
Was noch offen ist
Das Format der Ticketbeschreibung ist nicht vertraglich festgelegt. Es entsteht aus einer Vorlage des Monitoringsystems, und diese Vorlage ändert sich. Der Parser kommt mit allen bisher gesehenen Varianten zurecht, und wenn die Liste der Schnittstellen leer ist, hält er an und ruft einen Menschen hinzu. Das ist wohl das wichtigste Prinzip des gesamten Systems: Die Automatisierung darf die Arbeit verweigern.