01 · Agent Ops · AI agent 維運

一個「自癒」外掛,怎麼把我的 AI agent 改到開不了機

服務一切正常,磁碟上的核心檔卻已經壞了。一次 AI agent 平台的事故排查:從十幾個外掛同時報錯,到抓出那個號稱會自動修復的元兇。

3 min read#事故排查#postmortem#AI agent

TL;DR

一個標榜「失敗時自動降級、自動修補」的社群外掛,在背景把 agent 平台的核心 JS 覆寫成語法錯誤的版本。服務當下照常運作——因為舊程式碼早已載入記憶體——但下一次重啟就起不來。教訓:「服務正常」與「磁碟上的東西正常」是兩件事,基線檢查要兩個都驗。

背景:把 agent 當成一個服務在養

我用一套開源的 AI coding agent 平台當日常工作台:它有 Web 介面、能裝外掛、能排程、能讀寫檔案。用久了,外掛越裝越多——反向代理、手機版介面、記憶、用量統計、檔案上傳……高峰期 profile 裡有 24 個 bundle。

外掛多了以後,穩定性自然變差。所以當我看到社群有一個 fail-soft 外掛,宣稱能在某個外掛載入失敗時自動隔離它、還能「自癒核心補丁」,聽起來正是我需要的保險。

裝了。然後某天重啟,整個服務起不來。

症狀:十幾個不相干的外掛,同一秒一起壞

日誌裡最醒目的是這一段:fail-soft 在同一秒內連續隔離了一大串外掛,錯誤訊息全部一樣:

failed to apply loader entry include (cordis:include): loader entries failed to apply

受影響的包括反向代理、session 管理、圖片顯示、檔案上傳、手機導覽、自動化排程……彼此毫無關係。

第一直覺是「是不是哪次升級把這些外掛弄壞了」,然後開始一個一個查。這是錯的方向。

十幾個互不相關的元件,在同一秒出現同一個錯誤——問題幾乎不可能在這十幾個元件裡,而是在它們共用的那一層。

這一層就是外掛載入器(loader),以及它所在的平台核心檔。

關鍵發現:服務明明在跑,核心檔卻是壞的

修好啟動後,我做了一件之前沒做過的事:直接對平台核心 JS 檔跑語法檢查。

node --check profile-boot-*.js
# SyntaxError: missing ) after argument list

核心檔有語法錯誤。但服務剛剛還好好的在跑——怎麼可能?

答案是時間差:

  1. 服務啟動,正確的核心程式碼被載入記憶體。
  2. fail-soft 的背景「自癒」程序觸發,用它自帶的模板覆寫磁碟上的核心檔。
  3. 服務繼續正常運作——它跑的是記憶體裡的舊版本。HTTP 檢查全部綠燈。
  4. Node 讀到磁碟上壞掉的檔案,loader 炸掉,所有外掛被一起「隔離」。

證據鏈很直接:

  • fail-soft 的日誌記錄了它在某個時間點「自動修復並寫入」核心檔。
  • 磁碟上的核心檔,與 fail-soft 自帶的 .patched 模板雜湊完全相同。
  • 兩者都有同一個語法錯誤:某個 callback 結尾少了正確的 });。
  • 移除 fail-soft、從官方同版本套件還原核心檔後,語法檢查通過,重啟正常。

也就是說,它自帶的修補模板本身就是壞的。它每次「自癒」,都是在把一個好檔案換成壞檔案。

為什麼這種故障特別陰險

200當時 HTTP 健康檢查的結果

✗磁碟上核心檔的語法檢查

10+同一秒被「隔離」的無辜外掛

  1. 監控看不到。一般的健康檢查只問「服務有沒有回應」,而它確實有回應。
  2. 爆發點遠離原因。壞掉的動作發生在重啟之前的某個背景時間點;你在重啟時看到的錯誤,指向的是十幾個不相干的外掛。
  3. 保護機制放大了傷害。fail-soft 看到外掛載入失敗,就把它們隔離——於是「核心檔壞了」這個單一原因,被包裝成「十幾個外掛壞了」的假象。
  4. 它會再犯。只要外掛還在,你修好核心檔,它下一輪背景任務又會改回去。

修復與之後的做法

修復本身很簡單:從 profile 移除外掛、清掉 lockfile 裡的參照、把它的持久化開關設成關閉、從官方套件還原核心檔。真正花時間的是確認「不會再發生」。

我把這次的教訓收進一個唯讀的基線檢查腳本,每天早上由排程自動跑:

  • 各服務的 HTTP 回應(服務層:有沒有活著)。
  • profile 的 bundle 數量、有沒有被標成 disabled(設定層:有沒有被偷改)。
  • 那個外掛是否仍未安裝、開關是否仍為關閉(已知風險:有沒有回來)。
  • 平台核心 JS 的 node --check(磁碟層:下次重啟起不起得來)。
  • 磁碟與記憶體餘量。

最後一項是這次新增的,也是最重要的:它檢查的不是「現在好不好」,而是「下次重啟會不會好」。

帶走的三件事

  1. 同時壞很多個,就去找它們共用的那一層。 不要逐個修。
  2. 健康檢查要分層:服務活著 ≠ 設定正確 ≠ 磁碟上的程式碼能啟動。只檢查第一層,等於只在重啟那一刻才發現問題。
  3. 對「會自動修改核心檔」的東西保持懷疑。 自動修復本身也是程式碼,也會有 bug,而且它的 bug 會以「修復」的名義寫進你的系統。裝之前先問:它改了什麼、改之前有沒有備份、改完有沒有驗證。

我的規則現在是:任何外掛或腳本要改動平台核心檔,一律拒絕;外掛安裝一律加 --ignore-scripts、固定版本;改 profile 之前先備份、改完先跑基線。

不浪漫,但至少下一次出事時,我會先知道「重啟起不起得來」。

寫於 2026.10.09。內容是個人實作紀錄,數字與做法請以你的環境驗證。想追後續,可以用 RSS 訂閱。