Wiedza
Ślad audytowy agentów AI: zapisuj decyzję i skutek, nie wszystko
Dobry audit trail nie odpowiada na pytanie „co model napisał?”. Odpowiada na pytanie kto zlecił działanie, co system dopuścił, jakie narzędzie zostało użyte, co wydarzyło się w systemie docelowym i jaki stan pozostał po operacji.
To rozróżnienie jest ważne. Pełny prompt i odpowiedź mogą pomóc w debugowaniu, ale nie zastępują zapisu operacyjnego. Mogą też zawierać dane, których wcale nie chcemy utrwalać w systemie logów.
Zaczynamy od scenariusza odtworzenia zdarzenia
Załóżmy, że dwa tygodnie temu agent zmienił budżet kampanii albo uprawnienie użytkownika. Dzisiaj ktoś pyta:
- kto zainicjował zmianę;
- czy operator miał prawo ją zlecić;
- jak agent sklasyfikował operację;
- czy wymagana była zgoda człowieka;
- kto i co zatwierdził;
- jakie parametry trafiły do narzędzia;
- co zwrócił system zewnętrzny;
- czy odczytaliśmy stan po zmianie;
- która wersja polityki bezpieczeństwa obowiązywała.
Jeżeli odpowiedzi wymagają ręcznego zestawienia historii czatu, logów HTTP, bazy danych i panelu dostawcy, mamy logi. Nie mamy jeszcze dobrego śladu audytowego.
Minimalny rekord operacji agenta
Nie każdy system potrzebuje identycznego schematu. Dla działań narzędziowych sensowny rdzeń wygląda tak:
| Pole | Po co je zapisujemy |
|---|---|
event_id |
jednoznaczna identyfikacja zdarzenia |
timestamp |
kolejność i czas operacji |
operator_id |
osoba lub podmiot zlecający działanie |
agent_id / agent_version |
który agent/model był częścią wykonania |
task_id / correlation_id |
powiązanie kilku wywołań w jeden proces |
tool |
użyte narzędzie lub metoda |
operation_class |
read / write / operate / destructive albo lokalny odpowiednik |
target_resource |
konto, tenant, projekt lub zasób objęty działaniem |
authorization_decision |
allow / deny oraz zastosowane scope/policy |
approval_id |
dowód zatwierdzenia, jeśli było wymagane |
request_fingerprint |
skrót znormalizowanych parametrów zamiast pełnych danych, gdy to wystarcza |
provider_result |
kontrolowany wynik wywołania, bez sekretów |
resulting_state |
stan odczytany po zmianie lub identyfikator jego dowodu |
policy_version |
która wersja reguł miała zastosowanie |
Nie chodzi o to, żeby każde pole było tekstem w jednym rekordzie. Część może być referencją do osobnego artefaktu dowodowego. Ważna jest możliwość spójnego połączenia łańcucha.
Log rozmowy i audit trail rozwiązują różne problemy
Log rozmowy pomaga zrozumieć kontekst
Może pokazać, czego użytkownik oczekiwał, co model odpowiedział i jakie informacje były dostępne w sesji.
Audit trail pomaga dowieść wykonania
Powinien pokazać:
operator
→ decyzja autoryzacyjna
→ narzędzie
→ parametry istotne dla działania
→ approval, jeżeli wymagany
→ wynik dostawcy
→ stan po operacji
Jeżeli model napisał „kampania została wstrzymana”, ale nie mamy narzędziowego zdarzenia i stanu z systemu docelowego, mamy deklarację. Nie dowód wykonania.
Co zwykle warto redagować albo wykluczyć
Większa ilość logów nie zawsze oznacza lepszy audyt. Może oznaczać większą powierzchnię wycieku.
W wewnętrznym Brillnet Ads MCP z rekordów audytowych wykluczamy m.in. credentiale, nagłówki autoryzacyjne i surowe identyfikatory osobowe. Ten kierunek warto stosować szerzej.
Nie zapisuj sekretów
- kluczy API;
- access tokenów i refresh tokenów;
- prywatnych kluczy;
- haseł;
- cookies sesyjnych;
- pełnych nagłówków
Authorization.
Jeżeli potrzebujesz potwierdzić, jakiej tożsamości lub credential set użyto, zapisuj bezpieczny identyfikator referencyjny, nie sekret.
Nie kopiuj automatycznie całego request/response
Surowa odpowiedź API może zawierać dane osobowe, poufne pola lub informacje, które nie mają znaczenia dla audytu. Zamiast tego wybierz metadane istotne dla decyzji i rezultat.
Nie traktuj pełnego promptu jako obowiązkowego elementu audytu
Prompt może być użyteczny do diagnostyki. Może też zawierać dokumenty klienta, dane osobowe albo przypadkowo wprowadzony sekret. Zapis promptów powinien wynikać z osobnej polityki retencji i dostępu, nie z założenia „AI trzeba logować wszystko”.
Redakcja powinna następować przed zapisem
Jeżeli najpierw zapiszemy pełny payload, a potem uruchomimy proces maskowania, sekret już trafił do systemu logów.
Bezpieczniejszy przepływ:
narzędzie zwraca wynik
↓
normalizacja
↓
klasyfikacja pól
↓
redakcja / pseudonimizacja
↓
zapis rekordu audytowego
Wrażliwe dane mogą pozostać w systemie źródłowym, który ma własne zabezpieczenia i retencję. Audit ma przechowywać tyle, ile potrzeba do odtworzenia decyzji i skutku.
Read-after-write zamyka lukę między „wywołałem” a „zmieniłem”
Dla operacji zapisu zapisujemy nie tylko wynik wywołania, ale — jeśli API na to pozwala — również stan zasobu odczytany po zmianie.
Przykład:
14:02:11 write request: campaign status → PAUSED
14:02:12 provider: success
14:02:13 read-after-write: campaign.status = PAUSED
Dzięki temu później rozróżnimy:
- agent poprosił o zmianę;
- dostawca przyjął żądanie;
- zasób rzeczywiście miał oczekiwany stan w momencie weryfikacji.
To nie gwarantuje, że stan nie zmienił się sekundę później. Jest jednak znacznie lepszym dowodem wykonania niż sama odpowiedź modelu.
Approval jest osobnym zdarzeniem audytowym
Zgoda człowieka powinna mieć własny identyfikator i odnosić się do dokładnej operacji.
Przykładowy zapis:
approval_id: apr_...
approved_by: operator_...
approved_at: 2026-09-12T14:01:44+02:00
action_hash: sha256(...)
operation: ENABLE_CAMPAIGN
target: campaign_...
expires_at: ...
Dzięki temu nie musimy ufać wpisowi w rozmowie „użytkownik potwierdził”. System potrafi sprawdzić, że istnieje approval dla tej konkretnej wersji działania.
Więcej: Kiedy agent AI wymaga zatwierdzenia człowieka?
Integralność: append-only i łańcuch skrótów
W naszym wewnętrznym narzędziu Ads MCP rekordy audytowe są append-only i powiązane skrótem. Celem jest utrudnienie cichej zmiany historii bez pozostawienia śladu.
W uproszczeniu:
record_1 + hash(record_1)
↓
record_2 zawiera hash(record_1)
↓
record_3 zawiera hash(record_2)
Jeżeli ktoś zmieni starszy rekord, kolejne powiązania przestają się zgadzać.
To nie jest magiczna „niezmienność”. Administrator z odpowiednio szerokim dostępem może zniszczyć system albo całe repozytorium logów. Dlatego integralność rekordu trzeba łączyć z:
- ograniczeniem dostępu do logów;
- odrębną retencją;
- kopiami/eksportem tam, gdzie uzasadnione;
- monitoringiem przerw w łańcuchu;
- kontrolą czasu i identyfikatorów.
Co warto logować dla narzędzi MCP
Dla tools/call lub lokalnego odpowiednika przyda się:
- nazwa narzędzia;
- kategoria ryzyka;
- znormalizowane identyfikatory zasobów;
- scopes, które zostały sprawdzone;
- wynik autoryzacji;
- czy wykonano preview;
- identyfikator approval;
- czas startu i końca;
- status dostawcy;
- kod kontrolowanego błędu;
- czy nastąpił retry;
- idempotency key lub jego bezpieczny skrót;
- stan po zapisie;
- identyfikator modelu/agenta w zakresie potrzebnym do diagnostyki.
Nie musi to oznaczać przechowywania całego argumentu narzędzia.
Co z chain-of-thought?
Nie potrzebujemy prywatnego toku rozumowania modelu, żeby mieć użyteczny audyt operacji. Potrzebujemy obserwowalnych faktów:
- dane wejściowe istotne dla decyzji;
- wybrana operacja;
- zastosowana polityka;
- approval;
- wynik;
- stan po wykonaniu.
Jeżeli potrzebne jest uzasadnienie, agent może zapisać krótkie, jawne decision_reason, które jest przeznaczone do audytu. To co innego niż próba przechowywania ukrytego procesu rozumowania modelu.
Retencja: „na zawsze” jest zwykle złą wartością domyślną
Dla każdego typu zdarzenia ustal:
- cel przetwarzania;
- okres retencji;
- kto ma dostęp;
- czy dane można zagregować lub pseudonimizować;
- kiedy rekord staje się dowodem biznesowym, a kiedy tylko telemetrią techniczną;
- sposób legalnego/operacyjnego usunięcia, jeśli jest wymagane.
Nie mieszaj bezterminowo telemetryki debugowej z formalnym rejestrem decyzji.
Przykład rekonstrukcji incydentu
Sytuacja: kampania zaczęła generować koszt mimo oczekiwania, że pozostanie wstrzymana.
Dobry audit pozwala przejść kolejno:
task_id— skąd przyszło zlecenie;operator_id— kto je zainicjował;tool— które narzędzie wybrano;operation_class=operate— dlaczego potrzebna była dodatkowa kontrola;approval_id— czy ktoś faktycznie zatwierdził uruchomienie;- parametry — jaki status i budżet były objęte zgodą;
- provider result — co przyjął Google Ads;
- read-after-write — jaki stan zobaczyliśmy po wykonaniu;
- późniejsze zdarzenia — czy ktoś zmienił status ponownie.
Bez tego pozostaje analiza czatu i domysły.
Checklista śladu audytowego agenta
- Każde istotne zdarzenie ma unikalny ID i czas.
- Operator i agent są rozróżnieni.
- Kilka wywołań można połączyć jednym task/correlation ID.
- Rejestrujemy decyzję autoryzacyjną, nie tylko wykonane wywołanie.
- Approval jest osobnym, weryfikowalnym zdarzeniem.
- Parametry istotne dla skutku są utrwalone lub fingerprintowane.
- Sekrety i authorization headers są wykluczone przed zapisem.
- Dane osobowe są minimalizowane/redagowane.
- Retry i idempotencja są widoczne.
- Dla zapisu mamy wynik dostawcy i, gdy możliwe, read-after-write.
- Wersja polityki jest możliwa do odtworzenia.
- Dostęp do audytu jest węższy niż zwykły dostęp do aplikacji.
- Retencja jest zdefiniowana, nie przypadkowa.
- Integralność logu jest monitorowana.
Źródła
Granica
Audit trail nie dowodzi automatycznie, że decyzja była poprawna. Dowodzi, co system zarejestrował o jej przebiegu. W procesach regulowanych trzeba dodatkowo określić wymagania dla integralności, retencji, prywatności i wiarygodności dowodów.
Zobacz też Najmniejsze uprawnienia dla agentów AI oraz Bezpieczeństwo Brillnet.
