AI Core cho lập trình viên/Mini-challenge: đọc log ba sự cố LLM
26/54
Bài 26 / 54~15 phútCỗ máy LLMMiễn phí lượt xem

Mini-challenge: đọc log ba sự cố LLM

Ba transcript thật từ môi trường dev: bot đếm chữ sai, bot quên yêu cầu đầu hội thoại, bot trả lời loạn. Tự chẩn đoán cơ chế đứng sau từng sự cố trước khi xem lời giải.

TL;DR: Ba báo cáo lỗi thật từ log request/response LLM đều được gắn cùng một nhãn vô dụng: "bot trả lời sai". Nhưng log gốc luôn mang dấu vết định lượng — độ dài chuỗi, token, tham số sampling — và mỗi sự cố để lại một dấu vết khác nhau. Bài này cho bạn đọc log thô rồi tự chẩn đoán cơ chế đứng sau từng cái, trước khi xem lời giải: kỹ năng là đọc ra dấu vết, không phải đoán từ triệu chứng bề mặt.

Bạn là kỹ sư trực on-call tuần này cho ba sản phẩm nội bộ, cả ba đều gọi chung một model LLM qua API. Sáng thứ Ba, kênh giám sát dồn về ba báo cáo lỗi cùng lúc. Người báo cáo đầu tiên viết đúng một câu: "Bot trả lời sai, xem log giúp." Hai người còn lại cũng viết y hệt vậy, chỉ đổi tên bot.

Ba câu "bot trả lời sai" nghe giống hệt nhau, nhưng khi mở log ra, mỗi cái kể một câu chuyện khác. Việc của bạn không phải sửa code — là đọc đúng log, tìm đúng con số, và gọi tên đúng cơ chế trước khi đề xuất cách sửa.

🎯 Đề bài — ba log, một buổi trực

Với mỗi log dưới đây, hãy tự trả lời trước khi đọc phần Gợi ý hay Lời giải: cơ chế nào đứng sau sự cố, dữ kiện cụ thể nào trong log chứng minh điều đó, và hướng sửa hợp lý là gì.

Log 1 — Trợ lý rút gọn tiêu đề sản phẩm

