Handbook AI Engineering
Bagian VI - Bab 18

Observability dengan LangSmith

Mengapa logging biasa tidak cukup, setup dan tracing LangSmith, empat metrik yang perlu dipantau di produksi, dan evaluasi otomatis dengan LLM-as-a-Judge.

Apa yang Akan Kamu Pahami Setelah Bab Ini

Sistem AI yang sudah berjalan di produksi adalah kotak hitam tanpa observability. Kamu tidak tahu prompt mana yang gagal, tool mana yang dipanggil tapi memberikan hasil buruk, atau di mana bottleneck performa berada. LangSmith membuka kotak hitam tersebut, memberi visibilitas penuh ke dalam setiap langkah eksekusi sistem RAG dan Agent yang sudah dibangun di bab-bab sebelumnya.

18.1 Mengapa Logging Biasa Tidak Cukup untuk Sistem AI

Logging konvensional, menulis baris teks ke file, cukup untuk aplikasi web biasa. Tapi sistem AI memiliki karakteristik yang membuat logging biasa tidak memadai.

  • Eksekusi multi-langkah yang bercabang. Satu request ke agent bisa melewati 5-10 langkah yang berbeda. Log baris per baris tidak menangkap hubungan hierarki antar langkah ini.
  • Input dan output yang panjang. Setiap langkah bisa melibatkan ratusan token sebagai input dan output. Logging ini ke teks biasa tidak terstruktur dan sulit dicari.
  • Kebutuhan debugging yang unik. Ketika agent memberikan jawaban yang salah, kamu perlu tahu persis: prompt apa yang dikirim ke LLM, token apa yang dikonsumsi, tool mana yang dipanggil, dan hasil apa yang dikembalikan, semuanya dalam konteks yang terhubung.
Logging Biasa
[10:42:01] INFO Request masuk
[10:42:01] INFO Memanggil retrieve()
[10:42:02] INFO 3 chunk ditemukan
[10:42:02] INFO Memanggil LLM
[10:42:05] ERROR Jawaban tidak relevan
[10:42:05] INFO Request selesai
LangSmith
Run: tanya() — 4.2s — 1.842 token
retrieve() — 0.8s — 3 chunk
chunk 1: "Pengembalian 30 hari..."
generate() — 3.4s
System: "Jawab berdasarkan [KONTEKS]..."
User: "Cara retur barang?" + 3 chunk

18.2 Setup LangSmith

LangSmith bekerja melalui environment variable, setelah di-set, semua eksekusi LangChain dan LangGraph otomatis terekam tanpa perubahan kode apapun.

Setup .env

Cukup tambahkan empat environment variable ke file .env semua eksekusi LangChain dan LangGraph akan otomatis terekam di dashboard LangSmith tanpa perubahan kode apapun.

# Dapatkan API key dari: https://smith.langchain.com
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=ls__your_langsmith_key_here
LANGCHAIN_PROJECT=rework-ai-production  # nama project di dashboard
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com

# Setelah ini, semua pemanggilan via LangChain/LangGraph
# otomatis dikirim ke LangSmith. Tidak perlu ubah kode apapun.

# Untuk menonaktifkan sementara (misal saat testing lokal):
# LANGCHAIN_TRACING_V2=false

Tracing Manual

Untuk fungsi Python biasa yang tidak menggunakan LangChain, gunakan decorator @traceable agar tetap terlacak di LangSmith sebagai bagian dari run yang sama.

from langsmith import traceable

# @traceable membungkus fungsi apapun sebagai node
# yang terlihat di LangSmith, berguna untuk fungsi custom
# yang tidak menggunakan abstraksi LangChain

@traceable(name="retrieve_chunks", run_type="retriever")
def retrieve(query: str, top_k: int = 4) -> list[dict]:
    \"\"\"Fungsi ini sekarang terlihat di LangSmith sebagai 'retriever'.\"\"\"
    embedding_query = model.encode(query).tolist()
    hasil = index.query(vector=embedding_query, top_k=top_k, include_metadata=True)
    return [m["metadata"] for m in hasil["matches"]]

@traceable(name="generate_answer", run_type="llm")
def generate(query: str, chunks: list[dict]) -> str:
    \"\"\"Fungsi ini terlihat di LangSmith sebagai 'llm' call.\"\"\"
    konteks = "\n\n".join([c["teks"] for c in chunks])
    response = model_llm.generate_content(
        f"[KONTEKS]\n{konteks}\n\n[PERTANYAAN]\n{query}"
    )
    return response.text

