jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

AI Hallucination — Tại sao LLM "bịa" và 6 tầng phòng thủ cho dev

Vì sao hallucination là bản chất của next-token prediction chứ không phải bug: 4 cơ chế, taxonomy 6 dạng dev gặp, mô hình phòng thủ Swiss-cheese 6 tầng, vụ thật (luật sư, Air Canada, slopsquatting), và cân phòng thủ theo rủi ro.

Có một sự thật khó chịu bạn phải nắm trước khi giao việc cho LLM mỗi ngày: model không biết khi nào nó đang sai. Nó nói câu bịa với đúng giọng tự tin như câu đúng. Con người còn có cảm giác “cái này mình không chắc”; LLM thì không.

Đó là hallucination. Và đây là điểm mấu chốt của cả bài: nó không phải bug của ChatGPT, Claude hay Gemini sẽ được “fix ở version sau”. Nó là hệ quả toán học tất yếu của cách mọi LLM hiện tại vận hành. Hiểu được vì sao, bạn sẽ ngừng chờ phép màu và bắt đầu xây hàng rào.

Ý tưởng lớn nhất: LLM không phải cỗ máy tra cứu sự thật. Nó là cỗ máy đoán chuỗi token có khả năng nhất. “Đúng sự thật” chỉ là tác dụng phụ thường gặp, không phải mục tiêu thiết kế. Khi không có dữ liệu, nó vẫn đoán — và một câu bịa trôi chảy luôn “có khả năng” hơn một câu “tôi không biết”.


1. Hallucination là gì — định nghĩa chính xác

Hallucination = output nghe hợp lý nhưng không có căn cứ trong training data hoặc trong context bạn cung cấp.

Từ khoá là “hợp lý” (plausible). Output bịa không phải chữ ngẫu nhiên vô nghĩa — nó trông đúng đến mức bạn dễ không nhận ra:

// Hỏi: 'list user từ Supabase, limit 10, mới nhất trước'
const { data } = await supabase
  .from('users')
  .select('*')
  .limit(10)
  .orderBy('created_at', 'desc'); // ← Supabase KHÔNG có method này

Method đúng là .order('created_at', { ascending: false }). Model trộn syntax từ Prisma/Mongoose/SQL vì tất cả “nghe giống ORM”. Code đẹp, TypeScript loose vẫn pass, runtime mới nổ.

Ẩn dụ: hallucination giống một diễn viên ứng tác (improv) không bao giờ thoát vai. Bạn đưa tình huống nào, anh ta cũng diễn tiếp trơn tru, đầy tự tin — kể cả khi anh ta chẳng biết gì về chủ đề. Mục tiêu của anh ta là “giữ mạch diễn”, không phải “nói đúng”.

Hiểu lầm thường gặp: “model bịa vì nó kém / chưa đủ thông minh”. Sai. Ngay cả model giỏi nhất cũng bịa, vì bịa không đến từ thiếu năng lực mà từ chính cơ chế next-token (Phần 2). Model giỏi hơn chỉ bịa ít thường xuyên hơntinh vi hơn — đôi khi nguy hiểm hơn.


2. Vì sao hallucination là điều bắt buộc phải xảy ra

Nghe cực đoan, nhưng đúng về mặt cơ chế. Mọi LLM chạy theo một vòng lặp duy nhất (xem Tokenization & Sampling):

Input:  chuỗi token đã có


Model:  tính phân phối xác suất p(token kế tiếp | context)
   │     — MỌI token trong từ điển đều có xác suất > 0

Chọn:   token xác suất cao nhất (hoặc sample từ phân phối)


Lặp lại cho token tiếp theo

Đọc kỹ dòng “mọi token đều có xác suất > 0”. Nó kéo theo ba hệ quả:

  • Không có “token bị cấm” — không tồn tại cơ chế chặn cứng theo logic.
  • Model không suy luận “câu này không thể chứa từ X”. Nó chỉ biết pattern từ training.
  • Khi gặp câu hỏi nó chưa từng thấy dữ liệu, nó không im lặng — nó đắp pattern gần nhất.

Ví dụ kinh điển:

Hỏi: "Signature của hook useDeepMemo trong React 19 là gì?"

useDeepMemo không tồn tại. Nhưng model đã thấy hàng triệu ví dụ useMemo(() => value, deps). Pattern đó cực mạnh → nó dựng ra một signature “kiểu useMemo” mang tên useDeepMemo. Xác suất của output trôi chảy này cao hơn xác suất của “Tôi không biết”.

Vì sao “I don’t know” lại khó: muốn model biết từ chối, phải dạy nó nhận diện và chấp nhận sự bất định (calibration, abstention learning) — một trong những bài toán khó nhất của AI hiện tại. Có tiến bộ, nhưng còn xa hoàn hảo.

