Startseite / Artikel / SHACL TDD für GraphRAG-Agenten: Eine einzige Ausführungskapazitätsregel, die schlechte Aktionen verhindert

SHACL TDD für GraphRAG-Agenten: Eine einzige Ausführungskapazitätsregel, die schlechte Aktionen verhindert

Einen mit einer 30-prozentigen Haftungsgrenze versehenen Richtlinienentwurf für die Zustimmung von Führungskräften in SHACL kodieren, dies mit pytest überprüfen und beobachten, wie eine Ontologie-Feuerwand einen Agenten bei einer Demonstration eines Vertrags im Wert von 2,3 Millionen Dollar blockiert.

1411 Wörter

Das Lesen von Architekturnotizen ist nicht dasselbe wie das Implementieren einer Governance-Regel. Dieser Artikel baut auf einem dreiseitigen Vergleich – herkömmliches RAG, GraphRAG sowie GraphRAG in Kombination mit OWL/SHACL/policy – anhand eines Mustervertrags im Wert von 2,3 Millionen Dollar auf und konzentriert sich auf eine übertragbare Fähigkeit: Eine Geschäftsrichtlinie als Struktur kodieren, sie mittels automatischer Überprüfung beweisen und beobachten, wie der Agent die Weiterarbeit verweigert.

Das Repository Ontology RAG Firewall enthält das cont:-Wörterbuch, die Shape-Dateien sowie die hier verwendete Offline-Demo. Klonen Sie es, überprüfen Sie, ob das Paket auf main in Ordnung ist, und spielen Sie gegebenenfalls einen älteren Commit ab, um den roten-grünen Zyklus selbst zu erleben.

Die Baseline auf main überprüfen

git clone https://github.com/cloudbadal007/ontology-rag-firewall
cd ontology-rag-firewall
pip install -e ".[dev]"
pytest -q                    # 18 passed (full suite)
python examples/demo_offline.py

Das Festhalten an 6318929 ist optional, sofern der letzte überprüfte Tipp des Artikels relevant ist; der Tipp auf main könnte bereits neuer sein.

Ein gesunder Lauf zeigt 18 bestanden. Die Offline-Demo sollte bereits eine für Führungskräfte gerichtete Warnung im Abschnitt zur Haftungsfreistellung anzeigen, in etwa wie folgt:

Safe to act: 🚫 NO
- Flagged: 5
...
⚠️ EXECUTIVE APPROVAL: Liability cap is below 30% of contract value. Cap ratio: 25.00%. Agent action requires executive sign-off.
...
AGENT ACTION: HALTED. Routed to human review queue.
Total value protected: $2,300,000

Genau diese Warnung wurde durch die neue Struktur eingeführt. Der Rest beschreibt, wie sie durch entwicklungsorientierte Tests entstanden ist.

Die kodierten Richtlinien

Elf Knotenstrukturen sind bereits in contract_domain_shacl.ttl enthalten und umfassen Zahlungsbedingungen, Ankündigungsfristen, Uptime-SLA-Vorgaben, Extraktion bei geringer Zuverlässigkeit, Lücken in den Abhilfemöglichkeiten, Automatikverlängerung, fehlende Haftungsfreistellungsformulierungen, Überprüfung direkter Schäden, ein 10%-Obergrenzverhältnis zum Wert, einen Fall mit hohem Wert und niedriger absoluter Obergrenze sowie die von dieser Übersicht hervorgehobene Führungskräfverhältnis-Struktur.

In Bezug auf den Demo-Vertrag beträgt die Obergrenze von 575.000 $ 25% von 2,3 Mio. $ – was über der 10%-Untergrenze liegt – wodurch die ältere Verhältnisform unberührt bleibt. Die Executive-Form schließt dieses Blindfeld bei teuren Vereinbarungen.

Die zusätzliche Anforderung der Einkaufsabteilung in einfachen Worten:

Sobald der Wert einer Vereinbarung mindestens 500.000 $ beträgt und die Entschädigungs-Obergrenze unter 30% dieses Wertes liegt, muss ein Agent vor Handlung eine Genehmigung der Führungsebene einholen.

Dieser Satz wird zu ExecutiveCapRatioShape zusammen mit einem Paar pytest-Tests.

Schritt 1 – Zuerst fehlschlagen lassen

Schreiben Sie immer die Assertion vor dem TTL.

In der heutigen main-Version bestehen diese Überprüfungen bereits. Um den Fehler zu spüren, wechseln Sie zu bbeb15e (Vorform), fügen Sie die Tests ein, beobachten Sie das Rote, fügen Sie dann die Form aus Schritt 2 hinzu und kehren Sie schließlich zu main zurück.

Fügen Sie diesen Fall hinzu oder vergleichen Sie ihn in tests/test_shacl_constraints.py:

