AI Agent例外處理錯誤重試BuildInPublic一人公司

錯誤重試怎麼分類:該退避的和該立刻收手的

· 8 分鐘閱讀
龍蝦艦隊 · 逐章稽核 · 第 13 / 22 篇
目錄
  1. 分類做對之前,我們踩過的坑
  2. 先花幾分鐘查你自己的錯誤處理
  3. 我們實際怎麼改
  4. 例外處理體檢清單
  5. 這一章的四句話

《Agentic Design Patterns》第 12 章講例外處理與復原。核心一句話:錯誤不是同一種東西,要先分類。只有暫時性(transient)的錯誤才值得退避重試,永久性的錯誤要當場收手。硬重試一個永遠不會好的錯,不是韌性,是把一次失敗放大成一場風暴。

我們讀完,點頭。我們的 gateway 早就重寫過 _openrouter_call,402、401 立刻收手不重試,只有 429 跟 5xx 才退避,退避還設了上限。例外處理,實作完成。然後我們對自己做了對抗式稽核,翻出兩件事:一次真的把 gateway 打進崩潰迴圈的事故,和一個告警重報 bug,同一個沒變的狀態,一天咬了我們 4 次。

分類做對之前,我們踩過的坑

最早那版 _openrouter_call 只發一發 curl,從不看回來的 HTTP status,於是把兩種完全不同的失敗混成一種:

限流跟 5xx 這種暫時錯,被當成「這個 model 掛了」,立刻跳去下一個 fallback model。而 fallback 鏈的下一個往往比較貴,一次瞬間的限流,就把你悄悄升級到貴的模型上。

沒額度的 402、key 錯的 401 這種帳號級永久錯,也一樣被整條 fallback 鏈重打一輪。問題是鏈上每個 model 用的是同一把 key、同一個餘額。model A 402,model B、C 一定也 402。對一個 402 重打整條鏈,是保證失敗的無意義風暴。

真正的事故就長在這裡。額度歸零那天,max_tokens 還掛著 65535,每個請求一送出去就被 402 打回。gateway 跑在 systemd 底下、設了自動重啟,於是崩潰、402、再崩潰、再被救活,一個永久錯在程式層也被當成可以重來的錯。這跟第 16 章是同一場崩潰迴圈,但那章算的是燒掉多少錢,這章要問的是:為什麼一個永遠不會成功的錯誤,會被系統一遍遍重試。答案是它從頭到尾沒被分類。

先花幾分鐘查你自己的錯誤處理

01 你有沒有真的分類錯誤,還是所有錯走同一條路 翻你呼叫 LLM 或外部 API 的那段,看它有沒有按 HTTP status 分流。該重試的(429、5xx、連線逾時)跟該立刻收手的(402、401、403)要走不同的路。最危險的是把 402 也丟進重試迴圈,那只會風暴。

# 你的錯誤處理有沒有讀 HTTP status 分流,還是一視同仁
grep -nE 'http_code|status|case .*in|402|401|429|50[0-9]' your-llm-call.sh

紅旗:整段只有一條錯誤路徑(統一重試、或統一換 model),從頭到尾沒讀過 status code。

02 retry 有沒有上限,次數和退避都要封頂 找你的重試迴圈,確認兩件事都有天花板:重試次數有上限,退避間隔也有上限。少一個,一次失敗就會自己滾成崩潰迴圈。

# 找重試迴圈:有沒有次數上限、退避有沒有封頂
grep -nE 'max_attempts|max_retries|backoff|sleep|while ' your-llm-call.sh

紅旗:while 迴圈沒有 attempt 計數器、backoff 一路 ×2 沒有上限、或根本靠 systemd 崩了就無腦重啟、中間沒有任何斷路器。

03 告警有沒有 dedup,狀態沒變就別重報 狀態沒變卻一直重報,不是監控,是洗版。看你的告警有沒有記住上一次的狀態,只在「從正常轉成故障」那一刻才發,故障持續期間頂多隔一段時間重複一次。

# 告警有沒有記狀態、只在轉態時發;數同一則一天響幾次
grep -nE 'state|stamp|last_fire|OFF|ON|轉態' your-alert.sh
grep -c 'crash-loop' ~/.openclaw/logs/tg-alert.log   # 同一問題一天幾筆

紅旗:同一個沒變的狀況,一天在 log 裡出現好幾次。我們那個重報 bug 就是一天咬 4 次。

我們實際怎麼改

_openrouter_call 現在拿到回應第一件事是看 http_code 分流。2xx 就正常回傳。401、402 判永久錯,記一筆 log、整條鏈當場收手,不重試也不換 model,因為換了一樣 402。429、500、502、503、504、還有連線逾時的 000,判暫時錯,對同一個 model 退避重試,間隔 1、2、4 秒,最多 3 次,打光了才放棄這個 model。其餘像 400、403、404 判 model 級錯誤,重試也一樣錯,不重試,直接讓上層換下一個 fallback。有界、退避、不風暴。

告警那邊補了遲滯(hysteresis)。每個條件寫一個 state stamp,只在正常轉故障那一刻推一次,故障持續期間最多每 60 分鐘重複一次,不再每 5 分鐘咬人一口。同一個崩潰迴圈,現在響一次,不是 4 次。

例外處理體檢清單

對你自己的系統跑一遍:

  • 錯誤處理有沒有先看 HTTP status 分類,還是所有錯走同一條路
  • 402、401 這種永久錯,是立刻收手,還是也跟著重試、換 model
  • 換 model 的 fallback,會不會把一個「整個帳號都會失敗」的錯放大成整條鏈的風暴
  • retry 有沒有上限,次數和退避間隔都封頂了嗎
  • 靠 systemd/PM2 自動重啟的服務,有沒有斷路器,還是崩了就無腦復活
  • 告警有沒有 dedup,狀態沒變就別重報,同一個問題一天響幾次

這一章的四句話

  • 錯誤不是同一種。先分類:transient 才退避重試,402、401 這種永久錯要立刻收手。
  • 對永久錯重試不是韌性,是風暴。同一把 key 的 402,換 model、重打鏈、重啟程式,結果都一樣。
  • 退避一定要有上限。次數、間隔都要封頂,不然一次失敗會自己滾成崩潰迴圈。
  • 告警要等狀態真的變了才發。狀態沒變就重報,那不是監控,是洗版。

原始碼位置:~/.openclaw/scripts/ollama-helper.sh_openrouter_call:401/402 永久錯立刻收手、429/5xx 暫時錯退避 1→2→4 秒上限 3 次、其餘 model 級錯不重試換下一個);告警 dedup 在 ~/.openclaw/scripts/lib/hard-alert-watchdog.sh(每個條件寫 state stamp,只在 OFF→ON 轉態時推,之後最多每 60 分鐘重複一次)。

這是《Agentic Design Patterns》× 龍蝦艦隊系列。我們照書把一人公司的 AI agent 艦隊系統化,然後對自己做對抗式稽核。宣稱做到的每一章,都被重新驗證過一次,也把查法和改法整理成你能照著跑的步驟。這個系列的可信度,來自我們願意公開自己打臉自己。

龍蝦艦隊 · 逐章稽核 · 第 13 / 22 篇

每週 AI 自動化實戰筆記

不廢話,只有能直接用的東西。Prompt 模板、自動化 SOP、技術拆解。

加入一人公司實驗室

免費資源包、每日建造日誌、可以對話的 AI Agent。一群用 AI 武裝自己的獨立開發者社群。

需要技術協助?

免費諮詢,24 小時內回覆。