Kết luận của phần này: còn next-token prediction, còn hallucination. Nó là feature của kiến trúc, không phải bug của sản phẩm.


3. Bốn cơ chế gây hallucination phổ biến

Hiểu cơ chế giúp bạn đoán trước khi nào rủi ro tăng vọt.

3.1. Knowledge cutoff — dữ liệu training có hạn dùng

Library/framework ra sau ngày cutoff → model buộc phải đoán.

  • React 19 (12/2024), Astro 5 đổi content collections, Next.js App Router đổi 3 lần trong 18 tháng.
  • Ecosystem càng “nhanh”, rủi ro càng cao.

Ẩn dụ: như hỏi đường một người vừa rời thành phố 2 năm trước. Họ trả lời tự tin theo bản đồ cũ — và dẫn bạn vào con đường giờ đã thành công trường.

3.2. Pattern bleeding — trộn lẫn các framework giống nhau

# Hỏi Django query → model trộn với SQLAlchemy/Prisma
qs = User.objects.where(age__gt=18).order_by('name').limit(10)
# Django đúng: .filter(...), và phải slice [:10] thay cho .limit(10)

3.3. Confabulation dưới áp lực — “muốn giúp” hơn “biết thật”

Bạn: "Code này có bug? [paste]"
AI:  "Có, dòng 5 thiếu null check."   ← đoán theo pattern phổ biến
Bạn: "Sửa rồi vẫn lỗi."
AI:  "À, có thể do dòng 12..."         ← đoán tiếp, không dựa hiểu biết thật

Mỗi lần bạn nói “vẫn lỗi”, model dựng giả thuyết mới — không phải vì nó hiểu nguyên nhân, mà vì nó phải nói gì đó.

3.4. Context corruption — “lost in the middle”

[100KB đầu context: convention dự án, "không dùng axios"]
...
[câu hỏi cuối: "gọi API thế nào?"]
→ AI: const res = await axios.get('/api/...')   ← đi ngược convention

Không phải AI cố tình. Nó bỏ sót thông tin nằm giữa context dài — một hiện tượng có nghiên cứu chính thức (“Lost in the Middle”).


4. Taxonomy — 6 dạng hallucination dev gặp hằng ngày

DạngMô tảVí dụ
1. Method/API không tồn tạiTên nghe đúng, thật thì khácarray.shuffle(), el.getTextContent()
2. Import sai chỗPackage/path hợp lý nhưng saiimport { useDebounce } from 'react'
3. Config option bịaNghe kỹ thuật, không có trong schema"strictOptionalProperties": "safe"
4. Type signature saiSố/loại tham số/trả về saiconst [s, set, reset] = useState(0)
5. Behavior sai (nguy hiểm nhất)Code chạy nhưng hành vi ngầm saiArray.sort() không mutate” (sai — nó mutate)
6. URL/reference ảoLink đúng format, 404 khi clickreact.dev/reference/hooks/useDeepMemo

Dạng 5 đáng sợ nhất vì nó không crash. Code chạy, test sơ sài pass, nhưng mental model của bạn bị nhiễm độc — và bug lan sang chỗ khác. Type-check không bắt được; chỉ test hành vi mới bắt (Phần 5).


5. Mô hình phòng thủ 6 tầng — “Swiss cheese”

Không một tầng nào bắt hết hallucination. Triết lý đúng là mô hình phô mai Thuỵ Sĩ (Swiss cheese model, James Reason — vốn dùng trong an toàn hàng không và y tế): mỗi tầng là một lát phô mai có lỗ; xếp nhiều lát lại thì lỗ hiếm khi thẳng hàng, nên lỗi khó xuyên qua hết.

                      ┌──────────────┐
                      │ 6. Human     │  Review PR/commit; "tribal context"
                      │    review    │
                  ┌───┴──────────────┴───┐
                  │ 5. Observability     │  Feature flag, canary, Sentry
              ┌───┴──────────────────────┴───┐
              │ 4. Integration + E2E         │  Chạy thật → bắt config/URL/DB sai
          ┌───┴──────────────────────────────┴───┐
          │ 3. Unit test                         │  Bắt behavior sai (Dạng 5)
      ┌───┴──────────────────────────────────────┴───┐
      │ 2. Lint + static analysis                    │  Import/style/unused
  ┌───┴──────────────────────────────────────────────┴───┐
  │ 1. Type-check (TypeScript strict, mypy...)           │  Method tồn tại? Signature đúng?
  └──────────────────────────────────────────────────────┘
       ↑ rẻ nhất, nhanh nhất, bắt được nhiều nhất — đặt lên đầu

