Bỏ qua

Bài 7: LLM Observability & Guardrails at Scale

Tổng quan

Module I, Bài 7 dạy guardrails cơ bản (prompt injection, PII, output validation) và setup LangSmith/LangFuse. Module II, Bài 5 dạy tracing agent và OpenTelemetry.

Bài này chuyển sang vận hành ở scale:

  • Ba tầng observability và câu hỏi mỗi tầng trả lời.
  • Tracing production: sampling, PII trong trace, chi phí của chính observability.
  • Production dashboard: cost per feature, hallucination rate, user feedback, SLO.
  • Guardrails ở scale: latency overhead, false positive, fail-open vs fail-closed.
  • Incident response: 4 playbook (cost spike, hallucination spike, jailbreak, provider outage).

1. Ba tầng observability

graph TB
    T[Trace<br/>1 request: mọi node, tool call, token, latency] --> M[Metric<br/>tổng hợp theo thời gian: cost, p95, hit rate]
    M --> L[Log<br/>sự kiện rời rạc: lỗi, guardrail trigger, fallback]
Tầng Trả lời câu hỏi Ví dụ công cụ
Trace "Request này chậm/sai ở bước nào?" LangSmith, LangFuse, OTel + Jaeger
Metric "Xu hướng cost/latency/chất lượng đang đi đâu?" Prometheus/Grafana, Cloud Monitoring, dashboard của LangSmith
Log "Chuyện gì xảy ra lúc 02:14? Có bao nhiêu lần fallback?" Cloud Logging, Loki, ELK

Quy tắc: trace để debug một ca, metric để phát hiện xu hướng, log để điều tra sự kiện. Thiếu tầng nào là mù ở loại câu hỏi đó.


2. Tracing Production

Sampling - không trace 100%

Ở volume cao, lưu mọi trace tốn tiền và chậm. Chiến lược:

Chiến lược Cách Dùng khi
Head sampling Giữ ngẫu nhiên X% request ngay từ đầu Volume rất cao, chỉ cần bức tranh thống kê
Tail sampling Buffer rồi giữ trace nếu: có lỗi, latency > p99, guardrail trigger, chi phí cao Muốn giữ 100% ca "thú vị" mà không lưu hết ca bình thường
Luôn giữ Request bị đánh dấu (user báo lỗi, feedback âm) Điều tra khiếu nại cụ thể
def should_sample(ctx) -> bool:
    if ctx.error or ctx.latency_ms > P99 or ctx.guardrail_triggered:
        return True                     # tail: giữ ca bất thường
    return random.random() < 0.05       # head: 5% ca bình thường

PII trong trace

Trace chứa prompt + output → có thể chứa PII người dùng nhập. Trước khi gửi lên dịch vụ ngoài:

  • Redact (Presidio / regex tiếng Việt - xem M1, Bài 7) các trường input, output trong hook trước khi export.
  • Hoặc self-host LangFuse để dữ liệu không rời hạ tầng của bạn.
  • Đặt retention ngắn (14–30 ngày) cho trace có nội dung; giữ metric (không có nội dung) lâu hơn.

Chi phí của chính observability

  • Trace đầy đủ + judge chấm hallucination trên mẫu = một khoản chi phí thật.
  • Ngân sách hoá: "observability ≤ X% chi phí inference". Nếu vượt → giảm sampling, giảm tần suất chấm.

3. Token & Cost Analytics

Dùng lại record_cost() từ Bài 3, gắn tag đủ để cắt lát:

metrics.emit("llm_cost_usd", cost, tags={
    "feature": feature,        # rag_answer, summarize, classify...
    "model": model,
    "cache": "hit" | "miss",
    "cascade": "cheap" | "escalated",
    "prompt_version": pv,
})

Latency breakdown

Một request RAG chậm - chậm ở đâu?

