Pencatatan Tindakan Agen yang Tidak Dapat Diubah
Log hanya-tambah, tanda tangan kriptografis, dan jejak audit yang menunjukkan perubahan.
Pencatatan Tindakan Agen yang Tidak Dapat Diubah adalah pelajaran AI Agents gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Agents, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Agents mencakup 4 pelajaran total.
Mengapa Agen Memerlukan Catatan yang Tidak Dapat Diubah
Agen melakukan tindakan secara otonom — sering kali tanpa manusia yang meninjau setiap langkah. Ketika terjadi kesalahan, Anda perlu menjawab: apa yang dilakukan agen, kapan, atas nama siapa, dan mengapa?
Catatan yang tidak dapat diubah dan dapat menunjukkan perubahan membuat perubahan surut pada jejak audit menjadi mustahil.
Skema Entri Catatan
Setiap entri catatan memuat: stempel waktu, identitas agen, identitas pengguna, jenis tindakan, parameter, hasil, dan ringkasan kriptografis yang menghubungkannya dengan entri sebelumnya. Struktur ini mendukung pencarian sekaligus pendeteksian perubahan.
from dataclasses import dataclass
from typing import Any
@dataclass
class AuditEntry:
timestamp: float # Unix time (UTC)
agent_id: str
user_id: str
action_type: str
parameters: dict
result: dict
session_id: str
prev_hash: str # hash of previous entry
entry_hash: str = '' # computed after construction
if __name__ == '__main__':
entry = AuditEntry(
timestamp=1717000000.0, agent_id='agent-1', user_id='user-42',
action_type='send_email', parameters={'to': 'a@b.com'},
result={'status': 'sent'}, session_id='sess-1', prev_hash='0' * 64
)
print('Audit entry created:')
print(' agent_id:', entry.agent_id)
print(' action_type:', entry.action_type)
print(' prev_hash:', entry.prev_hash)
Rantai Ringkasan Kriptografis untuk Mendeteksi Perubahan
Ringkasan kriptografis setiap entri dihitung dari isinya ditambah ringkasan kriptografis entri sebelumnya. Jika ada entri yang diubah setelahnya, ringkasan kriptografisnya berubah dan semua ringkasan kriptografis berikutnya menjadi tidak valid. Dengan demikian, perubahan dapat dideteksi.
import hashlib, json, time
def compute_entry_hash(entry: dict, prev_hash: str) -> str:
content = json.dumps(entry, sort_keys=True, default=str)
payload = f'{prev_hash}:{content}'
return hashlib.sha256(payload.encode()).hexdigest()
def create_log_entry(agent_id: str, user_id: str, action_type: str,
parameters: dict, result: dict,
session_id: str, prev_hash: str) -> dict:
entry = {
'timestamp': time.time(),
'agent_id': agent_id,
'user_id': user_id,
'action_type': action_type,
'parameters': parameters,
'result': result,
'session_id': session_id,
'prev_hash': prev_hash
}
entry['entry_hash'] = compute_entry_hash(
{k: v for k, v in entry.items() if k != 'entry_hash'},
prev_hash
)
return entry
if __name__ == '__main__':
entry = create_log_entry('agent-1', 'user-42', 'send_email',
{'to': 'a@b.com'}, {'status': 'sent'},
'sess-1', prev_hash='0' * 64)
print('New log entry hash:', entry['entry_hash'])
print('Chained from prev_hash:', entry['prev_hash'])
Catatan Hanya-Penambahan dalam Proses
Implementasi paling sederhana adalah daftar dalam memori dengan metode yang hanya mengizinkan penambahan. Tidak ada metode penghapusan atau pembaruan yang tersedia. Dalam lingkungan produksi, catatan ini didukung oleh basis data atau penyimpanan objek.
class AppendOnlyLog:
def __init__(self):
self._entries: list[dict] = []
self._last_hash = 'GENESIS'
def append(self, agent_id: str, user_id: str, action_type: str,
parameters: dict, result: dict, session_id: str) -> dict:
entry = create_log_entry(
agent_id, user_id, action_type,
parameters, result, session_id,
self._last_hash
)
self._entries.append(entry)
self._last_hash = entry['entry_hash']
return entry
def verify_integrity(self) -> bool:
running_hash = 'GENESIS'
for e in self._entries:
expected = compute_entry_hash(
{k: v for k, v in e.items() if k != 'entry_hash'},
running_hash
)
if expected != e['entry_hash']:
return False
running_hash = e['entry_hash']
return True
@property
def entries(self):
return list(self._entries) # return copy, not referenceMenulis ke PostgreSQL dengan Perilaku Hanya-Penambahan
Dalam lingkungan produksi, tulis catatan ke tabel basis data yang tidak memberikan izin UPDATE atau DELETE kepada pengguna aplikasi. Cabut hak istimewa tersebut pada tingkat basis data untuk mendapatkan perilaku yang benar-benar hanya memungkinkan penambahan.
import psycopg2, json
# Table DDL (run once):
# CREATE TABLE agent_audit_log (
# id BIGSERIAL PRIMARY KEY,
# timestamp DOUBLE PRECISION NOT NULL,
# agent_id TEXT NOT NULL,
# user_id TEXT NOT NULL,
# action_type TEXT NOT NULL,
# parameters JSONB NOT NULL,
# result JSONB NOT NULL,
# session_id TEXT NOT NULL,
# prev_hash TEXT NOT NULL,
# entry_hash TEXT NOT NULL UNIQUE
# );
# REVOKE UPDATE, DELETE ON agent_audit_log FROM app_user;
def write_to_db(conn, entry: dict):
with conn.cursor() as cur:
cur.execute(
'INSERT INTO agent_audit_log '
'(timestamp,agent_id,user_id,action_type,parameters,result,session_id,prev_hash,entry_hash) '
'VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)',
(entry['timestamp'], entry['agent_id'], entry['user_id'],
entry['action_type'], json.dumps(entry['parameters']),
json.dumps(entry['result']), entry['session_id'],
entry['prev_hash'], entry['entry_hash'])
)
conn.commit()Menulis ke S3 dengan Penguncian Objek (WORM)
Penguncian Objek AWS S3 dengan mode COMPLIANCE mencegah pengguna mana pun — termasuk akun utama — menghapus atau menimpa objek selama masa penyimpanan. Ini adalah penyimpanan tulis-sekali yang sesungguhnya untuk catatan audit.
import boto3, json, time
s3 = boto3.client('s3', region_name='us-east-1')
BUCKET = 'your-audit-log-bucket-worm'
def write_to_s3_worm(entry: dict):
key = f'audit/{entry["agent_id"]}/{int(entry["timestamp"])}/{entry["entry_hash"][:16]}.json'
s3.put_object(
Bucket=BUCKET,
Key=key,
Body=json.dumps(entry).encode(),
ContentType='application/json',
ObjectLockMode='COMPLIANCE',
ObjectLockRetainUntilDate='2030-01-01T00:00:00Z' # 4+ year retention
)
return keyMembuat Kueri pada Catatan Audit
Catatan audit bukan hanya untuk kepatuhan — catatan ini juga berguna secara operasional. Buat kueri untuk menelusuri kesalahan perilaku agen, merekonstruksi suatu sesi, atau menjawab pertanyaan seperti mengapa agen melakukan tindakan tertentu.
def query_session(log: AppendOnlyLog, session_id: str) -> list[dict]:
return [
e for e in log.entries
if e['session_id'] == session_id
]
def query_user_actions(log: AppendOnlyLog, user_id: str,
action_type: str = None) -> list[dict]:
entries = [e for e in log.entries if e['user_id'] == user_id]
if action_type:
entries = [e for e in entries if e['action_type'] == action_type]
return sorted(entries, key=lambda e: e['timestamp'])
def count_actions_by_type(log: AppendOnlyLog) -> dict:
from collections import Counter
return dict(Counter(e['action_type'] for e in log.entries))Membersihkan Data Sensitif Sebelum Pencatatan
Catatan audit harus merekam tindakan agen, bukan mengekspos data sensitif. Hapus PII (kata sandi, kunci antarmuka pemrograman aplikasi, dan nomor kartu kredit) dari parameter dan hasil sebelum menulisnya.
import re
SENSITIVE_KEYS = {'password', 'api_key', 'secret', 'token', 'credit_card', 'ssn'}
def sanitize(obj, depth: int = 0) -> dict | list | str:
if depth > 5:
return '[MAX_DEPTH]'
if isinstance(obj, dict):
return {
k: '[REDACTED]' if k.lower() in SENSITIVE_KEYS
else sanitize(v, depth + 1)
for k, v in obj.items()
}
elif isinstance(obj, list):
return [sanitize(i, depth + 1) for i in obj]
elif isinstance(obj, str):
# Redact anything that looks like an API key
return re.sub(r'(sk-|Bearer\s)[A-Za-z0-9_-]{16,}', '[REDACTED]', obj)
return obj
if __name__ == '__main__':
record = {'user': 'alice', 'password': 'hunter2', 'note': 'call me at sk-abcdefghijklmnopqrstuv'}
print('Sanitized record:', sanitize(record))
Rotasi dan Pengarsipan Catatan
Catatan aktif terus bertambah tanpa batas. Lakukan rotasi: pindahkan entri yang lebih lama dari 90 hari ke penyimpanan dingin (misalnya, S3 Glacier) dan kompres entri tersebut. Pertahankan rantainya dengan menyimpan ringkasan kriptografis terakhir dari setiap segmen yang dirotasi.
import time, json, gzip
def rotate_log(log: AppendOnlyLog, max_age_days: int = 90) -> dict:
cutoff = time.time() - max_age_days * 86400
archive = [e for e in log.entries if e['timestamp'] < cutoff]
remaining = [e for e in log.entries if e['timestamp'] >= cutoff]
if not archive:
return {'archived': 0, 'remaining': len(remaining)}
# Compress archive
archive_bytes = gzip.compress(json.dumps(archive).encode())
archive_file = f'/tmp/audit_archive_{int(time.time())}.json.gz'
with open(archive_file, 'wb') as f:
f.write(archive_bytes)
# Update in-memory log
log._entries = remaining
return {'archived': len(archive), 'remaining': len(remaining), 'file': archive_file}Memberi Peringatan tentang Pola Mencurigakan
Pantau catatan audit secara waktu nyata untuk menemukan pola yang tidak biasa: lonjakan tindakan berisiko tinggi, tindakan di luar jam kerja, atau tindakan yang sama diulang lebih dari N kali dalam waktu singkat.
import time
from collections import defaultdict
HIGH_RISK_ACTIONS = {'delete_user', 'send_mass_email',
'transfer_funds', 'export_all_data'}
BURST_LIMIT = 5
BURST_WINDOW = 60 # seconds
action_timestamps: dict[str, list] = defaultdict(list)
def check_suspicious(entry: dict) -> list[str]:
alerts = []
action = entry['action_type']
if action in HIGH_RISK_ACTIONS:
alerts.append(f'HIGH_RISK_ACTION: {action} by {entry["agent_id"]}')
now = time.time()
action_timestamps[action].append(now)
recent = [t for t in action_timestamps[action] if now - t < BURST_WINDOW]
action_timestamps[action] = recent
if len(recent) > BURST_LIMIT:
alerts.append(f'ACTION_BURST: {action} called {len(recent)}x in {BURST_WINDOW}s')
return alerts
if __name__ == '__main__':
entry = {'action_type': 'delete_user', 'agent_id': 'agent-9'}
for _ in range(6):
alerts = check_suspicious(entry)
print('Alerts on 6th call:', alerts)
Memverifikasi Integritas Catatan Sesuai Kebutuhan
Jalankan pemeriksaan integritas sebagai bagian dari alur pemantauan Anda. Segera berikan peringatan jika terdeteksi kegagalan verifikasi — hal ini menunjukkan adanya bug dalam kode pencatatan atau upaya perubahan aktif.
def verify_and_alert(log: AppendOnlyLog) -> dict:
is_valid = log.verify_integrity()
total = len(log.entries)
result = {
'total_entries': total,
'integrity_ok': is_valid
}
if not is_valid:
import logging
alert_logger = logging.getLogger('agent.integrity_alert')
alert_logger.critical(
'AUDIT LOG INTEGRITY FAILURE: tampered or corrupted entries detected. '
'Total entries: %d. Initiating incident response.', total
)
result['alert_sent'] = True
return result
# Run periodically via cron or monitoring hook
# verify_and_alert(global_audit_log)Apa yang dideteksi rantai ringkasan kriptografis dalam catatan audit?
Rantai ringkasan kriptografis adalah mekanisme kriptografis yang memberikan sifat dapat mendeteksi perubahan pada catatan audit. Memahami hal yang dapat dideteksinya merupakan dasar penting dalam merancang catatan audit.
Ringkasan Pencatatan Tindakan yang Tidak Dapat Diubah
Catatan agen yang tidak dapat diubah menggunakan: rantai ringkasan kriptografis untuk mendeteksi perubahan, penyimpanan hanya-penambahan (cabut UPDATE/DELETE pada tingkat basis data), penyimpanan objek WORM (Penguncian Objek S3) untuk penyimpanan sesuai peraturan, pembersihan PII sebelum penulisan, dan pemberian peringatan anomali secara waktu nyata pada pola tindakan yang mencurigakan.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Pencatatan Tindakan Agen yang Tidak Dapat Diubah” gratis?
Ya — teks lengkap “Pencatatan Tindakan Agen yang Tidak Dapat Diubah” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Agents, upgrade ke CoddyKit PRO. Kursus AI Agents mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Pencatatan Tindakan Agen yang Tidak Dapat Diubah”?
Log hanya-tambah, tanda tangan kriptografis, dan jejak audit yang menunjukkan perubahan. Kamu berlatih AI Agents dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai AI Agents?
Tidak diperlukan pengalaman sebelumnya. AI Agents di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.
Berapa lama pelajaran “Pencatatan Tindakan Agen yang Tidak Dapat Diubah” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Agents ini?
Ya. Setiap pelajaran AI Agents menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Pencatatan Tindakan Agen yang Tidak Dapat Diubah
- Penegakan Kebijakan untuk Tindakan Agen
- Kepatuhan Regulasi: GDPR dan SOC2
- Gerbang Persetujuan dengan Keterlibatan Manusia