← Wszystkie poradniki

Dodaj DocketProof do agenta LangGraph

Co właściwie dodajesz

@guarded_tool owija jedną funkcję Pythona — zwykle węzeł narzędzia w LangGraph — lokalną, zadeklarowaną kontrolą polityki oraz podpisanym, dopisywalnym łańcuchem wpisów. Werdykt allow uruchamia funkcję od razu i zapisuje podpisany wpis typu action. Werdykt deny nigdy nie uruchamia funkcji i zamiast tego zapisuje podpisany wpis typu denial. Werdykt review_required zatrzymuje bieżący przebieg grafu LangGraph przez wbudowany interrupt(), aż człowiek go wznowi — patrz niżej.

Instalacja

docketproof nie został jeszcze opublikowany na PyPI, więc na razie instaluje się go z lokalnej kopii pakietu (katalog docketproof/ w jego repozytorium):

shell
$ pip install -e .

Zdefiniuj politykę

Polityka to dokładne mapowanie nazwa-narzędzia → werdykt. Nie ma tu symboli wieloznacznych ani języka wyrażeń — każde chronione narzędzie potrzebuje własnego, nazwanego wpisu, a narzędzie bez wpisu jest oceniane jako deny, nie allow: brak wpisu w polityce to nie zgoda. Jako plik YAML:

policy.yaml
delete_resource: review_required
read_resource: allow
wipe_everything: deny

Albo zbudowana bezpośrednio jako słownik Pythona, przez MandatePolicy.from_dict — pokazane w przykładzie w następnej sekcji.

Owiń narzędzie

Przekaż dokładnie jeden z parametrów: policy (raz zbudowany obiekt MandatePolicy) albo policy_path (ścieżkę do pliku, wczytywaną i walidowaną ponownie przy każdym wywołaniu — przydatne, gdy operator musi zmienić politykę bez restartu procesu). chain_path jest zawsze wymagany: to tam trafia podpisany łańcuch wpisów.

tools.py
from docketproof import MandatePolicy, guarded_tool

policy = MandatePolicy.from_dict({
    "delete_resource": "review_required",
    "read_resource": "allow",
    "wipe_everything": "deny",
})

@guarded_tool(policy=policy, chain_path="./mandate-chain.jsonl")
def delete_resource(resource_id: str) -> str:
    ...  # your existing tool logic, unchanged
    return f"deleted {resource_id}"

Aby zamiast tego wczytywać plik polityki przy każdym wywołaniu i być powiadamianym, gdy sama bramka się psuje:

tools.py
@guarded_tool(
    policy_path="./policy.yaml",   # reloaded and re-validated on every call
    chain_path="./mandate-chain.jsonl",
    on_failure_webhook="https://alerts.example.com/gate-failures",
)
def delete_resource(resource_id: str) -> str:
    ...

Co dzieje się przy review_required

Graf zatrzymuje się przez interrupt() z LangGraph, udostępniając słownik z polami tool_name, args i policy_name temu, co steruje grafem. Wznów przebieg za pomocą Command(resume=...), korzystając z dwóch pomocniczych funkcji z tego pakietu:

resume.py
from docketproof import Command, resume_approved, resume_denied

# Inside the code that's driving the graph (a CLI, a server handler, a
# human-in-the-loop console) once you've decided what to do with the
# paused call:
graph.invoke(Command(resume=resume_approved("looks right")), config)
# or:
graph.invoke(Command(resume=resume_denied("not today")), config)

Niezależnie od decyzji człowieka, powstały wpis — action dla zatwierdzenia, denial dla odrzucenia — otrzymuje ten sam podpis i to samo traktowanie w łańcuchu. Nie ma osobnego, mniej ważnego zapisu dla odrzucenia: to właśnie on dowodzi, że blokada faktycznie zadziałała.

Gdzie trafia lokalny plik rejestru

