SHACL TDD для агентаў GraphRAG: Адна правіла кантролю, яка зупіняе небяспечныя дзеяння
Кодавайце політику з максымальным рызыкам 30% для адзынавання керуючыхяктароў у формате SHACL, падтвердзіце яе за дапамою pytest, і старайцеся пабачыць, як брандмауэр онтологіі зупініць агента пад час дэманстрацыі контракту на суму 2,3 мільйона долераў.
Чытанне нотатак пра архітектуру не ўзмаўляецца з выкананнем правіла керавання. У этай статыце, якая ўзьмліваеся пасля трывайшага порэвання — звычайнага RAG, GraphRAG і GraphRAG, адгуканага да OWL/SHACL/policy — на прыкладзе даговора за $2,3 млн, акцэнт ставіцца на пераносныя навыкі: закодаваць аднае бізнес-правіло у вобраз, падтвердзіць яго за дапамогою автаматызаванай перацэнкі і спакульгаваць, як агент адмовіцца прыняць рашэнне.
У репазітарые Ontology RAG Firewall знаходзяцца слоўнік cont:, файлы вобразаў і офлайн-дэманстрацыя, якія викорыстаны тут. Клонаваце яго, пераканайцеся, што весь комплект працуе нормальна на рэпозітарые main, а потым, за жаданнем, запускайце старэйшы коміт, каб лячна пазнакаць цикл «чырвоны-зелены».
Пераканайцеся, што базовы стан на 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
Фіксацыя на версіі 6318929 є необавязковай, якщо важна пасляпэўнай перакананая падказка статыцы; падказка з рэпозітарые main можа вже быць новейшай.
Здаровы рэзультат паказвае 18 прынятыя. У дэмаверсіі без падзейчання з’яўляецца апавешчэнне, спрытнае да керуючых апошніх рашэнняў, у раздзеле пра аблегчэнне наследкав, падобнае гэтаму:
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
Гэтае апавешчэнне – гэта самае, што было уведзена ў новай версіі. Рэштка тексту апісвае, як гэта было реалізавана за дапамогою падходу разработкі, спачатку тэставання.
Політыка, якая кодуецца
Адзіннаццаць форматаў вузлаў уже ўключаныя ў contract_domain_shacl.ttl і абходзяць такія аспекты, як умовы платежаў, тэрміны паведамлення, стандарты пра час выконання, выкарыстоўванне данных з низкім рэвераментам, прычыны неадекватных заходаў, аўтоперазнавленне, відсутнасць тэкста пра аблегчэнне наследкав, перагляд прымітных збиткаў, ступенек 10% ад вялічыны, кейсы з вялікай вялічынай, але низкім абсалютным лімітом, а таксама ступенек для керуючых, які падкрэсляецца ў гэтым кароткам узорку.
У дэмаверсійнай угодзе максімацыя 575 тысяч долераў станавіць 25% ад 2,3 мільйона долераў — гэта больш, чым 10% мінімаў — таму старая формула спявазоў не працюе. Формула для керуючых адпавядае за усуненне гэтай слепой зоны для дорогіх угод.
Дадатковая патрабовання аддзелу закупкаў, простымі словамі:
Калі значэнне угоды станавіць прынямна 500 тысяч долераў, а максімацыя компенсацыі ўскладнюецца менш чым 30% ад гэтага значэння, агент должен атрымаць санкцію керуючага пры выконанні дзеяння.
Гэты абставект выклікае ExecutiveCapRatioShape плюс пару тэстаў на pytest.
Шаг 1 — Спачатку выклікайце абракаданне
Заўжды стварайце асэрцыю раней, чым TTL.
У сучасным main гэтыя пераказы вже праходзяць. Чыба відчуць абракаданне, перайдзіце да bbeb15e (перадвыконаная версія), дадзіце тэсты, пабачыце червоны кольор, дадзіце формулу з Шага 2, а потым верніцеся да main.
Дадзіце або парабялейце гэты кэс у 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
Выконайце:
pytest tests/test_shacl_constraints.py::test_liability_cap_below_30_percent_on_high_value_contract -v
Як выглядае цяплёны колер
До таго, калі форма існуе (на прыклад, у bbeb15e):
FAILED tests/test_shacl_constraints.py::test_liability_cap_below_30_percent_on_high_value_contract
AssertionError: ... executive ...
У ныяшнам main ідэнтычны вызов выглядае зелёным. Далей прыходзіце сам TTL — ён вялікі час існавання, які ўжо быў з’едынены вышэй, і яго воспроізводзяць, каб шаблон могаў быць викорыстаны знову.
Шаг 2 — Стварэнне формы
Дадзіце ў ontologies/contract_domain_shacl.ttl. Зберагаце cont: так, каб ён вяліў на простор імен OWL чераз сыры IRI з GitHub (ухіліцеся ад стварэння шляха /contract#, які не рашуецца):
https://raw.githubusercontent.com/cloudbadal007/ontology-rag-firewall/main/ontologies/contract_domain_owl.ttl#
Стваральнікі экзантэйнаў ствараюць URI пад тым жа базовым шляхам (…#instance/).
Павтараць на bbeb15e? Оспользуйце прымусовы патэрн URI, які ўжо є у файле SHACL той версіі. У режыме main лепш выкарыстоўваць чысты IRI, каб онтологія, форматы та тэсты былі супагодны.
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)
}
""" ;
] .
Тры выборы дизайну зроблены намеравана:
FILTER, які выкалічвае значэнне>= 500000, прызначаны для справ з вялікімі значэннямі; тае жа прыцэнтна цыфра мае іншы значэнне для замовлення на $50K.- Уключэнне
{?capRatio}у людскі текст дае рэвізорам точна вымерана прыцэнтна цыфру замест абстрактнага паведамлення пра апазыранне. - Праграма 30% — це правіла організацыі; якшо юрысты хочуць 40%, трэба зменіць гэтае значэнне. Сам файл являецца артыкулом правіла.
Шаг 3 — Спраўаць наявныя адхыленні да чытабельных пунктаў
Форматы выдаюць супакошанні машыны; захістная станова ператварае падзейкі ключоўых слоў у лініі звястака на рэжыме клазу. У main EXECUTIVE ўжо знаходзіцца сярод токенав адпаведальнасці ў firewall.py:
"LiabilityClause": ["LIABILITY", "LOW CONFIDENCE", "LEGAL REVIEW", "HIGH-VALUE", "EXECUTIVE"],
Калі переглядаеце bbeb15e, дадзіце гэты токен разам з форматам — іншаўна дэманстрацыя можа вылічыць супакошанне без прыўязкі яго да клазу адпаведальнасці.
Шаг 4 — Зноў запуск набора тэстаў і дэманстрацыі
pytest -q # 18 passed (entire repo)
pytest tests/test_shacl_constraints.py -v # 8 passed (this file)
python examples/demo_offline.py
Можна чакаць завершэння всего набора за калькі секунд. У звястку дэманстрацыі з’яўляецца спецыяльная лінія для клазу адпаведальнасці (колькасць флагоў можа застацца незменнай, калі калькі супакошанняяў дзелюцца адним клазам):
⚠️ 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
Адна політыка, закодаваная, падтверджаная і видныя. Гэты цыкл і є тым, што дазволяе пераходзіць да наступнага правіла домэна.
Чаму не «проста запытаць яго»?
Застосаванне таго ж 30% керавання ў системны прампт не дапамагае, калі адвакат перафразуе клазу, калі інструкцыя трапляецца ў дужа дзьвінкам контэксте, калі хтось рэдагуе прампты без урахоўвання контекста салідарнасці, або калі аудытары спытаюць, якая версія застосавала якое правіле ў які дзень.
Форма ёсць дэтэрміністычная для типаванага RDF, знаходзіцца пад кантролем версій, мае тэст на регрэсію, выдавае структураваныя доказы, укладаючы ў сабе вымераныя співважанні, і не можа зникнуць таму, што хтось прагнаў лёгкасці ў іншым месца.
Управліне для агентных систем патрабуе формальных обмежэнняя паляглых на выкарыстоўванні дадзенняў і стварэнні тэкста. Палітыка знаходзіцца ў форме; доказы — у тэстах; текст аб наявнасці аблучэння ёсць результатам аудыту.
Схема павторныя расшырэння
docs/extending.md деталізуе гэта; кароткая форма ёсць:
- Указаць правіле мовай, яку розумее адпаведальны за салідарнасць.
Цільны стан: кожны шэйп мае тест; кожны тест адпавядае якой-небудзь бізнес-наследку. Змены правіл адбываюцца за певны час; системы CI атрымляюць падтверджэнняя; стан системы застаецца падлежачым перагляду.
План развіцці палягчэння за межамі адной даговорнасці
Сягавая захист гэткі час выкарыстоўвае толькі адну-даговорнасць модель. Існуюць два недагавораныя аспекты: падсумовванне пакетаў дадзеных у всім портфеле (examples/demo_batch_processing.py ўжо є прыкладам), а таксама контекст багацальных переходаў з боку прадавца (зберагчыце інформацыю пра інцидэнты), калі будзе створаныя граф атрыбутаў — не проста статычны URL.
Даколі гэта не будзе рэалізавана, практыкуйце такі цыкл: напісайце шэйп, пераканаўцеся ў яго правільнасці, старанна перагляньце рэзультаты, а потым застосавайце той жа падход у наступныя сферы.
Для кожнай формы трэба ведаць додатковы журнал — власніка, дату запуску, ідэнтыфікатор прыметкі з джерела і ідэнтыфікатор вузла pytest — так кожны рядок з паведамленням git blame стане часткай летапа аудыту. Калі змянююцца прагі, трэба версіяваць строку з паведамленням і дадзіць тэсты на межы, каб старыя прагі не моглі непазначальна вернуцца. Спрыяйце викорыстоўванню карточак «ключавая слова → клазулі» як часткі API: фіксуйце выход дэманстрацыі ў CI, каб практыкі переработкі не моглі выдаліць EXECUTIVE зі спісу токенав компенсацыі без таго, каб заданне не завершылася невынікам. Валіце аддытыўныя формы працэсу падрыхтавання над рэдагаваннем спільных блакоў SPARQL; незалежныя формы чыста вяртаюцца да пачатковага стану, калі експерымент з правіламі не задаеся. Нарэшце, публікуйце вымераны спявазанне ў кожным паведамленні, надзеюцыся на розумеўшых — рэвізоры больш даверяюць цифрам, якія можна перысчытаць з RDF, чым загальным паведамленням «трэба адзначка».