Strona główna / Artykuły / SHACL TDD dla agentów GraphRAG: jedna zasada ograniczająca działania, która zapobiega nieodpowiednim zachowaniom

SHACL TDD dla agentów GraphRAG: jedna zasada ograniczająca działania, która zapobiega nieodpowiednim zachowaniom

Zakoduj politykę zatwierdzania przez kierownictwo z ograniczeniem odpowiedzialności na 30% w formacie SHACL, udowodnij ją za pomocą pytest, a następnie obserwuj, jak firewall ontologiczny zatrzymuje agenta podczas demonstracji kontraktu o wartości 2,3 miliona dolarów.

1411 słów

Czytanie notatek architektonicznych nie jest tym samym co wdrożenie zasady zarządzania. Ten tekst kontynuuje trójkierową porównanie – zwykłego RAG, GraphRAG oraz GraphRAG w połączeniu z OWL/SHACL/policy – na przykładzie umowy o wartości 2,3 miliona dolarów i koncentruje się na umiejętności przenoszalnej: kodowaniu jednej polityki biznesowej w postaci struktury, jej weryfikacji za pomocą automatycznego sprawdzenia oraz obserwowaniu, jak agent odmawia dalszej pracy.

Repozytorium Ontology RAG Firewall zawiera słownictwo cont:, pliki strukturalne oraz demo offline użyte w tym przykładzie. Sklonuj je, upewnij się, że zestaw działa poprawnie na gałęzi main, a następnie opcjonalnie odtwórz starszy commit, aby osobiście doświadczyć cyklu czerwono-zielonego.

Upewnij się co do stanu bazowego na main

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

Przytwierdzenie do wersji 6318929 jest opcjonalne, jeśli ostatnia zweryfikowana wersja artykułu ma znaczenie; wersja z main może być już nowsza.

Zdrowy wynik pokazuje 18 przetestowanych. Dema offline powinno już wyświetlać ostrzeżenie skierowane do kierownictwa w sekcji dotyczącej odszkodowań, mniej więcej w takim tonie:

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

To właśnie takie ostrzeżenie zostało wprowadzone dzięki nowej strukturze. Pozostała część opisuje, w jaki sposób zostało ono stworzone poprzez podejście rozwijania oparte na testach.

Polityka, która jest kodowana

Jedenastu typów węzłów znajduje się już w pliku contract_domain_shacl.ttl i obejmuje warunki płatności, okresy wypowiedzenia umowy, SLA dotyczące czasu dostępności, wydobywanie informacji o niskiej pewności, luki w środkach naprawczych, automatyczne odnowienie umowy, brak zapisów dotyczących odszkodowań, przegląd bezpośrednich szkód, stosunek limitu do wartości na poziomie 10%, przypadek wysokiej wartości przy niskim bezwzględnym limicie oraz stosunek kierowniczy, na który zwraca uwagę ten przewodnik.

W przypadku umowy demonstracyjnej górna granica w wysokości 575 tys. dolarów stanowi 25% od 2,3 miliona dolarów — co jest wyżej niż dolna granica na poziomie 10% — więc starszy model stosunku pozostaje niewykorzystany. Model kierowniczy eliminuje tę lukę w przypadku drogich umów.

Dodatkowy wymóg działu zakupów, w prostych słowach:

Zawsze, gdy wartość umowy wynosi co najmniej 500 tys. dolarów, a górna granica odszkodowania jest poniżej 30% tej wartości, agent musi uzyskać zatwierdzenie kierownictwa przed podjęciem działań.

To zdanie przekształca się w ExecutiveCapRatioShape wraz z dwoma przypadkami testowymi typu pytest.

Krok 1 — Najpierw nieudana próba

Zawsze twórz przekazanie przed TTL.

W obecnym main te sprawdzenia już przepuszczają testy. Aby doświadczyć niepowodzenia, przejdź do wersji bbeb15e (przed użyciem modelu), wstaw testy, zauważ czerwony kolor, dodaj model z Kroku 2, a następnie wróć do main.

Dodaj lub porównaj ten przypadek w pliku 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

Wykonaj:

pytest tests/test_shacl_constraints.py::test_liability_cap_below_30_percent_on_high_value_contract -v

Jak wygląda czerwień

Zanim kształt istnieje (na przykład w bbeb15e):

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

W obecnym main identyczne wezwanie ma kolor zielony. Następnie przychodzi sam TTL – już połączony w głównym kodzie, odtworzony tak, aby wzorzec mógł być ponownie wykorzystany.

Krok 2 — Stworzenie autora kształtu