chain_path to zwykły plik JSON Lines — jeden podpisany wpis na linię, tylko do dopisywania. Jeśli nie przekażesz własnego keypair=, klucz podpisujący jest generowany raz i przechowywany obok pliku jako <chain_path>.key (uprawnienia pliku 0600). Uruchom docketproof doctor przed pierwszą prawdziwą sesją — i ponownie w CI albo skryptach startowych — aby wykryć uszkodzony klucz, niezapisywalny rejestr albo błędną politykę, zanim zacznie to po cichu blokować każde wywołanie:

shell
$ docketproof doctor --docket-path ./mandate-chain.jsonl --policy ./policy.yaml

Nie masz jeszcze klucza podpisującego? Wygeneruj go bezpośrednio:

shell
$ docketproof init-key --docket-path ./mandate-chain.jsonl

Opcjonalnie: podłącz hostowany dashboard

Przekaż razem hosted_api_key i hosted_api_url, aby każdy podpisany wpis był kopiowany do hostowanego dashboardu — dopiero po tym, jak trafił już do lokalnego łańcucha. To najlepszy-możliwy, odpal-i-zapomnij mechanizm: lokalny zapis jest zawsze rozstrzygający, a wynik owiniętego wywołania, zgłoszony wyjątek i zawartość lokalnego łańcucha są identyczne niezależnie od tego, czy synchronizacja się uda, zawiedzie, czy w ogóle nie jest skonfigurowana:

tools.py
import os

@guarded_tool(
    policy=policy,
    chain_path="./mandate-chain.jsonl",
    hosted_api_key=os.environ.get("DOCKETPROOF_API_KEY"),
    hosted_api_url=os.environ.get("DOCKETPROOF_API_URL"),
)
def delete_resource(resource_id: str) -> str:
    ...

Nie ma tu odpytywania o zdalną decyzję człowieka — review_required jest zawsze rozstrzygany lokalnie, przez interrupt()/Command(resume=...) powyżej. Hostowana synchronizacja tylko kopiuje już zakończony wpis, później.

Zweryfikuj łańcuch niezależnie

Wyeksportuj łańcuch, do którego pisze twoje chronione narzędzie, i sprawdź go osobnym, niezależnie zaimplementowanym weryfikatorem w TypeScripcie — innym kodem niż ten, który go podpisał:

export.py
chain = delete_resource.mandate_chain   # the LocalChain this tool writes to
bundle = chain.to_bundle()

import json
open("bundle.json", "w").write(json.dumps(bundle, indent=2))
shell
$ mandate-verify bundle.json

Co dowodzi wpis — i czego nie dowodzi

✓ Co dowodzi

  • To dokładnie to wywołanie narzędzia, z tym dokładnie wejściem, zostało ocenione dokładnie w tym momencie.
  • Nazwana polityka wydała ten nazwany werdykt — allow, deny albo review.
  • Jeśli dopuszczone, to jest dokładnie to wywołanie, które zostało wykonane — nic nie zmieniono po zapisaniu.
  • Wpis nie został zmodyfikowany od momentu podpisania. Jakakolwiek edycja psuje weryfikację.

✗ Czego nie dowodzi

  • Że sama polityka była poprawna albo dobrze zaprojektowana.
  • Że rzeczywista intencja agenta była bezpieczna, legalna albo sensowna.
  • Niczego o działaniach spoza tego konkretnego rejestru.
  • Że osoba, która to zatwierdziła, powinna była to zrobić.

To to samo zastrzeżenie zakresu, co w sekcji na stronie głównej — pełny kontekst na docketproof.dev/pl/#scope.

Czego ten poradnik nie obejmuje

Ten pakiet nie ma języka wyrażeń dla polityk (tylko dokładne dopasowanie nazwy narzędzia), nie ma budżetów ani limitów wydatków, nie ocenia ryzyka na podstawie argumentów wywołania i nie wspiera innych frameworków agentowych niż LangGraph. Żadne z tych ograniczeń nie jest planowane jako rozszerzenie akurat tego dekoratora — pełną listę tego, czego pakiet celowo nie robi, znajdziesz w jego README.