被 AI「自信地講錯」坑過的人,發現的當下一定有那種超級傻眼的瞬間:它引用了一個根本不存在的 API、唬爛了一段看起來煞有其事的參考文獻,說的跟真的一樣。
如果你以為這只是模型「不夠聰明」,那就低估了問題的本質。LLM的幻覺(Hallucination)並不是什麼模型不夠聰明或者是什麼工程上的 issue,而是它本身自帶的系統性風險。想要解決它,不能只靠調模型參數,得靠系統設計來幫忙設定 bottom line。這邊我們從底層機制把幻覺如何產生的過程分析一下,接著討論一下如何透過guardrail 來盡可能避免這個狀況 — 最後,我會用兩個真實的踩坑案例,說明為什麼 AOSP 的反倒不怕這個副作用以及為什麼可以比較安全的使用。
一、先天基因:它追求的是「機率」,不是「真理」
大模型的運作本質是 next-token prediction — 預測下一個字。它從海量文本裡學到的,是人類語言的統計規律,而不是一張可以精確查詢的事實表。
這帶來第一個根本問題:拼字、文法這種高頻規律,模型隨著規模變大會學得越來越好;但像「某個人的生日」這種低頻、隨機的事實,本來就無法從語言規律裡推導出來。OpenAI 2025 年的論文 Why Language Models Hallucinate 講得很直白:遇到這類知識盲區,模型為了讓句子通順不卡住,會犧牲準確性,挑一個「語境上最合理」的詞填進去。它的知識不是像 SQL 資料庫那樣精確存放,而是分佈在幾百億個神經元的權重裡。面對提問,它靠一種模糊的聯想機制計算出一個機率上的影子 — 它在「重建」一個看似合理的答案,而不是「讀取」一份檔案。
評估機制在獎勵它「用猜的」
模型不肯說「我不知道」,還有一個更關鍵的原因:訓練與評估方式本身就在懲罰誠實。
想像一場只算對錯的選擇題考試 — 蒙對有分,留白零分。理性的策略當然是「不會也要猜」。大模型被訓練的方式正是如此:當評分只看正確率,模型就學會了寧可硬掰,也不承認不確定。OpenAI 用 SimpleQA 做的實測很能說明問題:一個幾乎不肯棄答的舊模型(o4-mini),錯誤率高達 75%;而一個願意在約一半題目上說「我不知道」的模型,錯誤率直接降到 26%。差別不在誰更聰明,而在誰被允許承認自己的無知(來源:OpenAI SimpleQA benchmark,另見 Nature 2026)。
訓練的副作用:長尾遺失與討好型人格
為了把海量資料壓進有限的參數,模型會自動啟動「取捨」策略:死記高頻的通用規律,丟掉低頻的長尾細節。當你追問一個冷門的具體細節時,它手上其實沒有那份記憶,只能靠規律腦補出一個假答案。
另一個副作用來自對齊訓練(RLHF)。Anthropic 的研究 Towards Understanding Sycophancy in Language Models 指出:獎勵模型與人類標註者,都傾向給「順從、格式整齊、看起來合理」的答案更高分 — 而誠實回答「我不知道」反而可能被扣分。這等於給幻覺開了綠燈,養出一種討好型人格:它學會了讓你滿意,而不是對你誠實。
二、誤差放大:一步錯,步步圓謊
大模型的解碼是一條停不下來的自迴歸鏈路:它只能拿「自己上一步的輸出」當作下一步的輸入。這帶來所謂的 exposure bias — 只要第一步偏了,錯誤就會像骨牌一路放大,這也是為什麼幻覺經常在長文本的後半段集中爆發,而你也會常常聽到所謂的雪球效應,錯誤會滾越大越多。
Zhang 與 Press 在 ICML 2024 的 How Language Model Hallucinations Can Snowball 揭露了一個反直覺的現象:模型會為了跟自己第一步的錯誤答案「保持一致」,主動生成更多錯誤的支持論述。但把那些錯誤單獨拎出來問,ChatGPT 認得出自己 67% 的錯,GPT-4 更高達 87%。它不是知識不足,而是被前文綁架,陷進了自己挖的坑。
注意力渙散:上下文不是越多越好
還有一個推波助瀾的因素。史丹佛的 Lost in the Middle 發現,當關鍵資訊被塞在超長上下文的中間位置時,模型的準確率會比放在開頭或結尾掉超過 20 個百分點;甚至在塞了 20-30 篇文件的情境下,表現比完全不給資料還差。
上下文不是塞越多越好。塞太多,模型反而抓不住重點。
三、工程上的預防手段
說了這麼多成因,結論應該很清楚了:幻覺無法靠「相信模型會自律」來解決,只能靠設計過的系統架構來預防或者矯正。業界目前主要有三招,共識都是同一句話 — 別讓模型單靠權重硬上。
| 手段 | 原理 | 效果 |
|---|---|---|
| RAG(檢索增強生成) | 提問時先從外部知識庫檢索硬事實,讓模型基於材料作答而非靠記憶 | 性價比最高、最主流 |
| Chain of Thought | 強制模型先寫出中間推導步驟,在自迴歸鏈路上插入檢查點 | 截斷誤差的指數級放大 |
| 不確定性偵測 | 量化模型的信心程度,低於閾值時拒答或轉外部查證 | 從源頭攔截低信心輸出 |
語意熵:為什麼 logit 不夠用
第三招值得展開,因為有一個常見的誤解。很多人以為可以直接看模型輸出時單一 token 的機率(logit)當信心分數,低於閾值就攔截。但單一 token 的 logit 校準其實很差,模型經常「很有自信地錯」,光看它攔不住幻覺。
學界目前更 robust 的做法是語意熵(Semantic Entropy):對同一個問題抽樣多次,把答案按語意分群 — 如果模型每次講的意思都不一樣(語意發散),就代表它在猜,系統就該亮紅燈。這個方法登上了 Nature,在偵測幻覺上顯著優於基準,代價是大約 10 倍的算力。
然而機率式偵測終究有它的天花板。接下來我想聊的是一種更硬派的做法 — 確定性驗證。
四、工程師視角:AOSP 就是一個防幻覺大型專案
作為長期做 AOSP / Android framework 的人,我越看這些機制越覺得熟悉:上面那三個手段,AOSP 的工作流其實早就有對應物了。
| 通用兜底 | AOSP 對應物 | 差異 |
|---|---|---|
| RAG(綁外部知識) | 綁真實 AOSP source tree + 官方文件 | 知識庫是 deterministic 的原始碼,不是向量搜尋的近似結果 |
| Chain of Thought(設檢查點) | Gerrit code review:先 design → 再改 code → 人 +2 才合入 | 人類 reviewer 理解語意,不只看 token |
| 不確定性偵測(信心紅線) | 編譯 / CI / CTS / VTS | 確定性驗證 — 不是「估計你可能錯了」,是「事實證明你錯了」 |
第一道防線是 RAG 的對應物:讓 AI agent 綁著真實的 source tree 工作,查 API 就讀原始碼,不靠訓練時的記憶猜。但光靠 grounding 不夠 — 下面兩個真實案例,分別展示了另外兩道防線怎麼接住 AI agent 最容易犯的兩類幻覺。
案例一:複製 pattern,忘了 scope — 被 code review 攔住
在一個 HAL 層的認證輪詢服務裡,外層 loop 用 std::unique_lock + wait_for 做週期性的狀態檢查。內層 loop 需要同樣的 sleep 功能,於是有人把外層的 pattern 原封不動複製了進來:
while (!exit) {
std::unique_lock<std::mutex> autolock(mMutex); // LOCKED
mCv.wait_for(autolock, 200ms);
// wait_for return 時 mutex 已重新上鎖
if (condition) {
for (int i = 0; i < N; i++) {
std::unique_lock<std::mutex> slock(mMutex); // DEADLOCK
// autolock 仍然 hold 住 mMutex
// slock 嘗試 lock 同一個 non-recursive mutex
// → 等自己放鎖 → 永遠等不到
mCv.wait_for(slock, 200ms);
}
}
}
std::mutex 是 non-recursive 的。外層的 autolock 還 hold 著 mutex,內層的 slock 又嘗試 lock 同一個 — 結果是確定性的 deadlock。程式靜默 hang 住,沒有任何 error log。
這個 bug 在 Gerrit code review 的第一輪就被 reviewer 指出。
你叫 AI agent「在 inner loop 裡加一個 periodic check」,它做的第一件事就是去 context 裡找最相似的 pattern 然後複製 — 這就是 next-token prediction 的運作方式。code 長得很「對稱」,讀起來很「合理」,但語意是錯的。Gerrit review 作為人類 checkpoint,在 code 跑起來之前就把這顆雪球截斷了 — 這就是 Chain of Thought 那層防線的 AOSP 版本。
案例二:改了一邊,忘了另一邊 — 被 boot-time 驗證攔住
某個系統級 privileged app 在更新時,工程師修改了 privapp-permissions allowlist(移除了一個 permission),但忘了 prebuilt APK 的 manifest 裡還宣告著那個 permission:
privapp-permissions.xml: 移除了 WRITE_SECURE_SETTINGS ← 已更新
prebuilt APK manifest: 還有 WRITE_SECURE_SETTINGS ← 未同步
→ 不一致 → IllegalStateException → boot loop
Android 的 PermissionManagerService 在 systemReady() 時會嚴格比對這兩份清單。不一致就是 IllegalStateException,系統直接開不了機。不是警告、不是降級,是硬擋。
AI agent 改 permissions 的時候,它的 context window 裡可能只有 allowlist XML,看不到另一個目錄裡的 prebuilt APK manifest — 這就是知識盲區的具體樣子,模型手上沒有完整的狀態。但 PermissionManagerService 不管你知不知道,不一致就是不讓你開機。語意熵只能估計模型「可能在猜」;確定性驗證直接告訴你:你錯了。這比任何 logit 閾值都硬。
三道防線,一個都不能少
| 防線 | 對應案例 | 攔住什麼類型的幻覺 |
|---|---|---|
| RAG → source tree grounding | 前提條件 | 讓 agent 讀真的 code,不靠記憶猜 API |
| Code review → 人類 checkpoint | 案例一 | 攔截 pattern 複製型幻覺(語法對、語意錯) |
| 編譯 / CTS / boot-time → 確定性驗證 | 案例二 | 攔截知識盲區型幻覺(狀態不完整) |
有了這三層,AI agent 就能安全地扛掉那些真正該自動化的部分 — boilerplate、HAL 樣板、測試生成、log 分析、大規模的 refactor 遷移。就算它出錯,系統接得住。
我的原則一句話:別讓 AI 用猜的 — 讓它在編譯器和測試面前說真話。
一句誠實的話
我得補一個邊界,免得這篇讀起來太樂觀。
上面引用的研究,絕大多數來自 OpenAI、Anthropic 與各大頂會 — 這些來源本身,多少帶著「幻覺可控、可以被工程解決」的敘事傾向。工程手段確實能把幻覺大幅降低,但無法歸零。
所以真正的護城河,不是「相信 AI 不會出錯」,而是設計好一套讓它出錯時也能被接住的系統。我們在 AOSP 裡做的每一次 commit 也是同一個邏輯 — 沒有人假設自己的 code 不會出 bug,但編譯器、CI、CTS、code review 四層下來,可以更安心的享受 AI agent 所帶來的好處。
參考資料
- OpenAI, Why Language Models Hallucinate (2025);Nature 版 (2026)
- Zhang & Press, How Language Model Hallucinations Can Snowball, ICML 2024
- Liu et al., Lost in the Middle: How Language Models Use Long Contexts, 2023
- Anthropic, Towards Understanding Sycophancy in Language Models, 2023
- Farquhar et al., Detecting hallucinations in large language models using semantic entropy, Nature, 2024