Dodaj treść do pliku ontologies/contract_domain_shacl.ttl. Upewnij się, że cont: wskazuje na przestrzeń nazw OWL za pomocą surowego IRI z GitHuba (unikaj tworzenia ścieżki /contract#, która nie jest rozwiązywalna):

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

Budowniczowie instancji tworzą URI pod tą samą bazą (…#instance/).

Czy chcesz odtworzyć proces przy bbeb15e? Wykorzystaj już istniejący URI prefiksu z pliku SHACL tej wersji. W wersji main lepiej użyć surowego IRI, aby ontologia, struktury i testy były spójne.

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)
}
""" ;
    ] .

Trzy wybrane rozwiązania są celowe:

  • FILTER wymagający wartości >= 500000 ogranicza zasadę do transakcji o wysokiej wartości; ta sama procentowa wartość ma inne znaczenie w przypadku umowy o wartości 50 tys. dolarów.
  • Włączenie {?capRatio} do wiadomości skierowanej do ludzi pozwala recenzentom uzyskać dokładny procent zamiast niejasnego ostrzeżenia.
  • Progiem 30% jest polityka organizacji — edytuj tę wartość, jeśli dział prawny wymaga 40%. Sam plik jest dokumentem reprezentującym tę politykę.

Krok 3 — Przyporządkowanie naruszeń do czytelnych klauzul

Kształty wytwarzają naruszenia związane z maszynami; firewall przekształca trafienia kluczowych słów w linie raportu na poziomie klauzul. W pliku main, EXECUTIVE jest już wymieniony wśród tokenów odpowiedzialności w firewall.py:

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

Podczas ponownego uruchamiania bbeb15e należy dodać ten token obok kształtu – w przeciwnym razie demo może obliczyć naruszenie bez powiązania go z klauzulą odszkodowawczą.

Krok 4 — Ponowne uruchomienie zestawu i demo

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

Oczekuj pełnego zestawu w ciągu zaledwie kilku sekund. Raport demo zawiera dedykowaną linię dotyczącą klauzuli odszkodowawczej (liczba flag może pozostać bez zmian, gdy kilka naruszeń dotyczy tej samej klauzuli):

⚠️ 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

Jedna polityka – zakodowana, sprawdzona i widoczna. To właśnie ten cykl umożliwia skalowanie do kolejnych reguł domeny.

Dlaczego nie „po prostu to zapytać”?

Wprowadzanie tych samych wytycznych na poziomie 30% do promptu systemowego zawodzi, gdy prawnik przeformułowuje klauzulę, gdy instrukcja ginie w długim kontekście, gdy ktoś edytuje prompty bez uwzględnienia kontekstu zgodności, lub gdy audytorzy pytają, która wersja zastosowała jaką zasadę w którym dniu.

Kształt jest deterministyczny w przypadku typowanego RDF, znajduje się pod kontrolą wersji, zawiera test regresji, generuje ustrukturyzowane dowody włączając mierzony stosunek, i nie może zniknąć tylko dlatego, że ktoś dążył do większej płynności w innym miejscu.

Rządy dotyczące systemów agentowych wymagają formalnych ograniczeń oprócz funkcji wyszukiwania i generowania. Polityka znajduje się w kształcie; dowód – w teście; tekst naruszenia stanowi artefakt audytu.

Sposób powtarzalnego rozszerzania

docs/extending.md szczegółowo to opisuje; forma skrócona brzmi:

  1. Sformułuj zasadę w języku zrozumiałym dla osoby odpowiedzialnej za zgodność.
  • Rozszerzaj OWL tylko wtedy, gdy potrzebne są nowe typy lub właściwości.
  • Dodawaj jedną strukturę na regułę — mała i oddzielna jest lepsza od monolitu.
  • Zapewnij, aby pytest był czerwony przed strukturą, a zielony po niej.
  • Docelowy stan: każda struktura ma test; każdy test odpowiada konsekwencji biznesowej. Edycje prawne mają określony czas trwania; CI przeprowadza weryfikacje; stan systemu pozostaje poddawalny recenzji.

    Plan rozwoju poza pojedynczą umową

    Dzisiejszy firewall wykorzystuje ścieżki oparte na jednej umowie. Pozostają dwa braki w produkcji: podsumowania partialne dla całego portfela (examples/demo_batch_processing.py jest przykładem) oraz kontekst wieloetapowy dostawcy (przechowujący dane, incydenty) po stworzeniu powiązanego grafu właściwości — a nie tylko adres URL.

    Dopóki to nie nastąpi, ćwicz ten cykl: napisz strukturę, sprawdź ją, obserwuj wynik, a następnie zastosuj ten sam schemat w kolejnej dziedzinie.

    Zachowuj osobny rejestr dla każdego kształtu – właściciela, daty wejścia w życie, identyfikatora notatki źródłowej oraz identyfikatora węzła pytest – aby linia z informacją o winowajcy w git blame mogła zostać rozszerzona na ślad audytowy. Gdy zmieniają się progi, zaktualizuj ciąg znaków z wiadomością oraz dodaj testy graniczne, aby stare wartości nie mogły powrócić bez śladu. Traktuj mapy słów kluczowych→klauzul jako interfejs API: zrób zrzut ekranu wyników demonstracji w CI, aby modyfikacje nie mogły usunąć EXECUTIVE z listy tokenów ochronnych bez powodowania nieudanej pracy. Wolij kształty dodawane od edycji wspólnych bloków SPARQL; niezależne kształty pozwalają na czyste przywrócenie stanu w przypadku niepowodzenia eksperymentu polityki. Wreszcie publikuj zmierzoną wartość stosunku we wszystkich ostrzeżeniach skierowanych do ludzi – recenzenci bardziej ufają liczbom, które mogą ponownie obliczyć na podstawie RDF, niż ogólnym komunikatom typu „wymaga zatwierdzenia”.