[QA log — bot rút gọn tiêu đề sản phẩm, ticket #PROD-118]

Request gửi cho model:
  "Rút gọn tiêu đề sau còn tối đa 40 ký tự, giữ nguyên ý nghĩa chính:
  'Bàn phím cơ không dây RGB chống nước dành cho game thủ chuyên nghiệp'"

Response của model:
  "Bàn phím cơ RGB không dây chống nước gaming"
  (model tự thêm dòng cuối: "Độ dài: 40 ký tự — đạt yêu cầu.")

QA đếm lại thủ công (bôi đen chuỗi, xem bộ đếm ký tự của trình soạn thảo):
  43 ký tự thật. Tiêu đề bị cắt xén khi hiển thị trên thẻ sản phẩm.

Ghi chú của QA, sau khi thử thêm vài tiêu đề khác:
  - Toàn tiếng Anh, không dấu: model đếm đúng, lệch 0-1 ký tự.
  - Nhiều dấu tiếng Việt: lệch tăng lên 6-8 ký tự.
  - Không dấu và có dấu đều được model báo là "đạt đúng yêu cầu".

Log 2 — Phiên hỗ trợ khách hàng, gói Enterprise

[Support log — phiên chat nội bộ #4521]

Lượt 1 (khách hàng, 08:02):
  "Từ giờ, mọi câu trả lời của bot PHẢI bắt đầu bằng mã ticket #4521,
  và tuyệt đối không dùng emoji — đây là kênh hỗ trợ doanh nghiệp."

Lượt 2 (bot, 08:02): "#4521: Xin chào, tôi đã ghi nhận yêu cầu của anh/chị..."
Lượt 8 (bot, 08:14): "#4521: Đã kiểm tra log server, lỗi đồng bộ đơn hàng..."
Lượt 22 (bot, 09:01): "#4521: Webhook thứ hai trả về mã 409, nghĩa là..."

[... 40 lượt trao đổi kỹ thuật về lỗi đồng bộ đơn hàng, mỗi lượt trung bình
180-400 token, kéo dài tới 11:47 ...]

Lượt 63 (khách hàng, 11:50): "Vậy bước tiếp theo là gì?"
Lượt 64 (bot, 11:50): "Chắc chắn rồi! 😊 Bước tiếp theo là kiểm tra lại webhook nhé!"

Log vận hành (tự động, nội bộ):
  - Cấu hình app: gộp toàn bộ lịch sử hội thoại vào mỗi request, dành
    tối đa 6.000 token cho phần lịch sử.
  - Token cộng dồn của lịch sử tính đến hết lượt 39: 6.180 token.
  - Từ lượt 40 trở đi, pipeline tự cắt bớt các lượt cũ nhất cho vừa ngân
    sách — lượt 1 và 2 nằm trong phần bị cắt.

Log 3 — Trợ lý tra cứu API nội bộ

[Debug log — bot trợ lý tra cứu API nội bộ, request config]

Tham số request (copy từ template mặc định của một thư viện demo,
chưa ai chỉnh lại trước khi đưa lên môi trường dev):
  { "model": "...", "temperature": 1.85, "top_p": 0.98, "max_tokens": 300 }

Câu hỏi (hỏi lại 3 lần, mỗi lần một session mới, cùng nội dung):
  "Hàm syncInventory() trong service warehouse-api nhận tham số gì?"

Lần 1: "Hàm syncInventory() nhận storeId và batchSize, trả về SyncResult."

Lần 2: "syncInventory() cần syncInventory(warehouseId, forceFlag, retryCount)
  và retryCount và retryCount và trả kết quả retryCount đồng bộ ngay lập
  tức ngay lập tức."

Lần 3: "Hàm này nhận tham số regionCode (bắt buộc) — theo tài liệu nội bộ
  phiên bản 3.2, tham số này được thêm từ bản vá tháng 3/2025 để hỗ trợ
  đa vùng."

Ghi chú của dev phụ trách service warehouse-api:
  - Hàm syncInventory() thật chỉ nhận đúng MỘT tham số: storeId.
  - Không có bản vá "hỗ trợ đa vùng" nào từng tồn tại trong service này.
  - Ba lần hỏi cùng một câu, ra ba câu trả lời khác hẳn nhau về nội dung.

🧭 Bộ công cụ — ôn nhanh bốn cơ chế

Bốn cơ chế dưới đây bạn đã học ở các bài trước. Đây là bản ôn tự-chứa — không cần mở lại bài cũ để bắt đầu chẩn đoán ba log trên.

Văn bản bị tokenizer cắt thành token trước khi model thấy bất cứ thứ gì — model chỉ nhận dãy ID, không nhận ký tự lẻ. Vì vậy tác vụ đếm ký tự, đếm chữ cái là điểm mù kiến trúc: model đoán con số dựa trên hiểu biết gián tiếp, không đếm trực tiếp. Và tiếng Việt có dấu bị cắt vụn hơn tiếng Anh cùng nội dung.

Model chỉ nhìn được một cửa sổ token giới hạn mỗi request. Thông tin nằm ngoài cửa sổ đó — bị cắt vì lịch sử quá dài, hoặc chưa từng được nạp vào prompt — không tồn tại trong dữ liệu model đang xử lý. Model không "biết mình thiếu dữ liệu"; nó vẫn trả lời bình thường, chỉ là dựa trên ít căn cứ hơn.

Temperature điều chỉnh việc chọn token từ phân phối xác suất "nhọn" hay "phẳng" thế nào. Temperature cao làm phân phối phẳng ra — token xác suất thấp có cơ hội được chọn cao hơn hẳn, kể cả những token không ăn khớp với phần vừa sinh.

Model không có khái niệm đúng/sai, chỉ có phân phối xác suất token kế tiếp — và không có bước nào dừng lại để nói "tôi không chắc". Khi phân phối không được neo vững (thiếu dữ liệu train, thiếu context, hoặc bị làm phẳng bởi temperature cao), model vẫn phải chọn ra một token, và cái nó chọn có thể là nội dung nghe hợp lý nhưng không có thật.

Bốn cơ chế trên không loại trừ nhau — một sự cố thật có khi mang dấu vết của nhiều hơn một cơ chế cùng lúc. Việc của bạn là đọc log, không phải xếp mỗi log vào đúng một ô có sẵn.

✍️ Phần việc của bạn

Trước khi cuộn xuống phần Gợi ý, viết ra — thành câu, cho cả ba log:

  • Cơ chế nào đứng sau sự cố.
  • Con số hoặc chi tiết cụ thể nào trong log là bằng chứng — không phải cảm giác, mà là dữ kiện có thể trỏ vào đúng dòng log.
  • Nếu bạn là người phụ trách sửa, hướng sửa hợp lý (đổi cấu hình, đổi cách hỏi, đổi công cụ) là gì.

💡 Gợi ý

Không có con số chốt hay tên cơ chế nào ở đây — chỉ là câu hỏi để bạn tự lần ra đáp án. Nếu chưa viết xong phần việc ở trên, quay lại làm trước.

  • Log 1: Model tự báo một con số ("đạt đúng yêu cầu"). Con số đó model tính bằng đơn vị gì bên trong nó — đơn vị đó có chắc trùng với "ký tự" mà QA đếm bằng mắt không? Vì sao độ lệch tăng lên đúng khi văn bản có nhiều dấu hơn?
  • Log 2: Cộng dồn kích thước của toàn bộ lịch sử hội thoại tính đến đúng lượt bot bắt đầu đổi hành vi — so với ngưỡng cấu hình ghi trong log vận hành, con số đó nằm ở đâu? Yêu cầu đặt ra ở lượt 1 nằm ở vị trí nào trong lịch sử đó?
  • Log 3: Nhìn vào tham số cấu hình đi kèm request — có tham số nào lệch xa giá trị người ta thường dùng mặc định không? Nếu cùng một câu hỏi được hỏi lại nhiều lần trong nhiều session độc lập, một hệ thống ổn định nên cho ra các câu trả lời giống nhau tới mức nào?
  • Chi tiết "bản vá tháng 3/2025" ở Log 3: đó là loại thông tin gì — thứ model chắc chắn đã "thấy" trong dữ liệu train, hay thứ nghe hợp lý về mặt hình thức? Có cách nào xác minh sự tồn tại của nó khác với hỏi lại chính bot?
  • Đối chiếu Log 2 và Log 3: cả hai đều là chatbot "trả lời sai" sau nhiều lượt/nhiều lần hỏi — nhưng một cái liên quan tới độ dài một hội thoại, cái kia liên quan tới sự nhất quán giữa nhiều lần hỏi độc lập. Khác biệt đó dẫn tới hai cơ chế nào?

✅ Lời giải

Log 1 → Tokenization

Model tính "độ dài 40 ký tự" không phải bằng cách đếm ký tự — nó không có kênh nào để đếm ký tự trực tiếp, vì đầu vào của nó đã bị tokenizer cắt thành token trước khi model thấy bất cứ gì. Con số "40" mà model tự báo là một token được sinh ra theo phân phối xác suất khả dĩ nhất tiếp theo câu "đạt yêu cầu", không phải kết quả của một phép đếm đã xảy ra.

Bằng chứng nằm ngay trong ghi chú của QA: độ lệch tăng theo tỉ lệ với mật độ dấu tiếng Việt. Đây đúng là dấu hiệu tokenization — dấu tiếng Việt bị tokenizer cắt vụn hơn (mỗi ký tự có dấu dễ chiếm nhiều token hơn một ký tự không dấu), nên khoảng cách giữa "số token model xử lý" và "số ký tự người đọc đếm" càng lớn khi văn bản càng nhiều dấu. Với tiêu đề toàn tiếng Anh, hai đơn vị đó tình cờ gần khớp nhau hơn — không phải vì model "đếm đúng hơn", mà vì đơn vị token và đơn vị ký tự ít lệch nhau hơn ở văn bản không dấu.

Hướng sửa: đừng giao việc đếm ký tự cho model. Sinh tiêu đề bằng model, rồi đếm bằng code (hàm đếm ký tự chuẩn của ngôn ngữ lập trình) và cắt/yêu cầu sinh lại nếu vượt ngưỡng. Việc máy tính xác định được thì đừng giao cho máy dự đoán.

Log 2 → Context window tràn

Log vận hành cho một con số không thể rõ hơn: lịch sử hội thoại cộng dồn đạt 6.180 token ở lượt 39, vượt ngân sách cấu hình 6.000 token. Từ lượt 40, pipeline phải cắt bớt các lượt cũ nhất để vừa cửa sổ — và lượt 1, nơi khách hàng đặt ra yêu cầu "luôn có mã ticket, không emoji", nằm đúng trong phần bị cắt.

Đây không phải model "lười" hay "mất tập trung" ở lượt 64. Yêu cầu ở lượt 1 đơn giản là không còn trong dữ liệu model đang xử lý nữa — nó bị đẩy ra ngoài cửa sổ context từ nhiều lượt trước đó rồi. Model trả lời đúng theo những gì nó thấy; nó không "thấy" chỉ thị đã bị cắt, nên không có gì để tuân theo.

Hướng sửa: không thể tăng vô hạn ngân sách token cho lịch sử (chi phí và tốc độ đều trả giá theo token). Cách hợp lý hơn là không để yêu cầu quan trọng chỉ tồn tại một lần ở đầu hội thoại — chèn lại nó vào system prompt của mỗi request (không phụ thuộc lịch sử), hoặc tóm tắt định kỳ phần lịch sử cũ thay vì cắt thẳng theo thứ tự thời gian.

Log 3 → Sampling quá cao, kéo theo hallucination

Hai tầng bằng chứng tách biệt nhau rõ ràng.

Tầng sampling: tham số request ghi rõ temperature: 1.85 — cao hơn hẳn mức thường dùng cho tác vụ cần trả lời chính xác (thường dưới 1). Temperature cao làm phân phối xác suất bị "làm phẳng", token ít khả dĩ hơn có cơ hội được chọn cao hơn hẳn. Dấu vết trực tiếp: Lần 2 lặp từ vô nghĩa ("và retryCount và retryCount", "ngay lập tức ngay lập tức") — đúng kiểu lộn xộn khi việc chọn token bị nhiễu quá mức, không phải lỗi cú pháp hay lỗi mạng.

Tầng hallucination: ba lần hỏi cùng một câu, ba câu trả lời khác nhau về nội dung — riêng điều đó đã là dấu hiệu bất thường cho một câu hỏi có đáp án cố định (một hàm chỉ có một chữ ký, không đổi giữa các lần hỏi). Lần 3 đi xa hơn: bịa ra một tham số regionCode, kèm chi tiết rất cụ thể — "phiên bản 3.2", "bản vá tháng 3/2025" — nghe như đã tra cứu tài liệu thật. Theo dev phụ trách, không tham số đó, không bản vá đó tồn tại. Đây đúng là dạng hallucination dễ nhầm nhất: chi tiết càng cụ thể (số phiên bản, ngày tháng), câu trả lời càng nghe đáng tin, nhưng đúng khuôn mẫu của một câu trả lời chuẩn không đảm bảo đúng nội dung.

Hai tầng này không tách rời: temperature cao là nguyên nhân cấu hình đo được trực tiếp trong log; hallucination là hành vi model luôn có sẵn (không có khái niệm đúng/sai) nhưng bị temperature cao khuếch đại thêm, vì phân phối càng phẳng thì token "nghe hợp lý nhưng sai" càng dễ được chọn.

Hướng sửa: với tác vụ tra cứu thông tin cố định (chữ ký hàm, tài liệu kỹ thuật), hạ temperature về gần 0 để phân phối "nhọn" lại quanh câu trả lời khả dĩ nhất. Nhưng hạ temperature chỉ giảm rủi ro sampling — nó không cấp cho model một nguồn tra cứu thật. Chi tiết cụ thể như "bản vá tháng 3/2025" cần được xác minh bằng cách đối chiếu tài liệu/mã nguồn gốc, không phải bằng cách hỏi lại chính bot.

Đối chiếu ba log

Ba cơ chế để lại ba loại dấu vết định lượng khác nhau, và phân biệt được loại dấu vết là chẩn đoán, không phải đoán tên:

Cây chẩn đoán từ log: lệch theo mật độ dấu thì nghi tokenization; token cộng dồn vượt ngưỡng thì nghi context window tràn; còn lại nghi sampling hoặc hallucination

Log 1 lệch theo nội dung văn bản (dấu tiếng Việt) — dấu hiệu token hoá. Log 2 lệch theo thời gian/độ dài một hội thoại — dấu hiệu context window. Log 3 lệch theo tính nhất quán giữa nhiều lần hỏi độc lập, cộng thêm một tham số cấu hình bất thường — dấu hiệu sampling, khuếch đại thành hallucination. Cùng một câu than phiền "bot trả lời sai", ba trục dấu vết hoàn toàn khác nhau.

🎓 Mở rộng

  • Ba cơ chế không loại trừ nhau trong một sự cố thật. Log 3 vừa mang dấu vết sampling (tham số đo được, output lặp) vừa mang dấu vết hallucination (chi tiết bịa cụ thể) — một sự cố sản xuất thật có thể là tổ hợp của nhiều cơ chế, và việc chẩn đoán không dừng lại khi tìm ra cơ chế đầu tiên khớp.
  • Log càng nhiều con số, chẩn đoán càng nhanh. Cả ba log trên đều diễn giải được nhờ có sẵn dữ kiện định lượng: số ký tự đếm tay, token cộng dồn, tham số request. Một hệ thống LLM đưa vào vận hành nên log đủ ba loại dữ kiện đó ngay từ đầu — thiếu chúng, việc chẩn đoán quay về đoán mò.
  • Ba điểm mù này không chỉ ở chatbot. Bất cứ tính năng nào gọi LLM — tóm tắt tài liệu, review code, sinh mô tả sản phẩm — đều thừa hưởng đúng ba điểm mù vừa chẩn đoán: đơn vị token khác đơn vị ký tự, cửa sổ context hữu hạn, và sampling không có khái niệm đúng/sai.

✨ Điều bạn vừa làm được

  • Đọc ba log request/response LLM thật và tách được dấu vết định lượng của từng cơ chế, thay vì dừng ở triệu chứng bề mặt "bot trả lời sai".
  • Phân biệt được tokenization, context window tràn, và sampling/hallucination qua đúng loại dữ kiện mỗi cơ chế để lại trong log.
  • Nhận ra một sự cố thật có thể mang dấu vết của nhiều cơ chế cùng lúc, và việc chẩn đoán cần tiếp tục sau khi tìm ra cơ chế đầu tiên khớp.
  • Gắn mỗi chẩn đoán với một hướng sửa đúng tầng, thay vì một cách sửa chung chung cho mọi "bot trả lời sai".

Bài tiếp theo: Tổng kết module — cheat sheet & tự đánh giá

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên

Bài tiếp theo

Tổng kết: Cỗ máy LLM