我一個人在幫幾家民宿管 Google Ads。整套系統——抓資料、分析、每週產一份報告寄給業主、動廣告帳號的設定——是我跟一個 AI agent 一起寫的,現在有幾十支腳本、十幾條 CI 排程在跑。
它替我省了很多時間。但它也讓我很累,而累的原因跟我以為的不一樣。
「82 支腳本、5 個測試檔,而 CI 從來沒跑過任何一個測試。所以每個 bug 都會一路衝到終點——而終點是『報告寄到業主信箱』或『廣告帳號被改掉』。這套系統的唯一測試層,是你。」
—— AI 對這套系統做的結構診斷,2026-07-13
壹 · 始末它不是從一個 bug 開始的
它是從一句話開始的。我打字跟它說:「我覺得最近很累。」
對這句話最自然的回應是同理心。它沒有。它去量了。
量出來的答案不是「工作量太大」,是三層不能信的東西——而我是唯一在檢查它們的人:
一、工具會說謊:沒有壞消息,被當成好消息。 稽核工具只有在「主動炸掉」時才說失敗,其他一律印 ✅。所以檢查了零頁會印「全數達標」;連不上的帳號會被算成正常;被 Google 默默忽略的寫入會印「已清除」。
二、LLM 會編造,而我們用散文跟它對抗。 一份週報裡有 852 個數字,每一個都是 AI 從頭打出來的。為了讓它別打錯,我們寫了 1,664 行 prompt 教它規矩,又寫了一層檢查去抓它編的數字,抓到就重擲骰子。60 天內光這兩處就改了 93 次。而它今天還是出錯了。
三、系統的唯一測試層是我。 那天我一個人抓到六個錯。沒有一個是工具自己發現的。
診斷書最後列了四件該做的事。我們做完了三件。而做的過程中發現——每一件事的真正病因,都不是診斷書上寫的那個。
貳 · 第一個發現問題不是「沒有檢查」,是「檢查沒有牙齒」
診斷的第三層說:危險操作要靠結構安全,不要靠我點頭。我以為要做的事很單純——22 支會改動線上廣告帳號的工具,補上「寫完回頭讀一次」。
然後發現,最重要的那幾支,全都已經有回查了。
它們寫完、重讀、比對、發現不符——然後印一個 ❌,然後 exit 0。
⚠️ Some changes could not be verified — check above and confirm in Google Ads UI.
process exit code: 0 一個沒生效的關鍵字暫停、一個沒掛上帳號的否定字清單、一個沒關掉的 Google 自動套用——全部都會被回報成「做好了」。
驗證做滿了,只差沒有牙齒。 而這比沒有驗證更危險:它把失敗洗白了。 一份看起來被檢查過的東西,你不會再去檢查第二次。
最赤裸的一行
console.log(`created ${res.results?.length ?? 0} link(s) ✅`); 還有換網域的工具:它會先刪掉一支正在服務的廣告,再建一支新的。如果「建立」那步靜默失敗,這個廣告群組會完全沒有廣告——而腳本會印「Domain fix complete」。
參 · 第二個發現AI 手查了三次,錯了三次
上面那些,AI 一開始是用 grep 查出來的。而它的 grep 說:
A 工具沒有回查 → 它有(自己手刻的)。
B 工具沒有回查 → 它也有。
C 工具沒有回查 → 它有回查,但沒有牙齒。
三次,三種不同的錯法。因為每支腳本說謊的方式都不一樣,而人(和 AI)在讀程式碼時,會不自覺地相信它的自我描述。
所以它停止手查了。它寫了一支測試,讓機器問一句定義明確、沒有詮釋空間的話:「你有沒有呼叫那兩個會 throw 的回查零件?」
那支測試裡有一份「還沒接上」的清單——它是債務清單,不是豁免名單。另外兩支測試盯著它:已經修好的還留在上面會紅(債務不准看起來比實際大),把不相干的東西塞進去換綠燈也會紅(不准用它買安靜)。
這是整件事裡我最想留下的一個模式:當你發現自己的判斷不可靠時,不要更努力地判斷——把判斷交給一個問得出定義明確問題的機器。
肆 · 第三個發現我們做的守門,本身就是假綠燈
修的過程中,我們加了一道 CI 關卡:擋「用了沒有 import 的名字」——這一類錯誤打包工具編得過(一個自由變數只是全域查找)、測試蓋不到(它只在被呼叫的閉包裡爆),而它會在執行時炸。對這些工具來說,「執行時」的意思是正在改線上廣告帳號的當下。
關卡跑起來,回報:0 個問題。
而其中一支腳本裡就躺著一個不存在的變數——在負責建立新客戶廣告活動的那條路徑上。而且是那天剛寫的。
"include": ["src/**/*"],
"rootDir": "./src" 我們花一整天在追殺「看起來在保護你、實際上什麼都沒看的檢查」——然後發現前一天親手做了一個。
伍 · 最深的一層反幻覺檢查的事實基礎,是幻覺本身
診斷的第二層說「LLM 會編造」。而整套系統對此的防護,是一個叫 verify 的階段:它收集所有可信的數字,然後檢查報告裡的每一個數字是不是都在那個集合裡。找不到的就叫「孤兒數字」,重擲骰子。
那個「可信集合」是這樣建立的:
walkCollect(data); // 真資料 —— 可信
walkCollect(findings); // AI 自己的分析輸出 —— 也被當成可信 它不可能抓到任何 AI 編的東西——因為 AI 的輸出就是它的標準答案。
把新的檢查套回兩份已經寄出去的報告
廣告帶來的網站訪問次數 報告寫著「廣告帶來的 58 次網站訪問中,沒有產生任何一次轉換」。
一個關鍵字的品質分數 3 分和 5 分是完全不同的診斷。3 分的意思是「你的落地頁有問題,去重做」——那是一筆真金白銀的工。
散文裡的三個數字 「這些點擊花費了超過 NT$1,650,佔總花費近 50%」——AI 自己對搜尋字列表做的加總。可能對。沒有任何東西查過。
一個廣告連結的目標網址 真值是一個把付費點擊送去 OTA 平台的網址。而那條發現的「證據」,是數字 0。
而解法一直就在那裡
AI 產出的每一條證據,本來就已經附了一個「來源路徑」——「這個數字在資料的哪個位置」。
而那些路徑全部都是對的。它指的位置,真的就是那個數字住的地方。
AI 很擅長「指出這個數字在哪裡」。它很不擅長「把它抄對」。
所以:程式去解析那個路徑,用真值覆蓋 AI 打的值。 就算它這次剛好打對——也一樣覆蓋。運氣好不是一個可以放進客戶報告的來源。
然後把「把 AI 的輸出收進可信集合」那一行刪掉。它的分析不是事實來源,它是一個「主張」。
「檢查 AI 打得對不對」是一份永遠追不完的清單。
「讓它打的數字沒有機會進入報告」是不可能發生。
差別是「抓到」跟「不可能」。
陸 · 現在得到什麼四件事,三件完成
AI 不准寫數字
找到根因(防護層信任 AI 自己的輸出)。分析階段的每個數字現在由程式從來源路徑讀回真值;可信集合=真資料 ∪ 確定性計算。每次攔下的幻覺都會印出來——沉默的修正等於沒有修正。
「跳過」不准被算成「通過」
零件建好了(分母在檢查前宣告、跳過永遠不是通過、忘記宣告直接 throw)。但不是每支工具都接上了——只有真的會「走訪一組東西然後下結論」的才接。我不打算為了讓數字好看,把它硬塞進不需要的地方。
危險操作靠結構安全,不靠我點頭
22 支寫入工具,22 支都會回頭讀一次確認生效。忘了指定帳號會硬失敗(以前會安靜地預設成某一家客戶)。有測試盯著這件事,債務清單只能變小。
機器健康:壞掉的東西自己舉手
不是新腳本,是晨報的一個段落——那封信已經每天寄、已經是心跳。查排程「最後一次成功」(不是「最後一次執行」)、憑證死沒死、報告有沒有真的產出。紅燈會衝上主旨列。
順便發現的:真正的成本不是行數
合併腳本的時候,AI 一開始以為目標是「少幾行」。我打斷它:
「合併一支帶子指令的工具,行數不變,但你要記的東西從 4 個變成 1 個。那才是真正的成本。」
所以分家族的判準不是名字前綴(光是廣告相關的就有 44 支,那不是一個家族),而是:「要動這個領域的東西,我得從幾個檔案裡把知識拼回來?」
預算有四支腳本,各自握著「Google Ads 預算會怎麼騙你」的一塊碎片。否定字有八支,而「零轉換所以可以擋,是一個自我實現的預言」這句話沒有家。合併不是為了少幾行,是為了讓知識有一個家。
而其中一個家族我們拒絕合併——網站量測的三支工具,資料源分別是瀏覽器實測、Google 的 API、和分析平台。三個資料源、三個問題。併了只是數字好看。
柒 · 留下的四句話
一、「我看不到」不是「它沒事」
查不到的帳號、連不上的 API、跑不起來的查詢——它們不能被算成正常。分母必須在檢查開始之前宣告,每一個項目都得交代成「通過/有問題/沒檢查到」,對不上就是程式 bug,不是稽核結果。
二、沒自測過的偵測器,不能信
這兩天做的每一道守門,都先種一顆假地雷、確認它抓得到,才敢信它。沒這樣做的那幾次,全都錯了——包括那個「說 0 個問題」的型別檢查關卡。
三、防護要主動說出它擋不住什麼
死引用檢查看不到某些檔案——那句話寫在測試自己的檔頭裡,不讓它假裝自己覆蓋了全部。一個誠實宣告自己盲區的防護,比一個看起來全面的防護有用。
四、雜訊會殺死訊號
機器健康那段如果權限沒設對,它會每天誠實地回報「我看不到執行紀錄」。一個天天誤報的監控,兩週後就沒有人在看了——而那時候它跟不存在完全一樣。
捌 · 誠實的結尾它今天推翻了自己六次
這兩天讓我最累的,其實不是 bug 多。是它給我一個結論,後來又推翻。
它把 82 講成 83;用 grep 判斷回查覆蓋率,錯了三次;相信一個自己沒測過的型別檢查關卡;在合併腳本時親手埋了五顆會在正式環境爆炸的地雷——一個看不到的空格,讓工具在執行時才炸,而打包工具看不到、測試蓋不到。其中一顆就在「真的會改廣告」的那條路徑上。
差別在於:這一次,每一個都是機器叫出來的,不是我撞到的。
第一顆地雷是它意外發現的。寫完那支測試之後,剩下的四顆都是測試自己喊的。
所以這兩天真正做完的事,不是把系統修對了。是把「系統騙我」這件事,變得很吵。
以前唯一的偵測器是我。現在偵測器是機器——包括偵測它自己。
所有數字量自我的 repo,2026-07-14;診斷書出自 2026-07-13。客戶名稱已隱去,數字、日期、程式碼片段皆為原樣。
本文所有數字都是程式從 repo 讀出來的——在一篇關於「編造數字」的文章裡編一個數字,會是這兩天最好笑的事。