graph LR
    REQ[Request] --> RW[Query rewrite<br/>~120ms] --> RET[Retrieval<br/>~80ms] --> RERANK[Rerank<br/>~150ms] --> LLM[LLM generate<br/>~2400ms] --> GR[Output guardrail<br/>~90ms]

Trace phải tách được các span này. Thường phát hiện: rerank hoặc guardrail âm thầm cộng 200–400ms; hoặc retrieval chậm khi index lớn lên.


4. Production Dashboard

graph TB
    subgraph "Dashboard production"
        A[Cost per feature<br/>ngày / tuần]
        B[Faithfulness / hallucination rate<br/>chấm judge trên mẫu]
        C[Latency p50 / p95 / p99<br/>tổng + theo span]
        D[User feedback<br/>thumbs + tín hiệu ngầm]
        E[Cache hit rate<br/>tầng 1 + tầng 2]
        F[Error rate + fallback count<br/>theo loại]
        G[SLO / error budget<br/>còn lại bao nhiêu]
    end
Widget Nguồn dữ liệu Ngưỡng cảnh báo gợi ý
Cost per feature llm_cost_usd tag feature Feature tăng > 50% tuần-trên-tuần; tổng > 120% dự phóng
Hallucination rate Judge/RAGAS faithfulness trên mẫu 1–5% traffic Faithfulness < baseline − 0.05
Latency p95 Span tổng p95 > SLO (ví dụ 4s); p99 > 2× p95
User feedback Nút thumbs; tín hiệu ngầm: bỏ giữa chừng, hỏi lại ngay, copy đáp án Tỉ lệ thumbs-down > X%; retry-rate tăng
Error / fallback Log tag loại (429, timeout, guardrail block, provider fallback) Bất kỳ loại nào tăng đột biến
SLO / error budget availability + latency SLO Error budget cháy nhanh hơn dự kiến

Tín hiệu ngầm từ người dùng

Không phải ai cũng bấm thumbs. Tín hiệu rẻ mà giá trị:

  • Regenerate / hỏi lại ngay trong < 10s → câu trả lời có thể tệ.
  • Bỏ giữa stream → quá chậm hoặc lạc đề.
  • Copy đoạn trả lời → có thể hữu ích.
  • Rời phiên ngay sau 1 câu → không giải quyết được nhu cầu.

5. Guardrails at Scale

Guardrails cơ bản đã có ở M1, Bài 7. Ở production, câu hỏi chuyển từ "làm thế nào" sang "chịu được chi phí vận hành không".

graph LR
    IN[Input] --> GI[Input guard<br/>injection, PII, off-topic]
    GI -->|pass| LLM[LLM]
    GI -->|block| REFUSE1[Từ chối / hỏi lại]
    LLM --> GO[Output guard<br/>PII leak, groundedness, toxicity, format]
    GO -->|pass| OUT[Trả người dùng]
    GO -->|fail| ACT{Fail-open / Fail-closed?}
Vấn đề vận hành Chi tiết
Latency overhead Mỗi guard là thêm 50–300ms (regex rẻ; LLM-based detector đắt). Đo và ngân sách hoá; chạy song song các guard độc lập
False positive rate Guard quá gắt chặn cả câu hợp lệ → user bực. Đo FP trên traffic thật; tune ngưỡng; log mọi lần block để review
Fail-open vs fail-closed Guard service lỗi/timeout thì làm gì?
Thứ tự & chi phí Chạy guard rẻ trước (regex PII) rồi mới guard đắt (LLM injection detector); dừng sớm khi đã block

Fail-open vs Fail-closed

Fail-open (cho qua khi guard lỗi) Fail-closed (chặn khi guard lỗi)
Rủi ro Nội dung xấu lọt khi guard down Từ chối cả request hợp lệ khi guard down
Hợp với Guard "nice-to-have" (ví dụ format check) Guard bắt buộc (PII leak, nội dung nguy hiểm)
Bắt buộc kèm Alert khi rơi vào fail-open + đếm số lần Fallback nhẹ hơn (regex-only) trước khi từ chối hẳn