def test_liability_cap_below_30_percent_on_high_value_contract() -> None:
    """
    25% cap on a $2.3M contract must trigger ExecutiveCapRatioShape.
    Existing shapes (10% ratio, $100K absolute) do not catch 575K / 2.3M.
    """
    clause = ExtractedClause(
        "test-cap-ratio",
        "LiabilityClause",
        "text",
        {"liabilityCap": 575_000, "liabilityScope": "DirectDamagesOnly"},
        0.9,
        1,
    )
    graph = ClauseRDFBuilder().build(clause, 2_300_000)
    conforms, violations, _ = SHACLContractValidator().validate(graph)
    assert not conforms
    assert any(
        "30%" in v or "executive" in v.lower() for v in violations
    ), violations

def test_liability_cap_at_32_percent_no_executive_flag() -> None:
    """32.6% cap on $2.3M should not trigger the 30% executive rule."""
    clause = ExtractedClause(
        "test-cap-ratio-ok",
        "LiabilityClause",
        "text",
        {"liabilityCap": 750_000, "liabilityScope": "FullDamages"},
        0.9,
        1,
    )
    graph = ClauseRDFBuilder().build(clause, 2_300_000)
    _, violations, _ = SHACLContractValidator().validate(graph)
    cap_ratio_hits = [
        v for v in violations if "30%" in v or "executive" in v.lower()
    ]
    assert len(cap_ratio_hits) == 0, cap_ratio_hits

Führen Sie aus:

pytest tests/test_shacl_constraints.py::test_liability_cap_below_30_percent_on_high_value_contract -v

Wie Rot aussieht

Vor dem Bestehen der Form (zum Beispiel bei bbeb15e):

FAILED tests/test_shacl_constraints.py::test_liability_cap_below_30_percent_on_high_value_contract
AssertionError: ... executive ...

In der aktuellen main-Version ist die identische Aufrufung grün. Danach kommt das TTL selbst – es wurde bereits in die Quelle integriert und erneut erstellt, damit das Muster wiederverwendet werden kann.

Schritt 2 – Erstellen Sie die Form

