Saat tim backend menambahkan ringkasan AI ke alur audit, masalahnya sering tidak muncul sebagai error model, melainkan sebagai kerusakan data turunan: log gagal diparse, event audit menjadi tidak konsisten, dan query analitik mulai menghasilkan angka yang salah. Inti bug-nya sederhana: output AI bukan string aman. Ia harus diperlakukan seperti input dari sistem eksternal yang tidak sepenuhnya dapat dipercaya.

Dalam studi kasus ini, ringkasan AI merusak query audit dan log karena hasil model dimasukkan langsung ke payload audit terstruktur tanpa boundary yang jelas, sanitasi, atau validasi skema yang ketat. Ini sejalan dengan pengingat dari gagasan “Your AI Is Not a Tool”: AI bukan sekadar fungsi deterministik di dalam proses kita, melainkan integrasi eksternal dengan keluaran yang bisa menyimpang, berubah format, atau gagal memenuhi kontrak.

Arsitektur awal dan titik rawan

Kasusnya berawal dari alur audit backend yang sebelumnya stabil. Setiap aksi penting di aplikasi menghasilkan event audit berbentuk JSON terstruktur, lalu disimpan ke database dan dikirim ke sistem log/analytics.

{
  "event_type": "ticket.updated",
  "actor_id": "usr_123",
  "resource_id": "tkt_456",
  "occurred_at": "2026-08-09T10:15:00Z",
  "changes": {
    "status": {"from": "open", "to": "closed"}
  }
}

Tim lalu menambahkan ringkasan AI agar auditor internal bisa cepat memahami konteks perubahan. Secara desain, ringkasan ini ditambahkan ke payload audit:

{
  "event_type": "ticket.updated",
  "actor_id": "usr_123",
  "resource_id": "tkt_456",
  "occurred_at": "2026-08-09T10:15:00Z",
  "changes": {
    "status": {"from": "open", "to": "closed"}
  },
  "ai_summary": "Tiket ditutup setelah permintaan pengguna diverifikasi."
}

Di atas kertas ini terlihat aman. Masalah muncul karena implementasinya mengasumsikan bahwa output model selalu berupa teks singkat, satu baris, dan tidak mengganggu serialisasi atau downstream parser.

Gejala di produksi

Bug ini jarang muncul sebagai kegagalan total. Yang lebih umum adalah gejala tidak langsung yang sulit dikaitkan ke ringkasan AI pada awal investigasi.

1. Query analitik audit mulai aneh

Dashboard menunjukkan jumlah event audit harian turun, padahal traffic aplikasi stabil. Query agregasi berdasarkan event_type juga mulai tidak cocok dengan data transaksi utama.

2. Parser log terstruktur gagal secara intermiten

Sebagian log ingestion tetap berhasil, tetapi sebagian event masuk sebagai string mentah, bukan objek terstruktur. Akibatnya field seperti actor_id dan resource_id tidak dapat diindeks dengan benar.

3. Peningkatan error yang tampak tidak berhubungan

Di beberapa service, muncul error seperti:

  • JSON parse failure
  • unexpected token
  • schema validation error
  • timeout pada pipeline downstream karena retry ingestion

Karena gejalanya tersebar di audit service, worker queue, dan analytics pipeline, tim awalnya menduga ada masalah di sisi logger atau broker, bukan pada ringkasan AI.

Payload yang memicu kerusakan

Akar masalah biasanya bukan karena model menghasilkan “salah secara semantik”, tetapi karena hasilnya melanggar asumsi format.

Contoh payload yang tampak normal bagi manusia tetapi berbahaya bagi sistem:

{
  "ai_summary": "Perubahan dipicu oleh user.\n\nCatatan tambahan: {\"risk\":\"medium\",\"needs_review\":true}"
}

Jika aplikasi atau pipeline log melakukan penggabungan string secara manual, baris baru dan potongan mirip JSON ini dapat merusak format akhir. Contoh implementasi rawan:

const logLine = '{"event_type":"ticket.updated","ai_summary":"' + aiSummary + '"}';
logger.info(logLine);

Bila aiSummary mengandung kutip ganda, newline, atau fragmen JSON, hasil akhir bisa menjadi JSON tidak valid. Masalah yang sama terjadi bila payload audit dibangun melalui templating string, bukan serializer JSON yang benar.

Contoh lain yang lebih halus adalah ketika model kadang menjawab dengan format bercampur:

Ringkasan: tiket ditutup.
Confidence: tinggi
Tags: billing, escalation

Bagi manusia ini masih dapat dibaca. Namun bila sistem mengharapkan satu string ringkas atau objek JSON tertentu, output seperti ini membuat parser atau validator downstream gagal.