Guardrail cũng là điểm lỗi

Một LLM-based injection detector gọi model ngoài: nó timeout thì cả request treo. Đặt timeout riêng, có nhánh fallback (regex), và log mỗi lần fallback → đưa lên dashboard (mục 4, "Error / fallback").


6. Incident Response

Bốn playbook. Mỗi playbook: tín hiệu phát hiện → khoanh vùng → giảm thiểu → sau sự cố.

6.1. Cost Spike

Bước Hành động
Phát hiện Alert budget (Bài 3): chi phí giờ này > 3× trung bình; hoặc đạt 80% ngân sách sớm bất thường
Khoanh vùng Dashboard cost per feature + per user: feature nào / user nào nhảy vọt? Cache hit rate có tụt (key bị đổi)? Prompt version mới có làm context phình?
Giảm thiểu Bật/giảm ngưỡng hard limit per user; tạm route feature thủ phạm sang model rẻ; nếu do cache miss hàng loạt → rollback thay đổi làm hỏng cache key; nếu do loop agent → giảm max_iterations
Sau sự cố Thêm alert sớm hơn; thêm test cache-key vào CI; ghi runbook

6.2. Hallucination Spike

Bước Hành động
Phát hiện Faithfulness (judge trên mẫu) tụt dưới baseline − 0.05; thumbs-down tăng; feedback "sai thông tin"
Khoanh vùng Đổi gì gần đây: prompt version? model? retrieval (index rebuild, embedding đổi)? Slice nào tệ nhất (dùng eval theo slice Bài 2)?
Giảm thiểu Rollback prompt version / model config về last-known-good (Bài 6); nếu do index → khôi phục snapshot index trước đó; siết guardrail groundedness tạm thời
Sau sự cố Thêm case vào golden set từ đúng các câu bị sai; siết eval gate cho slice liên quan

6.3. Jailbreak / Prompt Injection Attempt

Bước Hành động
Phát hiện Guardrail injection log tăng đột biến; xuất hiện output rò rỉ system prompt / phá vai; một user gửi nhiều biến thể tấn công
Khoanh vùng Mẫu tấn công nào đang lọt? Từ ít user hay lan rộng? Guard đang fail-open?
Giảm thiểu Chuyển guard injection sang fail-closed cho traffic nghi ngờ; thêm pattern vào input filter; rate-limit / block user tấn công; nếu system prompt bị lộ → xoay các secret nhắc trong đó
Sau sự cố Thêm mẫu tấn công vào golden set slice injection; red-team lại; xem M1, Bài 7

6.4. Provider Outage / Degradation

Bước Hành động
Phát hiện Error rate 5xx / timeout từ provider tăng; latency p95 tăng gấp bội; status page provider
Khoanh vùng Một model hay cả provider? Khu vực nào? Có phải quota bị vượt (429 chứ không phải 5xx)?
Giảm thiểu Chuyển sang fallback model/provider đã cấu hình sẵn; bật retry backoff dài hơn (Bài 4); giảm tính năng không thiết yếu; hiện banner "đang chậm"
Sau sự cố Kiểm tra fallback có thực sự chạy (diễn tập định kỳ); điều chỉnh timeout/retry; đa dạng hoá provider cho tính năng quan trọng
# Fallback provider - cấu hình sẵn, diễn tập định kỳ
PROVIDERS = ["claude-sonnet-5", "gpt-4o"]     # thứ tự ưu tiên

async def generate(messages) -> str:
    last = None
    for model in PROVIDERS:
        try:
            return await call_with_retry(model=model, messages=messages)
        except (ProviderError, APITimeoutError) as e:
            last = e
            metrics.emit("provider_fallback", 1, tags={"from": model})
    raise last