@traceable(name="rag_pipeline", run_type="chain")
def tanya(query: str) -> dict:
    \"\"\"Root trace, merangkum seluruh pipeline RAG.\"\"\"
    chunks = retrieve(query)          # -> terlihat sebagai child run
    jawaban = generate(query, chunks)  # -> terlihat sebagai child run
    return {"jawaban": jawaban, "n_chunks": len(chunks)}

Tracing RAG dengan Metadata

Menambahkan metadata kustom ke trace, berguna untuk memfilter dan mengelompokkan run di dashboard berdasarkan sumber, pengguna, atau tag tertentu.

from langsmith import traceable
from langsmith.run_helpers import get_current_run_tree

@traceable(
    name="rag_pipeline",
    run_type="chain",
    tags=["production", "rag", "v2"]  # Tags memudahkan filtering di dashboard
)
def tanya(query: str, session_id: str = "anonymous") -> dict:
    # Tambahkan metadata kustom ke run saat ini
    run_tree = get_current_run_tree()
    if run_tree:
        run_tree.add_metadata({
            "session_id": session_id,
            "query_length": len(query),
            "environment": os.getenv("ENVIRONMENT", "development")
        })

    chunks = retrieve(query)
    jawaban = generate(query, chunks)

    # Tambahkan feedback setelah run selesai
    if run_tree:
        run_tree.add_metadata({
            "n_chunks_retrieved": len(chunks),
            "chunks_sources": [c.get("sumber") for c in chunks]
        })

    return {"jawaban": jawaban, "sumber": [c["sumber"] for c in chunks]}

18.3 Apa yang Perlu Dipantau di Produksi

Setelah LangSmith terhubung, ada empat metrik yang paling penting untuk dipantau secara rutin, bukan semua metrik yang tersedia, tapi yang paling berdampak pada kualitas dan biaya sistem.

Metrik Yang Perlu Dipantau Cara Memperbaiki Target / Alert
Latency (P95)Bukan rata-rata, tapi persentil ke-95. Mean bisa menyembunyikan outlier yang sangat lambat.Identifikasi langkah paling lambat, gunakan caching, optimalkan chunk_size.P95 < 5 detik untuk RAG
Token Usage & BiayaTotal token per hari, rata-rata per request, tren kenaikan biaya.Tanda bahaya: satu request konsumsi jauh lebih banyak token, biasanya chunk yang tidak perlu ikut masuk.Set alert jika biaya harian > threshold
Error RatePersentase request gagal, jenis error paling sering, tren setelah deployment baru.Jenis umum: timeout Pinecone, rate limit LLM API, validation error Pydantic.Alert jika error rate > 1% dalam 5 menit
Retrieval QualityDistribusi skor cosine similarity dari chunk yang diambil.Re-index dengan model embedding lebih baik, atau sesuaikan threshold.Pantau jika skor rata-rata < 0.6

18.4 Evaluasi Otomatis dengan LLM-as-a-Judge

Di Bab 13, evaluasi generation dilakukan dengan pencocokan substring, sederhana dan cepat, tapi tidak bisa menilai kualitas jawaban yang parafrase atau menjawab dengan benar dari sudut pandang berbeda. LangSmith mendukung pendekatan yang lebih canggih: menggunakan LLM lain sebagai penilai.

Implementasi LLM-as-a-Judge: LLM kedua (model yang lebih kuat) menilai kualitas jawaban yang dihasilkan oleh pipeline RAG. Berguna untuk evaluasi berkala menggunakan test set yang terus berkembang.

from langsmith.evaluation import evaluate
from langsmith import Client
import google.generativeai as genai

client = Client()

# 1. Definisikan evaluator berbasis LLM
def evaluator_faithfulness(run, example) -> dict:
    \"\"\"
    Evaluasi apakah jawaban setia pada konteks dokumen.
    Gunakan model yang lebih kuat dari yang dipakai RAG.
    \"\"\"
    pertanyaan = example.inputs["pertanyaan"]
    jawaban = run.outputs["jawaban"]
    konteks = run.outputs.get("konteks_digunakan", "")

    prompt_hakim = f\"\"\"
Kamu adalah hakim yang menilai kualitas jawaban AI.