Langkah reproduksi bug

Bug seperti ini lebih mudah dipahami jika direproduksi di lingkungan lokal atau staging dengan payload nyata.

Reproduksi minimum

  1. Buat event audit terstruktur seperti biasa.
  2. Tambahkan field ai_summary dari hasil model tanpa normalisasi.
  3. Bangun log line memakai konkatenasi string, atau kirim ke komponen downstream yang mengasumsikan teks satu baris.
  4. Gunakan input model yang menghasilkan kutip ganda, newline, blok markdown, atau JSON parsial.

Contoh kode rawan:

function writeAuditLog(event, aiSummary) {
  const line = '{"event_type":"' + event.type + '",' +
    '"actor_id":"' + event.actorId + '",' +
    '"ai_summary":"' + aiSummary + '"}';

  process.stdout.write(line + '\n');
}

Input berikut cukup untuk memecahkan format:

aiSummary = 'Ditutup oleh agen "L2".\n{ "note": "cek ulang" }';

Hasilnya bukan lagi JSON valid karena ada karakter kutip yang tidak di-escape dengan benar.

Reproduksi pada query analitik

Jika sebagian event gagal di-ingest atau berubah menjadi log mentah, query seperti ini mulai bias:

SELECT event_type, COUNT(*)
FROM audit_events
WHERE occurred_at >= NOW() - INTERVAL '1 day'
GROUP BY event_type;

Angkanya turun bukan karena event tidak terjadi, tetapi karena event tertentu gagal diparse lalu tidak masuk tabel terstruktur, atau masuk dengan kolom kosong.

Investigasi: bagaimana tim menemukan root cause

1. Mulai dari event yang hilang, bukan dari model

Langkah paling efektif biasanya membandingkan tiga lapisan:

  1. Jumlah aksi bisnis aktual di database utama
  2. Jumlah message yang dikirim ke audit pipeline
  3. Jumlah record audit yang berhasil diindeks atau disimpan terstruktur

Jika angka di langkah 1 dan 2 cocok tetapi langkah 3 turun, kerusakan ada di serialisasi, transport, atau parsing downstream.

2. Ambil sampel raw log yang gagal

Jangan hanya melihat dashboard agregat. Ambil beberapa payload mentah yang ditandai gagal parse. Di kasus ini, pola mulai terlihat: semua payload gagal memiliki ai_summary dengan karakter khusus, multi-baris, atau format semi-terstruktur.

3. Telusuri asumsi di boundary

Tim menemukan bahwa event audit diserialisasi dengan benar saat disimpan ke database, tetapi tidak saat dikirim ke sistem log tertentu. Ada satu boundary yang diam-diam menggunakan string interpolation agar “mudah dibaca”. Di sinilah output AI merusak struktur.

4. Verifikasi kontrak skema antar-service

Ternyata beberapa consumer menganggap ai_summary opsional string bebas, sedangkan consumer lain mencoba mengekstrak metadata darinya. Ketidakselarasan kontrak ini membuat bug menyebar ke query analitik.

Kenapa validasi skema tetap gagal menangkap bug?

Ini pertanyaan penting. Banyak tim merasa aman karena sudah memiliki validator. Masalahnya, validasi sering dipasang di tempat yang salah atau terlalu longgar.

Kasus umum kegagalan validasi

  • Validasi dilakukan sebelum enrichment AI, tetapi tidak setelah payload akhir dibentuk.
  • Skema terlalu permisif, misalnya hanya mengecek ai_summary bertipe string, tanpa batas panjang, karakter kontrol, atau format.
  • Skema tidak dipakai di semua boundary, misalnya hanya di API masuk, bukan saat publish ke queue atau logger.
  • Payload tervalidasi sebagai objek aplikasi, tetapi rusak ketika diubah lagi menjadi string dengan cara manual.

Contoh skema yang terlalu longgar:

{
  "type": "object",
  "properties": {
    "event_type": {"type": "string"},
    "ai_summary": {"type": "string"}
  },
  "required": ["event_type"]
}

Skema di atas memang memastikan ai_summary adalah string, tetapi tidak cukup untuk menjamin aman bagi downstream yang mengharapkan satu baris, panjang terbatas, atau bebas karakter kontrol tertentu.

Root cause yang sebenarnya

Root cause bukan sekadar “model kadang mengembalikan format aneh”. Itu hanya pemicu. Penyebab sistemiknya adalah:

  • Output AI diperlakukan sebagai string internal yang aman.
  • Tidak ada boundary type yang memisahkan data mentah dari data tervalidasi.
  • Serialisasi dilakukan manual di salah satu titik.
  • Kontrak skema tidak konsisten antar-service.
  • Tidak ada fallback yang jelas ketika output AI gagal memenuhi kontrak.

