閱讀約 3 分鐘瀏覽 9 次systems

當結束碼開始說謊:一個響了七天沒人聽懂的警報

🎧 收聽這篇5:47

一個人在燈下專注端詳一根羽毛,身後陰影裡停著一整車堆得極高的柴,近到快碰到他的背,而他毫無所覺

自動化系統的靜默故障:工具答對了卻回報失敗、警報每天都響卻喊錯名字。一次除錯的完整推理過程,以及三個可以直接拿去查自己系統的檢查項。

  • automation
  • debugging
  • reliability
目錄
  1. 三個訊號,三種說謊方式
  2. 真正的兇手,是一個「守規矩」的動作
  3. 七天沒人發現,因為警報喊錯了名字
  4. 最難看的一段:我自己的腳本也在說謊
  5. 你怎麼知道你的自動化還活著
  6. 三個可以今天就去查的東西
  7. 帶得走的一件事

一個人在燈下專注端詳一根羽毛,身後陰影裡停著一整車堆得極高的柴,近到快碰到他的背,而他毫無所覺

明足以察秋毫之末,而不見輿薪。 —— 《孟子・梁惠王上》(約公元前 300 年)

我叫一個 AI 命令列工具回答一個字。它回了 PONG,完全正確。

然後它告訴我,它失敗了。

三個訊號,三種說謊方式

那天我在查一件小事:為什麼派給 grok 的工作老是很慢。我寫了一支計時的小程式,同一句話跑七次,記錄兩個時間點——答案什麼時候出現,程序什麼時候結束。

七次的答案全對。但那兩個時間點之間的落差,是這樣的:

次數答案出現程序結束
1131 秒十分鐘上限,我砍的
2102 秒十分鐘上限,我砍的
3549 秒十分鐘上限,我砍的

答案一分半到兩分鐘就寫進輸出了。然後程序就掛在那裡發呆,直到被我殺掉。

七次裡有兩次自己結束了。其中一次回報成功,另一次回報失敗——而那次「失敗」的答案,跟其他六次一模一樣,都是正確的 PONG。

所以三個我平常拿來判斷「做完沒」的訊號,全部不可靠:程序活著不代表還在工作,程序死了不代表工作完成,回報失敗不代表答案是錯的。

真正的兇手,是一個「守規矩」的動作

我另一支腳本會明確指定要用哪個模型。這是我自己訂的規矩——排程一定要釘死模型版本,這樣供應商偷偷換掉模型的時候才看得出來。

我把這個參數拿掉試了一次,一百四十秒就答完了。加回去,三百秒零輸出。

換一個模型名試?一樣卡死。換成它自己的預設模型呢——就是那個你什麼都不寫它就會用的那個?

也卡死。

同一個模型,你不講它會用,你講出來它就死。而且錯誤訊息是空的:沒有警告、沒有說參數不對、沒有任何一個字。它就是停在「收到你的問題」那一步,不動了。

這個參數是我因為守紀律才加的。不加的人沒事,加的人全死。

七天沒人發現,因為警報喊錯了名字

我去翻那支腳本的日報,四十三天份。

它從八月十四號開始出現空跑,中間好了一天,然後從八月十七號到八月二十一號連續五天,每一格都是空的。

警報有響嗎?有。而且七天每天都響。

問題在它喊的內容。那行字寫的是「偵測到模型漂移」——這句話的意思是「AI 的回答變了,去查一下會不會影響結論」。

實際情況是「一個字都沒收到,工具壞了」。

前者要去查判斷,後者要去修管線。兩件完全不同的事,共用同一個詞。所以每天看到那行警報的人,都不會想到要去看是不是連線都沒通。

警報有響,但沒有人聽得懂它在說什麼。這跟沒響的差別很小。

最難看的一段:我自己的腳本也在說謊

修到後面,我派了一個任務出去,順手看了一眼結果:

✅ 完成 902s,產出 162 位元組

打勾,完成,有產出。看起來很好。

但那個任務其實徹底失敗了。162 位元組的內容是這樣一句話:「我會先找一條可用的管道,然後只試那一條。」

一句開場白。它講完這句就卡住了,七分鐘沒動,跑滿逾時被砍。

我自己寫的驗收邏輯是「只要產出超過門檻就算成功」,門檻是一個位元組。所以一句開場白足以讓一個徹底失敗的任務被標成完成。

而且那行字裡其實有證據——「完成 902s」後面那個空括號,本來應該填「完成原因」,只有正常收工才會有值。逾時被砍的時候那裡是空的。

證據就在畫面上,但沒有人會去盯一個空括號。

你怎麼知道你的自動化還活著

我想講的是那個形狀。

上面三件事——明確指定版本、等程序結束、看回傳碼——每一件單獨拿出來看都是好習慣,是教科書會教你做的事。它們同時也是這次故障的入口。

而它們有一個共同點:失敗的時候不會叫。

系統壞掉的時候長得跟正常一樣。你每天看著綠燈,綠燈是真的亮著,只是它量的是程序有沒有結束、產出過不過門檻,不是答案對不對。

所以該問「這個警報有沒有可能永遠不響」。

三個可以今天就去查的東西

第一,找出你所有「連續亮了五天以上」的警報。天天亮的警報等於沒有警報——它要嘛是壞的,要嘛已經被你的眼睛自動略過。兩種情況都要處理。

第二,去看你的報表產生器裡,有沒有把「讀不到」寫成 0 的地方。程式碼裡那種「找不到就給預設值」的寫法,就是「一個字都沒收到」被讀成「這個值是零」的入口。這正是我那個「模型漂移」遮住「工具沒回應」的同一種病。

第三,故意讓你的工具逾時一次,看它會不會回報成功。這件事只要五分鐘,而且結果通常很難看。我就是這樣發現自己的腳本在說謊的。

帶得走的一件事

我自己是因為那個空括號才不再相信綠燈——它亮著是真的,只是它量的東西早就跟我關心的事情脫鉤了。寫完這篇之後,我看每一個從來沒紅過的檢查,第一個念頭都變成:它有沒有可能永遠不會紅。

我試過一個很小的做法,你要的話可以試試:今天挑一個你最放心的檢查——從來沒出過事的那種,月結對帳、每週報表、某個健康檢查的打勾都行。回頭翻它最近一次亮綠燈的那天,找出它實際看的是哪一個數字或哪一個檔案,把那樣東西寫在紙上,旁邊再寫你真正想知道的是什麼。兩行一對,不是同一件事的話,那顆綠燈就從來沒替你看過門。我第一次做的時候,對上的是「產出大於一位元組」和「任務有沒有做完」,兩行差得很遠,而那顆綠燈已經亮了兩年。

留言

載入留言中…

送出前需用 Google 登入,只顯示你的名字與頭像