電商翻車實錄:AI 代理人接管 WooCommerce 訂單通知,差點引發退貨海嘯的 37 天救援指南
☰ 目錄 table-of-contents.md
讓 AI Agent 判斷「要不要發訂單通知」,而不是只負責「通知的文案與語氣」,是電商自動化最危險的一條線。WooCommerce 的高頻 Hook 觸發,疊上 n8n 的雙重保險(Webhook + Polling),極容易演變成同一筆訂單被連發數十封確認信、差點掀起退貨海嘯的災難。這篇用 37 天救援實錄,拆解判斷權該怎麼從 AI 手上收回來。
本文用一次真實的線上事故(一家日訂單約 3,000 筆的電商,有客人一小時內收到 23 封「訂單已確認」)拆解三個核心問題:為什麼會重複觸發、為什麼緊急關閉後業務也跟著停擺、以及最後如何用「冪等鎖(Idempotency Lock)」把決策權交回系統。如果你正打算在電商流程導入 AI 自動化,這篇能幫你避開最痛的幾個坑。
事故全貌:三個禮拜串接,一個早上引爆
那天下午三點,我坐在浪花科技的辦公室盯著螢幕,看著監控儀表板上綠油油的狀態,心裡只有一個念頭:「這次應該沒問題了吧?」
上個月,我們團隊剛花了整整三個禮拜,把 n8n、AI Agent 和 WooCommerce 的訂單通知系統全部串接起來。測試環境跑得順順的,Staging 階段也沒有出現任何 Error Log,就這樣懷著一種工程師特有的「說不清楚的自信」,我把它推上了正式環境。
這是一家日訂單量穩定在 3,000 筆左右的中大型電商。當初的系統設計初衷非常豐滿:我們希望利用 AI Agent 分析客戶的購買歷史,在訂單成立與出貨時,自動生成「帶有溫度的客製化通知信」,讓原本冷冰冰的系統通知變成一場極致的消費者體驗。
結果隔天早上剛泡好咖啡,客戶的客服就拿著手機衝進來,臉色鐵青地問我:「為什麼有客人說,他一個小時內收到了二十三封『訂單已確認』的 Email?還有人以為我們被駭客攻擊,氣到要退貨!」
看著客服信箱裡雪片般飛來的客訴,我知道,一場長達 37 天的血淚救援行動正式開始了。
第一個坑:AI 判斷邏輯為什麼在高頻觸發下完全失控?
問題的根源其實不是程式碼寫錯了(工程師最後的倔強),而是 AI Agent 把 WooCommerce 的 Hook 觸發時機,誤當成自己該做決策的「業務事件」。
WooCommerce 的訂單事件,本來就會被重複呼叫
在 WooCommerce 的底層設計中,woocommerce_order_status_changed 或針對 post_meta 的更新,往往會因為外掛(例如發票模組、物流外掛)的介入,在短時間內被重複呼叫多次。這是它的設計常態,而不是 bug——一筆訂單從成立到出貨,本來就會經過多次狀態變更與 meta 寫入。
關鍵在於:每次訂單只要有任何一個 Meta 欄位被更新,AI Agent 就會收到 Webhook,然後它那聰明的小腦袋瓜一轉,覺得:「哇!這是一個需要通知客戶的新事件!」它無法分辨「這是同一筆訂單在同一個狀態下的第 N 次寫入」,於是把每一次寫入都當成一個全新的、值得通知的事件。
雙重保險,反而變成「通知地獄」
再加上我們當初為了確保通知不漏接,在 n8n 裡設定了 Webhook 搭配 Polling(輪詢)的雙重保險機制。立意是好的——萬一 Webhook 漏接,輪詢還能補上。但在高併發的流量衝擊下,這兩條路徑同時觸發,就變成了完美的災難。同一個事件,會從多個來源各自觸發一次:
- Webhook 觸發:物流外掛更新了追蹤碼,觸發一次。
- 金流回傳:綠界回傳付款成功,又觸發一次。
- n8n 輪詢:AI 發現狀態是 processing,再發一次。
每一條觸發路徑彼此都不知道對方已經發過信。看著 Log 視窗像瀑布一樣一行一行跑出來,每一行都是一封寄出去的信,那種看著系統發瘋卻不知道從哪裡下手的焦慮感,真的會讓工程師折壽。你以為的聰明,在高併發下只是個瘋狂的打字機。
核心教訓:「不漏接」與「不重複」是兩個獨立的問題。多加一條保險路徑能解決前者,卻會直接惡化後者——除非你在路徑匯流的地方做了去重(去重的工具,就是後面要講的冪等鎖)。
第二個坑:緊急關掉自動化之後,為什麼手動也回不去了?
當下第一直覺當然是「拔掉插頭」。我們在事發兩小時內緊急把 n8n 上的 AI Agent 通知節點關閉。但最可怕的事情不是系統壞掉,而是你把它關掉之後,才發現整個業務流程已經完全依賴它了。
拔掉插頭後,訂單確認信完全停止發送。因為當初為了導入 AI 通知,我們把 WooCommerce 原生的 Email 觸發給 Hook 掉了。結果備份不夠完整,那些原本靠人工設定的發信條件、過濾規則,全都找不回來。
這就是典型的「自動化單點依賴」:一個本來只是「加值」的功能,因為攔截了原生機制,悄悄變成了整條流程的唯一出口。一旦它倒下,沒有任何後備路徑可以承接。
那令人崩潰的 37 天救援三階段
- 第一階段:肉身止血(第 1-5 天)。客服團隊只能從後台匯出名單,用 BCC 密件副本手動寄發出貨通知。那幾天,業主開會時看我的眼神,充滿了「你之前說這個 AI 系統很穩」的無聲質問。
- 第二階段:重塑資料流(第 6-15 天)。我們開始在測試主機上瘋狂復現問題,釐清 n8n 的 Log 紀錄,揪出到底是哪個外掛的更新觸發了死亡迴圈。
- 第三階段:架構重構(第 16-37 天)。徹底放棄讓 AI 當「業務主管」,將系統解耦,重新設計狀態機(State Machine)。
那種被客戶指著鼻子問「是不是資料外洩」的尷尬瞬間,讓我深刻體會到,技術再新潮,一旦脫離了容錯機制,就是一場災難。
第三個坑與重生:如何讓「裁判權」回歸系統?
在重建架構的時候,我們做了一個非常關鍵的決定:AI Agent 不再負責判斷「要不要發通知」,它只負責決定「通知的內容和語氣」。
這個區分看似微小,卻是整套架構的轉折點。判斷「要不要觸發動作」屬於業務邏輯,必須是可預測、可重現、不可出錯的;而「觸發後的文案優化」才是 AI 真正擅長、也容許一定彈性的地方。我們把這兩件事徹底分開。
我們將觸發的判斷權交回給 WooCommerce 結合後端的 Laravel 中介層,加上了一層程式碼級別的「冪等性鎖(Idempotency Lock)」。簡單來說,就是確保同一個訂單在同一個狀態下,絕對只能被處理一次。
先搞懂:什麼是冪等性(Idempotency)?
冪等性是一個系統架構概念,意思是無論你執行同一個操作一次還是多次,最終的結果都必須一樣。在訂單通知的情境中,理想狀態是:「針對訂單 A、狀態為 processing 寄出確認信」這個操作,不管被呼叫一次還是一百次,客戶最終都只會收到一封信。
要達成這件事,你需要兩樣東西:一個能唯一辨識「這個事件」的鍵(key),以及一個能記住「這個鍵已經處理過」的儲存空間。在 WooCommerce/WordPress 的世界裡,最直接的儲存空間就是 Transient API。
經典的防禦機制:冪等鎖(Idempotency Lock)實作邏輯
即使使用經典的 WordPress 架構,你也能透過 Transient API 加上簡單的鎖定機制來防禦這種高頻誤觸:
// 在 WooCommerce hook 中加入防連發機制
$order_id = $order->get_id();
$status = $order->get_status();
$lock_key = 'ai_notify_lock_' . $order_id . '_' . $status;
// 檢查是否已經鎖定
if ( get_transient( $lock_key ) ) {
error_log('攔截重複的訂單通知觸發: Order ID ' . $order_id);
return; // 已經發送過或正在發送中,直接中斷
}
// 設定一把 60 秒的鎖
set_transient( $lock_key, true, 60 );
// 接下來才呼叫 n8n 的 Webhook 交給 AI 處理文案...
這段程式碼的精髓,全在 $lock_key 的設計上:它同時綁定了「訂單編號」與「當下狀態」。這代表同一筆訂單在同一個狀態下的重複觸發,會被這把鎖擋下;但當訂單真的從 processing 進到 completed(一個新的、合理的狀態),鎖的鍵也會跟著改變,新的通知就能正常放行。換句話說,它擋的是「重複」,不是「所有後續事件」。
關於這把鎖,有幾個實務上要想清楚的點
- 鎖的存活時間(TTL)要對齊去重窗口:上例設 60 秒,意思是「同一訂單同一狀態,60 秒內只處理一次」。窗口太短擋不住瀑布式的連發,太長則可能誤擋掉合理的重送,需依實際觸發頻率調整。
- 檢查與寫入之間仍有極小的競爭空隙:「先 get 再 set」這種寫法在極端高併發下,理論上仍可能有兩個請求同時通過檢查。若要更嚴謹,可考慮使用具備原子性的鎖定手段(例如資料庫層的唯一索引或具備原子操作的快取),這也是本文最後延伸閱讀中「競爭條件」一文要解決的問題。
- 鎖只是「去重」,不負責「重試」:它確保不重複發送,但若真正的發信流程失敗了,去重鎖不會幫你補發。可靠的重送要靠 n8n 端的錯誤處理與重試機制來搭配。
重生後的乾淨流程
現在的流程變得很乾淨:
- WooCommerce 訂單狀態改變。
- 系統(Laravel 中介層)檢查冪等鎖。
- 確認放行後才呼叫 n8n。
- AI 根據客戶歷史購買行為生成專屬推薦文案。
- 送出信件。
AI 只做最後一哩路的包裝,再也無法干涉業務邏輯的觸發權。觸發與否由系統的狀態機決定,AI 只在被允許之後,負責讓那封信讀起來有溫度。
三十七天之後,我學到的三件血淚教訓
歷經這 37 天的搶修與系統重構,喝了無數杯濃縮咖啡之後,我把這次事件當作職涯的重要養分。如果你也打算把 AI Agent 引入電商流程,請務必把這三件事刻在心裡。
1. 永遠要準備好「降級方案」(Fallback Plan)
自動化系統上線前,你要先想清楚:如果它今天突然全部死機,業務能不能活下去?這不是要工程師悲觀,而是你必須有一個乾淨的一鍵切換機制。當 AI 秀逗時,能不能一秒切回原生的 WooCommerce 通知?如果不行,千萬別上線。我們最大的錯誤,就是把原生機制 Hook 掉之後,沒有保留一條能立刻復原的回頭路。
2. 慎選 AI 代理人的「決策節點」
AI Agent 放在哪個決策點,比它用哪一個模型還重要。讓 AI 負責判斷「要不要觸發動作」,跟讓 AI 負責「觸發後的文案優化」,完全是兩種不同維度的風險。AI 有幻覺,不要把攸關營運命脈的 Switch 交給會產生幻覺的大腦——把不可出錯的判斷留給可預測的程式碼,把需要創意的包裝交給 AI。
3. Log 是你事後重建現場的唯一救命稻草
很多工程師不喜歡看 Log,覺得那是佔空間的垃圾。但這次如果不是 n8n 完整的執行紀錄(Execution Logs)還在,我根本不知道第一個出錯的迴圈是由哪個外掛引發的。完善你的日誌記錄,出事時它就是你的黑盒子。
回想那個因為被狂發信而暴怒的下午,現在雖然可以笑著說出來,但當下真的是頭皮發麻。你呢?你在導入 AI 自動化的路上,有踩過什麼讓你半夜驚醒的地雷嗎?
如果你現在的 WooCommerce 系統也面臨自動化轉型的陣痛,或者你的 AI 工作流總是時不時卡頓罷工,別再讓系統「憑感覺」運作了。浪花科技具備豐富的系統重構與自動化容錯設計經驗,歡迎前往 浪花科技聯繫表單 填寫需求,讓我們的資深工程團隊幫你把脈,把風險降到最低!
延伸閱讀
常見問題
為什麼 WooCommerce 訂單通知會在 n8n 與 AI 串接後重複發送數十封?
如何用冪等鎖(Idempotency Lock)防止訂單通知重複發送?
為什麼緊急關閉 AI 自動化後,連手動發信也回不去了?
AI Agent 在訂單通知系統裡到底該負責什麼?
冪等鎖能取代重試機制嗎?
訂閱免費電子報
把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。