Di sinilah ide dari “Your AI Is Not a Tool” relevan secara teknis: jika Anda memperlakukan AI seperti helper function biasa, Anda cenderung melewatkan pola pertahanan yang lazim untuk integrasi eksternal, seperti validasi ketat, timeout, retry terbatas, observability, dan degradasi terkontrol.

Perbaikan yang benar: bukan satu patch, tetapi lapisan pertahanan

1. Gunakan boundary type untuk output AI

Jangan langsung menyuntikkan hasil model ke payload audit final. Bungkus dulu dalam tipe terpisah, misalnya:

type RawAiSummary = {
  provider: string;
  model?: string;
  rawText: string;
  receivedAt: string;
};

type ValidatedAiSummary = {
  text: string;
  truncated: boolean;
};

Manfaatnya adalah memaksa pipeline membedakan data mentah dari data yang sudah lolos aturan internal. Anda jadi punya titik eksplisit untuk validasi, sanitasi, dan fallback.

2. Sanitasi sebelum masuk ke audit/log

Sanitasi bukan berarti mengubah makna sebebas mungkin. Tujuannya adalah menjaga kontrak teknis. Contoh aturan yang masuk akal:

  • Batasi panjang maksimal
  • Normalisasi newline menjadi spasi atau format aman lain
  • Hapus atau escape karakter kontrol tertentu
  • Tolak blok markdown, JSON mentah, atau struktur yang tidak diharapkan bila audit hanya butuh ringkasan satu paragraf
function sanitizeAiSummary(raw) {
  const singleLine = raw.replace(/[\r\n]+/g, ' ').trim();
  const noControlChars = singleLine.replace(/[\u0000-\u001F\u007F]/g, '');
  const maxLen = 500;
  return {
    text: noControlChars.slice(0, maxLen),
    truncated: noControlChars.length > maxLen
  };
}

Catatan: aturan sanitasi harus disesuaikan dengan kebutuhan bisnis. Jika Anda memang butuh format multi-baris atau data terstruktur, simpan sebagai objek tervalidasi, bukan string bebas.

3. Terapkan JSON schema pada payload akhir, bukan hanya awal

Validasi perlu dilakukan pada bentuk final yang benar-benar akan dipublish, disimpan, atau dikirim ke logger.

{
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "event_type": {"type": "string", "minLength": 1},
    "actor_id": {"type": "string", "minLength": 1},
    "resource_id": {"type": "string", "minLength": 1},
    "occurred_at": {"type": "string"},
    "ai_summary": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "text": {"type": "string", "maxLength": 500},
        "truncated": {"type": "boolean"}
      },
      "required": ["text", "truncated"]
    }
  },
  "required": ["event_type", "actor_id", "resource_id", "occurred_at"]
}

Perhatikan bahwa ai_summary tidak lagi string mentah. Dengan bentuk objek tervalidasi, lebih sulit bagi consumer untuk salah asumsi.

4. Jangan pernah membangun JSON dengan konkatenasi string

Gunakan serializer standar di bahasa pemrograman Anda. Ini aturan dasar, tetapi justru sering dilanggar di jalur logging.

const payload = {
  event_type: event.type,
  actor_id: event.actorId,
  ai_summary: validatedAiSummary
};

logger.info(JSON.stringify(payload));

Lebih baik lagi, gunakan logger yang menerima objek langsung agar serialisasi dan escaping ditangani konsisten.

5. Sediakan fallback bila AI gagal

Audit tidak boleh bergantung total pada AI. Jika validasi gagal, timeout terjadi, atau provider error, event audit utama tetap harus tersimpan.

Contoh strategi fallback:

  • Simpan audit tanpa ringkasan AI
  • Simpan status ai_summary_status: "unavailable"
  • Simpan hasil mentah di storage terpisah untuk forensik, bukan di payload utama
function buildAuditEvent(baseEvent, rawAiOutput) {
  let aiSummary = null;

  if (rawAiOutput) {
    try {
      aiSummary = sanitizeAiSummary(rawAiOutput);
    } catch (_) {
      aiSummary = null;
    }
  }

  return {
    ...baseEvent,
    ai_summary: aiSummary,
    ai_summary_status: aiSummary ? 'ok' : 'unavailable'
  };
}

6. Terapkan timeout dan isolasi eksekusi

Jika ringkasan AI dibuat sinkron di jalur request utama, timeout provider bisa memperlambat seluruh transaksi audit. Praktik yang lebih aman adalah memisahkan enrichment AI ke proses asynchronous atau memberi batas waktu ketat dengan fallback.

