Logging Tindakan Ejen yang Tidak Berubah
Log tambah sahaja, tandatangan kriptografi dan jejak audit yang menunjukkan gangguan.
Logging Tindakan Ejen yang Tidak Berubah ialah pelajaran Ejen AI percuma di CoddyKit. Ini ialah pelajaran 1 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Ejen AI, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Ejen AI merangkumi sejumlah 4 pelajaran.
Mengapakah Ejen Memerlukan Log Tidak Boleh Ubah
Ejen mengambil tindakan secara autonomi — selalunya tanpa manusia menyemak setiap langkah. Apabila sesuatu berlaku dengan tidak betul, anda perlu menjawab: apakah tindakan yang diambil oleh ejen, bila, bagi pihak siapa, dan mengapa?
Log tidak boleh ubah dan jelas jika diusik menjadikan pengubahan jejak audit secara retroaktif mustahil.
Skema Entri Log
Setiap entri log merekodkan: cap masa, identiti ejen, identiti pengguna, jenis tindakan, parameter, hasil, dan cincangan yang memautkannya kepada entri sebelumnya. Struktur ini menyokong carian serta pengesanan pengusikan.
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)
Rantaian Cincangan untuk Mengesan Pengusikan
Cincangan setiap entri dikira daripada kandungannya serta cincangan entri sebelumnya. Jika mana-mana entri diubah selepas itu, cincangannya berubah, lalu membatalkan semua cincangan berikutnya. Ini menjadikan pengusikan dapat dikesan.
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'])
Log Tambah Sahaja dalam Proses
Pelaksanaan paling mudah ialah senarai dalam memori dengan kaedah yang hanya membenarkan penambahan. Tiada kaedah pemadaman atau pengemaskinian didedahkan. Dalam persekitaran pengeluaran, ini disokong oleh pangkalan data atau stor 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 Semantik Tambah Sahaja
Dalam persekitaran pengeluaran, tulis log ke jadual pangkalan data yang tidak memberikan kebenaran UPDATE atau DELETE kepada pengguna aplikasi. Tarik balik keistimewaan ini pada peringkat pangkalan data untuk mendapatkan tingkah laku tambah sahaja yang sebenar.
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 Kunci Objek (WORM)
Kunci Objek AWS S3 dengan mod COMPLIANCE menghalang mana-mana pengguna — termasuk punca akaun — daripada memadam atau menulis ganti objek sepanjang tempoh pengekalan. Ini ialah stor tulis sekali yang sebenar untuk log 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 Pertanyaan pada Log Audit
Log audit bukan sekadar untuk pematuhan — log ini juga berguna dari sudut operasi. Buat pertanyaan terhadapnya untuk menyahpepijat tingkah laku ejen, membina semula sesi, atau menjawab soalan 'mengapa ejen melakukan X?'
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 Mencatat Log
Log audit hendaklah merekodkan tindakan ejen, bukan mendedahkan data sensitif. Buang PII (kata laluan, kunci API, nombor kad kredit) daripada parameter dan hasil sebelum menulis.
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))
Putaran dan Pengarkiban Log
Log aktif terus bertambah tanpa had. Putarkannya: pindahkan entri yang lebih lama daripada 90 hari ke storan sejuk (contohnya, S3 Glacier) dan mampatkannya. Kekalkan rantaian dengan menyimpan cincangan terakhir bagi setiap segmen yang diputar.
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 Amaran tentang Corak Mencurigakan
Pantau log audit untuk mengesan corak luar biasa secara masa nyata: ledakan tindakan berisiko tinggi, tindakan di luar waktu perniagaan, atau tindakan yang sama diulang lebih daripada N kali dalam jangka masa yang 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)
Mengesahkan Integriti Log Mengikut Keperluan
Jalankan pemeriksaan integriti sebagai sebahagian daripada saluran pemantauan anda. Beri amaran serta-merta jika sebarang kegagalan pengesahan dikesan — ini menunjukkan sama ada terdapat pepijat dalam kod pencatatan log atau cubaan mengusik secara 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)Apakah yang dikesan oleh rantaian cincangan dalam log audit?
Rantaian cincangan ialah mekanisme kriptografi yang memberikan sifat jelas jika diusik kepada log audit. Memahami perkara yang dikesannya ialah asas penting dalam reka bentuk log audit.
Ringkasan Pencatatan Tindakan Tidak Boleh Ubah
Log ejen yang tidak boleh ubah menggunakan: rantaian cincangan untuk mengesan pengusikan, storan tambah sahaja (tarik balik UPDATE/DELETE pada peringkat pangkalan data), storan objek WORM (Kunci Objek S3) untuk pengekalan kawal selia, pembersihan PII sebelum menulis, dan pemberian amaran anomali masa nyata terhadap corak tindakan yang mencurigakan.
Pelajari Ejen AI dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 60
- Pelajaran
- 239
Soalan Lazim
Adakah pelajaran “Logging Tindakan Ejen yang Tidak Berubah” percuma?
Ya — teks penuh “Logging Tindakan Ejen yang Tidak Berubah” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Ejen AI, tingkat taraf kepada CoddyKit PRO. Kursus Ejen AI merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Logging Tindakan Ejen yang Tidak Berubah”?
Log tambah sahaja, tandatangan kriptografi dan jejak audit yang menunjukkan gangguan. Anda berlatih Ejen AI menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Ejen AI?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Ejen AI di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 1 daripada 4.
Berapa lamakah pelajaran “Logging Tindakan Ejen yang Tidak Berubah” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Ejen AI ini?
Ya. Setiap pelajaran Ejen AI menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Logging Tindakan Ejen yang Tidak Berubah
- Penguatkuasaan Dasar bagi Tindakan Ejen
- Pematuhan Peraturan: GDPR dan SOC2
- Pintu Kelulusan Manusia dalam Gelung