0Pricing
AI Agents · บทเรียน

การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้

บันทึกแบบเพิ่มต่อท้ายเท่านั้น ลายเซ็นเข้ารหัส และเส้นทางการตรวจสอบที่ตรวจพบการแก้ไขได้

การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้ เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดเอเจนต์จึงต้องมีบันทึกที่แก้ไขไม่ได้

เอเจนต์ดำเนินการต่าง ๆ โดยอัตโนมัติ โดยมักไม่มีมนุษย์ตรวจสอบทุกขั้นตอน เมื่อเกิดข้อผิดพลาด คุณต้องตอบให้ได้ว่าเอเจนต์ทำอะไร เมื่อใด ในนามของใคร และเพราะเหตุใด

บันทึกที่แก้ไขไม่ได้และแสดงให้เห็นการดัดแปลง ทำให้ไม่สามารถแก้ไขเส้นทางการตรวจสอบย้อนหลังได้

โครงสร้างรายการบันทึก

รายการบันทึกทุกรายการจะเก็บข้อมูลประทับเวลา ข้อมูลระบุตัวตนของเอเจนต์ ข้อมูลระบุตัวตนของผู้ใช้ ประเภทการกระทำ พารามิเตอร์ ผลลัพธ์ และแฮชที่เชื่อมโยงกับรายการก่อนหน้า โครงสร้างนี้รองรับทั้งการค้นหาและการตรวจจับการดัดแปลง

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)

การเชื่อมโยงแฮชเพื่อตรวจจับการดัดแปลง

แฮชของแต่ละรายการคำนวณจากเนื้อหาของรายการ รวมกับแฮชของรายการก่อนหน้า หากรายการใดถูกแก้ไขภายหลัง แฮชของรายการนั้นจะเปลี่ยนไป ซึ่งทำให้แฮชทั้งหมดหลังจากนั้นใช้ไม่ได้ วิธีนี้ทำให้ตรวจจับการดัดแปลงได้

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'])

บันทึกแบบเพิ่มต่อท้ายเท่านั้นภายในกระบวนการ

การใช้งานที่ง่ายที่สุดคือรายการในหน่วยความจำพร้อมฟังก์ชันที่อนุญาตให้เพิ่มข้อมูลต่อท้ายเท่านั้น จะไม่มีการเปิดให้ใช้ฟังก์ชันลบหรืออัปเดต ในระบบใช้งานจริง ข้อมูลนี้จะมีฐานข้อมูลหรือที่จัดเก็บวัตถุรองรับ

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 reference

เขียนลง PostgreSQL ด้วยความหมายแบบเพิ่มต่อท้ายเท่านั้น

ในระบบใช้งานจริง ให้เขียนบันทึกลงตารางฐานข้อมูลที่ไม่ได้มอบสิทธิ์ UPDATE หรือ DELETE ให้แก่ผู้ใช้แอปพลิเคชัน เพิกถอนสิทธิ์เหล่านี้ในระดับฐานข้อมูลเพื่อให้ได้พฤติกรรมแบบเพิ่มต่อท้ายเท่านั้นอย่างแท้จริง

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()

เขียนลง S3 ด้วยการล็อกออบเจ็กต์ (WORM)

การล็อกออบเจ็กต์ของ AWS S3 ในโหมด COMPLIANCE จะป้องกันไม่ให้ผู้ใช้รายใด รวมถึงผู้ใช้ระดับรากของบัญชี ลบหรือเขียนทับออบเจ็กต์ได้ตลอดระยะเวลาเก็บรักษา นี่คือที่จัดเก็บบันทึกการตรวจสอบแบบเขียนครั้งเดียวอย่างแท้จริง

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 key

สอบถามบันทึกการตรวจสอบ

บันทึกการตรวจสอบไม่ได้มีไว้เพื่อการปฏิบัติตามข้อกำหนดเท่านั้น แต่ยังมีประโยชน์ในด้านการปฏิบัติงาน คุณสามารถสอบถามบันทึกเพื่อแก้ไขข้อบกพร่องของพฤติกรรมเอเจนต์ สร้างเซสชันขึ้นใหม่ หรือหาคำตอบว่าเหตุใดเอเจนต์จึงดำเนินการบางอย่าง

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))