7. Hands-on: LangSmith tracing + cost dashboard cho Vietnamese RAG agent

Dùng RAG agent từ Capstone Module I đã deploy ở Bài 5.

Bước 1 - Tracing có sampling

  • Bật LangSmith/LangFuse tracing (như M1, Bài 7).
  • Thêm should_sample(): 100% ca lỗi/guardrail/slow, 5% ca bình thường.
  • Redact PII ở hook trước export (regex tiếng Việt cho SĐT, email, CCCD).
  • Đặt retention 30 ngày cho trace.

Bước 2 - Span breakdown

  • Instrument các span: query_rewrite, retrieve, rerank, llm_generate, output_guard.
  • Chạy 30 câu hỏi, xem trace: span nào chiếm nhiều thời gian nhất?

Bước 3 - Cost dashboard

  • record_cost() với tag feature, model, cache, prompt_version.
  • Dashboard (Grafana/Cloud Monitoring/LangSmith) với widget: cost per feature (ngày), latency p50/p95/p99, cache hit rate, error/fallback count.
  • Chấm faithfulness bằng judge trên 5% traffic → widget hallucination rate.

Bước 4 - Alert + một incident

  • Alert: cost giờ này > 3× trung bình 7 ngày → gửi Slack/email.
  • Diễn tập cost spike: tạm sửa prompt cho context phình gấp 3 (lấy top-30 chunk) → chạy tải → xác nhận alert kêu → theo playbook 6.1 khoanh vùng bằng dashboard → rollback prompt version.

Bước 5 (mở rộng) - Fallback provider

  • Cấu hình PROVIDERS với 2 model khác nhà.
  • Giả lập outage (chặn network tới provider 1 / trả 503) → xác nhận tự chuyển provider 2, provider_fallback metric tăng, người dùng vẫn có câu trả lời.

Tiêu chí hoàn thành

  • Trace có sampling (100% ca bất thường, ~5% ca thường) + PII đã redact
  • Trace tách được span; chỉ ra được bước chậm nhất
  • Dashboard có ≥ 5 widget: cost/feature, latency p95, cache hit, error/fallback, hallucination rate
  • Alert cost spike hoạt động (đã kích hoạt thật trong diễn tập)
  • Thực hiện trọn 1 playbook incident: phát hiện → khoanh vùng bằng dashboard → mitigate
  • (Mở rộng) fallback provider chạy khi provider chính lỗi

Tóm tắt

graph LR
    APP[RAG / Agent] --> TRACE[Trace có sampling + redact PII]
    APP --> METRIC[Metric: cost/feature, p95, hit rate, hallucination]
    APP --> LOG[Log: lỗi, guardrail, fallback]
    METRIC --> DASH[Dashboard + SLO]
    DASH --> ALERT{Alert}
    ALERT -->|cost spike| P1[Playbook: khoanh feature/user -> hard limit / route rẻ / rollback]
    ALERT -->|hallucination| P2[Playbook: rollback prompt/model/index + thêm golden case]
    ALERT -->|jailbreak| P3[Playbook: fail-closed + block user + thêm injection case]
    ALERT -->|provider outage| P4[Playbook: fallback provider + retry dài + giảm tính năng]
Chủ đề Cốt lõi
Ba tầng Trace (debug 1 ca) · Metric (xu hướng) · Log (điều tra sự kiện)
Tracing prod Head/tail sampling; redact PII trước export; retention ngắn cho nội dung; ngân sách hoá chi phí observability
Dashboard Cost/feature, faithfulness (judge trên mẫu), latency p95/p99, feedback + tín hiệu ngầm, error/fallback, SLO
Guardrails at scale Đo latency overhead + false positive; guard rẻ trước; fail-open vs fail-closed có chủ đích; guard cũng là điểm lỗi
Incident response 4 playbook chung khung: phát hiện → khoanh vùng → giảm thiểu → sau sự cố; fallback phải được diễn tập