Pertanyaan: {pertanyaan}
Konteks yang tersedia: {konteks}
Jawaban yang diberikan: {jawaban}

Nilai jawaban ini dalam skala 1-5:
- 5: Jawaban akurat, sepenuhnya berdasarkan konteks
- 3: Jawaban sebagian benar, ada info tidak dari konteks
- 1: Jawaban tidak relevan atau mengarang

Balas HANYA dengan angka 1-5 dan alasan singkat.
Format: SKOR: X\nALASAN: ...
\"\"\"

    model_hakim = genai.GenerativeModel("gemini-1.5-pro")
    response = model_hakim.generate_content(prompt_hakim)

    # Parse skor dari respons
    baris = response.text.strip().split("\n")
    skor_str = baris[0].replace("SKOR:", "").strip()
    skor = int(skor_str) if skor_str.isdigit() else 0

    return {
        "key": "faithfulness",
        "score": skor / 5,  # normalisasi ke 0-1
        "comment": "\n".join(baris[1:])
    }

# 2. Jalankan evaluasi pada dataset di LangSmith
evaluate(
    tanya,                        # fungsi yang dievaluasi
    data="rework-qa-test-set",    # nama dataset di LangSmith
    evaluators=[evaluator_faithfulness],
    experiment_prefix="rag-v2"    # label eksperimen
)

Kesalahan Umum

Jangan mengirim data sensitif pengguna ke LangSmith tanpa pertimbangan.

LangSmith merekam seluruh input dan output, termasuk pertanyaan pengguna yang mungkin mengandung informasi pribadi. Sebelum mengaktifkan tracing di produksi, pastikan kebijakan privasi produkmu mengizinkan data dikirim ke layanan pihak ketiga. Pertimbangkan untuk menyamarkan atau memotong data sensitif sebelum masuk ke trace.

Pantau P95, bukan rata-rata latency.

Rata-rata latensi bisa terlihat baik meskipun 5% pengguna mengalami waktu tunggu yang sangat lama. Persentil ke-95 memberi gambaran yang lebih jujur tentang pengalaman pengguna terburuk yang masih sering terjadi. Set alert berdasarkan P95, bukan mean.

Gunakan LangSmith untuk membandingkan eksperimen, bukan hanya memantau produksi.

Setiap kali mengubah System Prompt, chunk_size, atau model embedding, jalankan test set yang sama dan bandingkan hasilnya di LangSmith sebagai dua eksperimen berbeda. Ini memberi bukti kuantitatif bahwa perubahan tersebut benar-benar memperbaiki kualitas bukan sekadar terasa lebih baik saat diuji manual.

Aktifkan tracing sejak development, bukan hanya di produksi.

LangSmith paling berguna saat digunakan sejak awal, sehingga kamu sudah terbiasa membaca trace sebelum sistem masuk ke produksi. Gunakan project yang berbeda untuk memisahkan trace development dan production: LANGCHAIN_PROJECT=rework-dev vs LANGCHAIN_PROJECT=rework-prod.

Ringkasan Bab 18

Checklist Pemahaman
  • Saya memahami mengapa logging biasa tidak cukup untuk sistem AI: tidak menangkap hierarki langkah, input/output panjang, dan konteks antar langkah yang dibutuhkan untuk debugging.
  • Saya bisa mengaktifkan LangSmith dengan menambahkan empat environment variable ke .env, semua eksekusi LangChain/LangGraph otomatis terekam tanpa perubahan kode.
  • Saya bisa menggunakan decorator @traceable untuk membungkus fungsi Python biasa agar terlihat sebagai node di LangSmith, termasuk menambahkan metadata kustom.
  • Saya memantau empat metrik utama di produksi: latency P95, token usage dan biaya, error rate, dan distribusi skor retrieval, dan tahu apa yang perlu dilakukan ketika di luar threshold.
  • Saya memahami konsep LLM-as-a-Judge dan bisa mengimplementasikan evaluator yang menggunakan LLM lebih kuat untuk menilai faithfulness jawaban pipeline RAG.
  • Saya menggunakan project LangSmith yang berbeda untuk memisahkan trace development dan production, dan menggunakan fitur eksperimen untuk membandingkan perubahan secara kuantitatif.
  • Saya mempertimbangkan implikasi privasi sebelum mengaktifkan tracing di produksi, termasuk apakah data pengguna boleh dikirim ke layanan pihak ketiga.