ทำความสะอาดข้อมูลอ่อนไหวก่อนบันทึก

บันทึกการตรวจสอบควรแสดงว่าเอเจนต์ทำอะไร ไม่ใช่เปิดเผยข้อมูลอ่อนไหว ให้ลบ PII เช่น รหัสผ่าน คีย์ API และหมายเลขบัตรเครดิต ออกจากพารามิเตอร์และผลลัพธ์ก่อนเขียนข้อมูล

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))

การหมุนเวียนและเก็บถาวรบันทึก

บันทึกที่ใช้งานอยู่จะเติบโตอย่างไม่สิ้นสุด ให้หมุนเวียนบันทึกโดยย้ายรายการที่เก่ากว่า 90 วันไปยังที่จัดเก็บระยะยาว เช่น S3 Glacier แล้วบีบอัดข้อมูล รักษาการเชื่อมโยงให้ต่อเนื่องด้วยการเก็บแฮชสุดท้ายของแต่ละส่วนที่หมุนเวียนออกไป

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}

แจ้งเตือนรูปแบบที่น่าสงสัย

ติดตามบันทึกการตรวจสอบแบบเรียลไทม์เพื่อค้นหารูปแบบที่ผิดปกติ เช่น การกระทำที่มีความเสี่ยงสูงจำนวนมากในช่วงสั้น ๆ การกระทำนอกเวลาทำการ หรือการกระทำเดียวกันซ้ำเกิน N ครั้งภายในช่วงเวลาสั้น ๆ

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)

ตรวจสอบความถูกต้องของบันทึกเมื่อจำเป็น

เรียกใช้การตรวจสอบความถูกต้องเป็นส่วนหนึ่งของกระบวนการตรวจติดตาม แจ้งเตือนทันทีหากตรวจพบความล้มเหลวในการตรวจสอบ เพราะนั่นบ่งชี้ว่าอาจเกิดข้อบกพร่องในโค้ดการบันทึกหรือมีความพยายามดัดแปลงข้อมูลอยู่

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)

การเชื่อมโยงแฮชในบันทึกการตรวจสอบตรวจจับอะไรได้

การเชื่อมโยงแฮชเป็นกลไกการเข้ารหัสที่ทำให้บันทึกการตรวจสอบแสดงให้เห็นการดัดแปลงได้ การเข้าใจว่าสิ่งนี้ตรวจจับอะไรได้ถือเป็นพื้นฐานสำคัญของการออกแบบบันทึกการตรวจสอบ

สรุปการบันทึกการกระทำที่แก้ไขไม่ได้

บันทึกการกระทำของเอเจนต์ที่แก้ไขไม่ได้ใช้ การเชื่อมโยงแฮช เพื่อตรวจจับการดัดแปลง ที่จัดเก็บแบบเพิ่มต่อท้ายเท่านั้น โดยเพิกถอน UPDATE/DELETE ในระดับฐานข้อมูล ที่จัดเก็บออบเจ็กต์แบบ WORM ด้วยการล็อกออบเจ็กต์ของ S3 เพื่อการเก็บรักษาตามข้อกำหนด การทำความสะอาด PII ก่อนเขียนข้อมูล และ การแจ้งเตือนความผิดปกติแบบเรียลไทม์ เมื่อพบรูปแบบการกระทำที่น่าสงสัย

คำถามที่พบบ่อย

บทเรียน “การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้”

บันทึกแบบเพิ่มต่อท้ายเท่านั้น ลายเซ็นเข้ารหัส และเส้นทางการตรวจสอบที่ตรวจพบการแก้ไขได้ คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม

ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การบันทึกการกระทำของเอเจนต์แบบแก้ไขไม่ได้
  2. การบังคับใช้นโยบายกับการกระทำของเอเจนต์
  3. การปฏิบัติตามข้อกำหนด: GDPR และ SOC2
  4. จุดอนุมัติโดยมนุษย์ในวงจรการทำงาน
← กลับไปที่ AI Agents