Nguyên tắc xếp tầng: lỗi nên bị chặn ở tầng rẻ và sớm nhất có thể. Đừng để một method-không-tồn-tại lọt tới tận production rồi mới phát hiện qua Sentry.

TầngBắt được gìBỏ lọt gì
1. Type-checkMethod/signature/import sai (Dạng 1,2,4)Behavior sai, config runtime
2. LintImport thừa, any, @ts-ignore lénLogic
3. Unit testBehavior sai (Dạng 5)Tích hợp thật, config
4. Integration/E2EConfig bịa, URL 404, query sai (Dạng 3,6)Lỗi chỉ xảy ra ở scale/production
5. ObservabilityLỗi production, hồi quyLỗi “đúng kỹ thuật, sai ý đồ”
6. Human review”Tribal context” (quyết định team, data distribution)Cái con người cũng bỏ sót

Hai tầng đáng nhấn:

  • Tầng 1 — Type-check: bắt buộc strict mode + noUncheckedIndexedAccess + exactOptionalPropertyTypes. Không strict → any ngầm → AI bịa method mà TS im lặng.
  • Tầng 3 — Unit test cho behavior:
test('sortAsc trả về bản sao đã sắp, KHÔNG mutate input', () => {
  const original = [3, 1, 2];
  const sorted = sortAsc(original);
  expect(sorted).toEqual([1, 2, 3]);
  expect(original).toEqual([3, 1, 2]); // ← bắt đúng Dạng 5
});

6. Điều này đã gây thiệt hại thật ngoài đời

Hallucination không phải rủi ro lý thuyết. Vài vụ được ghi nhận công khai:

Vụ việcChuyện gì xảy raBài học
Mata v. Avianca (2023, New York)Luật sư nộp hồ sơ với các án lệ do ChatGPT bịa hoàn toàn; toà phát hiện và phạtOutput AI là giả thuyết, không phải nguồn dẫn
Air Canada chatbot (2024)Chatbot tự “chế” chính sách hoàn tiền; toà buộc hãng phải chịu trách nhiệmBạn chịu trách nhiệm cho cái AI nói thay bạn
Google Bard demo (2023)Trả lời sai về kính viễn vọng James Webb ngay trong video ra mắtSai tự tin xảy ra cả ở demo có chuẩn bị
Package hallucination / “slopsquatting”LLM gợi ý tên package npm/pip không tồn tại; kẻ xấu đăng ký đúng tên đó để cài malwareHallucination thành lỗ hổng supply-chain

Điểm rút ra cho dev: dạng nguy hiểm nhất không phải code crash — mà là output trôi chảy, đáng tin, và sai, được một con người mệt mỏi bấm “accept”.


7. Khi nào AI bịa ít hơn / nhiều hơn

AI ít hallucinate khi…AI dễ hallucinate khi…
Context cụ thể: attach file thật, dán docs, link ticketContext mơ hồ (“fix this”)
Có tool/MCP đọc docs real-time (vd Context7)Library mới/non-mainstream/internal
Dùng thinking model (bảo thủ hơn, dám nói “chưa chắc”)Task mở (“design architecture for…”)
Grounding qua RAG tốt → nhìn nguồn thậtHội thoại dài, không có vòng phản hồi/verify
Task định nghĩa rõ (“refactor theo 3 rule này”)Yêu cầu chung chung (“improve this code”)

Hai kỹ thuật ép AI tự soi lại

1. Self-verification (Socratic) — bắt AI xác thực chính output của nó:

"Soi lại đoạn trên. Xác nhận từng method/import có thật trong
 library X phiên bản Y.Z không. Nếu không chắc, ghi 'chưa chắc'."

Khoảng 60–70% trường hợp AI tự phát hiện và sửa — không phải vì nó “nhớ ra”, mà vì câu hỏi kích hoạt pattern kiểm tra thay vì pattern sinh code. Tốn ~5 giây, vài trăm token. Không phải thuốc tiên, nhưng là một lát phô mai miễn phí.

2. Chống “You’re absolutely right” — model hay đồng ý với giả thuyết sai của bạn vì nó được reward khi bạn vui:

Bạn: "Tôi nghĩ bug do useEffect chạy 2 lần trong strict mode."
AI:  "You're absolutely right!..."   ← có thể đang xuôi theo bạn

Cách chặn: đừng đưa kết luận sớm — chỉ mô tả triệu chứng. Khi AI đồng ý, thách thức: “Chứng minh bằng một test case reproduce đi.” Nếu không reproduce được → giả thuyết sai (dù cả hai đang gật gù). Đây là lý do minimal reproduction quan trọng: nó khách quan hoá tranh luận.