Fügen Sie sie zu ontologies/contract_domain_shacl.ttl hinzu. Stellen Sie sicher, dass cont: über den rohen GitHub IRI auf den OWL-Namespace verweist (vermeiden Sie es, einen /contract#-Pfad zu erstellen, der nicht auflösbar ist):

https://raw.githubusercontent.com/cloudbadal007/ontology-rag-firewall/main/ontologies/contract_domain_owl.ttl#

Instanzierer erzeugen URIs unter derselben Basis (…#instance/).

Wiederholen auf bbeb15e? Verwenden Sie den bereits im SHACL-Datei dieser Revision enthaltenen Präfix-URI. Bei der Spalte main sollte man den rohen IRI bevorzugen, damit Ontologien, Shapes und Tests übereinstimmen.

cont:ExecutiveCapRatioShape a sh:NodeShape ;
    sh:targetClass cont:LiabilityClause ;
    sh:severity sh:Warning ;
    sh:message "⚠️ EXECUTIVE APPROVAL: Liability cap is below 30% of contract value. Cap ratio: {?capRatio}%. Agent action requires executive sign-off." ;
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:select """
PREFIX cont: <https://raw.githubusercontent.com/cloudbadal007/ontology-rag-firewall/main/ontologies/contract_domain_owl.ttl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT $this ?capRatio WHERE {
  ?contract cont:hasLiabilityClause $this ;
            cont:contractValue ?v .
  $this cont:liabilityCap ?cap .
  BIND((xsd:decimal(?cap) / xsd:decimal(?v) * 100) AS ?capRatio)
  FILTER (xsd:decimal(?v) >= 500000)
  FILTER (?capRatio < 30)
}
""" ;
    ] .

Drei Gestaltungsentscheidungen sind beabsichtigt:

  • Der FILTER, der den Wert >= 500000 erfordert, beschränkt die Regel auf Geschäfte mit hohen Werten; derselbe Prozentsatz bedeutet etwas anderes bei einer SOW im Wert von 50.000 $.
  • Durch Einbetten von {?capRatio} in die menschliche Nachricht erhalten die Prüfer den gemessenen Prozentsatz anstelle einer vagen Warnung.
  • Die 30%-Schwelle ist eine organisatorische Richtlinie – ändern Sie den Wert, wenn die Rechtsabteilung 40 % verlangt. Die Datei ist das Dokument dieser Richtlinie.

Schritt 3 – Verknüpfung von Verstößen mit verständlichen Klauseln

Formen erzeugen Maschinenverstöße; die Firewall wandelt Schlüsselwortauftretungen in Berichtszeilen auf Klauselebene um. In main ist EXECUTIVE bereits in firewall.py unter den Haftungstoken aufgeführt:

"LiabilityClause": ["LIABILITY", "LOW CONFIDENCE", "LEGAL REVIEW", "HIGH-VALUE", "EXECUTIVE"],

Beim Wiedergeben von bbeb15e sollte dieser Token zusammen mit der Form hinzugefügt werden – andernfalls könnte die Demo den Verstoß berechnen, ohne ihn der Haftungsklausel zuzuordnen.

Schritt 4 – Suite und Demo erneut ausführen

pytest -q                         # 18 passed (entire repo)
pytest tests/test_shacl_constraints.py -v   # 8 passed (this file)
python examples/demo_offline.py

Die gesamte Suite sollte in wenigen Sekunden bereitstehen. Der Demo-Bericht enthält eine eigene Zeile für die Haftungsklausel (die Flaggenzahlen können konstant bleiben, wenn mehrere Verstöße dieselbe Klausel betreffen):

⚠️ EXECUTIVE APPROVAL: Liability cap is below 30% of contract value. Cap ratio: 25.00%. Agent action requires executive sign-off.
AGENT ACTION: HALTED. Routed to human review queue.
Total value protected: $2,300,000

Eine Richtlinie, die kodiert, überprüft und sichtbar ist. Dieser Zyklus ermöglicht die Erweiterung auf weitere Domänenregeln.

Warum nicht einfach „danach fragen“?

Das Hineinpressen derselben 30%-Leitlinie in einen Systemprompt versagt, wenn der Berater den Klauseltext umformuliert, wenn die Anweisung in einem langen Kontext untergeht, wenn jemand Prompts ohne Kontext zur Einhaltung der Vorgaben bearbeitet oder wenn Prüfer fragen, welche Version an welchem Tag welche Regel angewandt hat.

Eine Struktur ist bei typischem RDF deterministisch, wird im Versionskontrollsystem verwaltet, verfügt über einen Regressionstest, liefert strukturierte Beweise einschließlich des gemessenen Verhältnisses und kann nicht verschwinden, nur weil jemand anders auf Flüssigkeit der Ausgabe achtet.

Die Steuerung agenter Systeme erfordert neben Such- und Generierungsmechanismen formale Einschränkungen. Die Richtlinien befinden sich in der Struktur; die Beweise im Test; der Text der Verletzung ist das Prüfprotokoll.

Wiederholbares Erweiterungsverfahren

docs/extending.md erläutert dies ausführlich; die Kurzform lautet:

  1. Formulieren Sie die Regel in einer Sprache, die der Verantwortliche für die Einhaltung kennt.
  • Erweitern Sie OWL nur dann, wenn neue Typen oder Eigenschaften erforderlich sind.
  • Fügen Sie pro Regel eine Struktur hinzu – kleine, trennbare Strukturen sind besser als ein Monolith.
  • Sorgen Sie dafür, dass der pytest vor der Struktur rot und danach grün ist.
  • Zielzustand: Jede Struktur hat einen Test; jeder Test bezieht sich auf eine geschäftliche Konsequenz. Rechtliche Änderungen werden zeitlich begrenzt; CI führt Überprüfungen durch; die Struktur bleibt überprüfbar.

    Roadmap jenseits einer einzigen Vereinbarung

    Die heutige Firewall nutzt eine-Vereinbarung-Pfade. Es bleiben zwei Produktionslücken: Batch-Zusammenfassungen für ein ganzes Portfolio (examples/demo_batch_processing.py dient als Beispiel) sowie ein Vendor-Multi-Hop-Kontext (mit Informationen zu Lagerbeständen und Vorfällen), sobald ein verknüpftes Eigenschaftsgraph existiert – nicht nur eine Platzhalter-URL.

    Bis dahin üben Sie den Zyklus: Schreiben Sie die Struktur, überprüfen Sie sie, beobachten Sie das Ergebnis und wenden Sie dann dasselbe Muster auf den nächsten Bereich an.

    Führen Sie für jede Form ein separates Register – mit Eigentümer, Inkrafttrittsdatum, Quellennotiz-ID und pytest-Node-ID – damit sich eine git-blame-Anzeige in einen Prüfverlauf verwandelt. Wenn Schwellenwerte geändert werden, versionieren Sie den Nachrichtentext und fügen Sie Grenzwerttests hinzu, damit alte Schwellenwerte nicht stillschweigend wieder in Kraft treten. Behandeln Sie Schlüsselwort→Klausel-Verbindungen als API-Schnittstelle: Erstellen Sie Snapshots der Demo-Ausgaben in CI, damit Umbauten EXECUTIVE nicht ohne fehlgeschlagenen Job aus der Liste der Haftungstoken entfernen können. Ziehen Sie additive Formen vor dem Bearbeiten gemeinsamer SPARQL-Datenblöcke vor; unabhängige Formen kehren bei fehlgeschlagenen Policy-Experimenten sauber in ihren ursprünglichen Zustand zurück. Veröffentlichen Sie schließlich das gemessene Verhältnis in jeder für Menschen zugänglichen Warnung – Überprüfer vertrauen Zahlen, die sie aus dem RDF neu berechnen können, mehr als allgemeinen „Benötigt Genehmigung“-Bannern.