Trade-off-nya:

  • Synchronous: data langsung lengkap, tetapi latensi dan kegagalan provider memengaruhi request utama.
  • Asynchronous: lebih tangguh, tetapi event audit awal mungkin belum memiliki ringkasan saat pertama kali muncul.

Untuk sistem audit, umumnya integritas event utama lebih penting daripada kelengkapan ringkasan AI.

7. Tambahkan observability khusus untuk enrichment AI

Jangan cukup memantau error provider. Pantau juga kualitas kontrak output.

Metrik yang berguna:

  • Jumlah event audit dengan ai_summary_status=ok vs unavailable
  • Tingkat kegagalan validasi skema setelah enrichment
  • Panjang rata-rata dan persentil output AI
  • Jumlah sanitasi/truncation
  • Timeout rate dan retry rate
  • Jumlah log ingestion failure yang terkait field AI

Tambahkan correlation ID agar satu event bisa ditelusuri dari request bisnis, queue, worker AI, audit store, hingga analytics pipeline.

Desain yang lebih aman untuk jangka panjang

Jika ringkasan AI benar-benar penting, pertimbangkan memisahkan data audit inti dari data enrichment.

Pola yang lebih robust

  • Audit event inti: deterministik, kecil, terstruktur ketat, tanpa ketergantungan pada AI.
  • AI enrichment record: entitas terpisah yang mereferensikan audit event melalui ID.

Dengan pola ini, query kepatuhan atau forensik tidak rusak hanya karena enrichment gagal. Analytics juga bisa memilih apakah ingin menggabungkan data AI atau tidak.

Contohnya:

{
  "audit_event_id": "aud_789",
  "summary_status": "ok",
  "summary": {
    "text": "Tiket ditutup setelah verifikasi identitas.",
    "truncated": false
  },
  "provider": "external-llm",
  "received_at": "2026-08-09T10:15:02Z"
}

Trade-off pendekatan ini adalah kompleksitas query bertambah karena perlu join atau lookup tambahan. Namun untuk sistem audit yang sensitif, isolasi semacam ini sering sepadan.

Kesalahan umum yang sering terulang

  • Menganggap output AI “biasanya aman” karena prompt sudah diatur.
  • Menyimpan hasil model langsung ke field yang dipakai analytics tanpa normalisasi.
  • Memakai validator tipe dasar tetapi tidak memvalidasi bentuk final payload.
  • Mencampur tujuan manusia dan mesin dalam satu field string bebas.
  • Menggunakan retry agresif saat validasi gagal, padahal payload-nya memang invalid.
  • Tidak menyimpan sampel output mentah untuk investigasi insiden.

Checklist pencegahan untuk developer backend

  • Perlakukan output AI sebagai input tak tepercaya, setara integrasi eksternal.
  • Buat boundary type yang memisahkan output mentah dan output tervalidasi.
  • Gunakan serializer JSON standar; jangan membangun JSON dengan string concatenation.
  • Terapkan JSON schema pada payload akhir yang benar-benar keluar dari service.
  • Batasi panjang, normalisasi newline, dan tangani karakter kontrol.
  • Jangan gabungkan data audit inti dan enrichment AI tanpa kontrak yang jelas.
  • Sediakan fallback bila AI timeout, invalid, atau unavailable.
  • Tambahkan timeout ketat dan pertimbangkan pemrosesan asynchronous.
  • Instrumentasikan metrik validasi, truncation, timeout, dan ingestion failure.
  • Gunakan correlation ID untuk pelacakan lintas service.
  • Uji dengan payload yang mengandung kutip, newline, markdown, JSON parsial, dan output panjang.
  • Pastikan consumer analytics memahami bentuk data yang sama, bukan asumsi berbeda-beda.

Penutup

Pelajaran utama dari bug ini bukan bahwa AI “sering salah”, melainkan bahwa sistem backend gagal membangun batas yang benar di sekelilingnya. Saat ringkasan AI merusak query audit dan log, masalah sesungguhnya ada pada desain integrasi: output model diperlakukan sebagai string aman, bukan sebagai data eksternal yang harus disanitasi, divalidasi, diisolasi, dan diamati.

Jika Anda menambahkan AI ke alur audit, logging, atau analytics, jangan berhenti di prompt dan response parsing. Pastikan ada kontrak tipe yang jelas, validasi skema pada payload akhir, fallback non-destruktif, timeout yang masuk akal, dan observability yang cukup untuk membedakan error model dari kerusakan pipeline. Itu cara praktis menerjemahkan gagasan “Your AI Is Not a Tool” ke rekayasa backend yang lebih aman.