Key Takeaways

  • Hallucination là feature của kiến trúc, không phải bug. Next-token prediction luôn đoán, kể cả khi không có dữ liệu — không version nào “fix” hết được.
  • Output AI = giả thuyết, không phải sự thật. Verify trước khi commit. Sự tự tin của model nói lên độ trôi chảy, không phải độ đúng.
  • Dạng nguy hiểm nhất là “behavior sai” (Dạng 5): không crash, lọt type-check, đầu độc mental model. Chỉ test hành vi mới bắt được.
  • Phòng thủ theo mô hình Swiss cheese 6 tầng: type-check → lint → unit → integration/E2E → observability → human review. Lỗi nên bị chặn ở tầng sớm và rẻ nhất.
  • Context cụ thể giảm tần suất bịa ~10×. Mơ hồ + library mới = vùng rủi ro cao nhất.
  • Vụ thật đã có thiệt hại (luật sư bị phạt, Air Canada thua kiện, slopsquatting) — đây là rủi ro vận hành, không phải lý thuyết.

Common Mistakes

  • Tin vào giọng tự tin của AI. Tin test + type + review, không tin ngữ điệu.
  • “Accept all” mà không đọc từng dòng diff. Đây chính là lỗ để hallucination xuyên qua tầng cuối.
  • Tắt strict mode / xài any / @ts-ignore để “cho nó chạy” — tự tay khoét thủng tầng phòng thủ rẻ nhất.
  • Đưa giả thuyết sai rồi hỏi AI xác nhận → nhận về confabulation đồng thuận. Hãy mô tả triệu chứng, bắt AI tự đề xuất + chứng minh.
  • Tin URL/citation do AI tạo mà không click kiểm tra — chúng đúng format nhưng thường ảo.
  • Copy tên package AI gợi ý mà không kiểm tra trên registry — rủi ro slopsquatting.

When Should You Use This?

Câu hỏi đúng không phải “có dùng AI không” mà là “hàng rào dày bao nhiêu cho từng mức rủi ro”. Cân lượng phòng thủ theo mức nguy hiểm:

Mức rủi roLoại codePhòng thủ tối thiểu
🔴 Cực caoSecurity, crypto, authTest với test vector chuẩn (RFC) + security review người thật + audit trail. Không trust AI trực tiếp
🔴 CaoPayment, tính tiền, thuếUnit test biên (decimal, rounding) + human review bắt buộc
🟡 Trung bìnhLogic nghiệp vụ coreUnit + integration test, review bình thường
🟡 Thấp–TBHành vi UIE2E/component test
🟢 ThấpStyle, format, commentLint + type-check là đủ
  • Dùng AI thoải mái cho boilerplate, refactor có ràng buộc rõ, vùng có type + test mạnh.
  • Dùng AI thận trọng (verify nặng) cho security/payment, library mới, task mở, hoặc code không có test bao quanh.

Quick Start Guide

Bước đầu tiên để bắt đầu phòng thủ hôm nay:

  1. Bật tầng 1 (rẻ nhất, mạnh nhất) — siết TypeScript:
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}
  1. Thêm một verification prompt vào thói quen sau mỗi đoạn code AI sinh:
"Liệt kê mọi method, import, và config option bạn vừa dùng.
 Với từng cái, xác nhận nó có thật trong <library@version>.
 Cái nào không chắc, đánh dấu 'CẦN KIỂM TRA'."
  1. Viết test hành vi cho thứ AI tạo — đặc biệt với hàm có hành vi ngầm (mutate, async, edge case). Đây là lưới bắt Dạng 5.
  2. Không bao giờ “accept all” cho code rủi ro cao — đọc từng dòng diff; mang “tribal context” của team vào review.
  3. Đầu tư vào bộ kỹ năng verify — nó tăng giá trị theo thời gian: model mạnh hơn vẫn bịa (coverage gap, internal code, ngôn ngữ mơ hồ), chỉ là tinh vi hơn.

Dev làm việc tốt với AI không phải dev “tin AI nhiều hơn”. Ngược lại — họ hoài nghi có phương pháp hơn.


Đọc thêm trong series

Reference

  • Google Research — “Lost in the Middle” (arxiv.org/abs/2307.03172)
  • Mata v. Avianca, Inc. (S.D.N.Y. 2023) — chế tài cho citation bịa bởi ChatGPT
  • Moffatt v. Air Canada (BC Civil Resolution Tribunal, 2024) — trách nhiệm cho chatbot
  • Anthropic — Calibration & uncertainty papers
  • Cursor Learn (cursor.com/learn)