iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
ChatGPT & Codex

AI 時代的輕量化開發:ChatGPT 打造 LINE 多模態記帳與續訂預警 Agent系列 第 29

[Day 29] 不是所有 API 都會乖乖工作:SubWise 的 API 防呆與錯誤處理

  • 分享至 

  • xImage
  •  

前言

鐵人賽進入倒數第二天。回頭看最開始的 SubWise,還只是一個很單純的想法:「能不能做一個真的可以幫我記帳、管理訂閱的 LINE Bot?」那時候從 Flask、LINE Webhook 開始,一步一步把功能拼起來。從最初只能 Echo「你剛剛說:你好」,到現在已經可以做到 AI 智慧記帳、發票/收據圖片辨識、消費與訂閱查詢、消費分析、訂閱管理、扣款提醒、消費修改與刪除、上下文理解、Quick Reply 互動操作、API 錯誤處理十項功能。

功能越來越多,也讓我開始發現一件事情:真正的應用程式,不是只有「功能可以成功」就夠了。 如果 API 暫時掛掉了呢?如果 Gemini 今天回傳 429 呢?如果 Google Sheets 沒有正常回應呢?如果使用者輸入了系統看不懂的內容呢?這些「不順利的情況」,其實也是產品的一部分。所以 Day 29,決定把重點放在:讓 SubWise 從「能運作」走向「更可靠」。


今日實作實錄:Gemini API 錯誤處理

過去的 Gemini 呼叫方式比較簡單,如果 API 發生錯誤,就直接:

except Exception as e:
    print(f"❌ Gemini API 發生錯誤:{e}")
    return None

這種方式雖然可以避免程式直接崩潰,但有一個問題:**不知道到底發生了什麼類型的錯誤。**例如 429 是請求太頻繁或達到使用限制、503 是 Gemini 暫時無法提供服務,其他錯誤則可能是網路、設定或未知問題。如果全部都只回傳 None,到了 app.py 就很難針對不同情況做更好的處理。

一、建立 GeminiAPIError

gemini_client.py 中新增專門的錯誤類別:

class GeminiAPIError(Exception):
    """Gemini API 錯誤,用來把 API 錯誤狀態傳回 app.py。"""

    def __init__(self, status_code=None, message=""):
        self.status_code = status_code
        self.message = message
        super().__init__(message)

這個類別的目的很簡單:把 Gemini 發生的 HTTP 狀態碼一起帶出去,例如 GeminiAPIError(status_code=429, message="Test Gemini rate limit"),到了 app.py 之後就能知道 e.status_code 是多少。

二、讓 Gemini API 錯誤可以被辨識

修改 ask_gemini(),原本發生錯誤時只是印出訊息並回傳 None,現在改成先取得錯誤的 status_code

status_code = getattr(e, "status_code", None)
raise GeminiAPIError(status_code=status_code, message=str(e))

這樣 API 層就負責「告訴上層到底發生什麼錯誤」,而 app.py 則負責「決定使用者應該看到什麼」,讓不同模組之間的責任更加清楚。

三、針對 429 與 503 提供不同訊息

app.pyget_friendly_error_message() 中,分別針對兩種錯誤設計不同文案:

429(使用量較高):

"gemini_rate_limit":
    "⏳ SubWise AI 目前使用量較高\n\n"
    "請稍等一下,再重新輸入你的需求。",

503(服務暫時無法使用):

"gemini_unavailable":
    "🔧 SubWise AI 目前暫時無法使用\n\n"
    "AI 服務可能正在忙碌或維護中,"
    "請稍後再試。",

兩種情況雖然都是「Gemini 出問題」,但對使用者而言,原因與下一步其實不太一樣——429 代表「等一下再試」,503 代表「服務本身有狀況」,區分開來能讓使用者更清楚該怎麼反應,這就是今天想補上的細節。


實際測試

完成程式修改後,沒有直接假設它可以正常運作,而是先做基本測試。

測試一:GeminiAPIError 本身

try:
    raise GeminiAPIError(status_code=429, message="Test Gemini rate limit")
except GeminiAPIError as e:
    print("status:", e.status_code)
    print("message:", e.message)

成功得到 status: 429message: Test Gemini rate limit,代表錯誤物件可以正常保存 HTTP Status Code 與 Error Message。
https://ithelp.ithome.com.tw/upload/images/20260829/20178527SVCsZ2eET0.png

測試二:429 與 503 的友善訊息

分別執行 get_friendly_error_message("gemini_rate_limit")get_friendly_error_message("gemini_unavailable"),都成功得到對應的友善提示文字。
https://ithelp.ithome.com.tw/upload/images/20260829/20178527Shgx3WMw1k.png
https://ithelp.ithome.com.tw/upload/images/20260829/20178527bw5SwVdPC6.png

測試三:確認正常功能沒有受影響

新增錯誤處理後,最重要的是確認原本正常的功能沒有被改壞。實際在 LINE 輸入「午餐 120」,SubWise 依然可以正常完成記帳,回覆完整的日期、分類、金額、項目資訊——新增錯誤處理,不應該讓原本正常的功能壞掉。
https://ithelp.ithome.com.tw/upload/images/20260829/20178527WLO3TeXhTD.png


今日完成

  • 建立 GeminiAPIError 類別,攜帶 HTTP status_code 與錯誤訊息
  • 修改 ask_gemini(),讓 API 層負責辨識錯誤類型
  • 針對 429、503 分別設計不同的友善錯誤訊息
  • 完成錯誤類別與友善訊息的單元測試
  • 確認新增錯誤處理不影響原本記帳功能

明日預告

最後一天,不打算再單純追求「多做一個功能」。Day 30 的目標,是把前面 29 天累積的功能,真正當成一個完整產品來驗收。

會進行最後的 End-to-End 測試,從使用者輸入開始,一路確認 LINE → Webhook → Intent/Context → Gemini AI → Service Layer → Google Sheets → 分析/查詢/訂閱 → LINE 回覆這整條路徑,同時重新檢查 AI 記帳、發票辨識、消費查詢、訂閱管理、扣款提醒、消費分析、修改/刪除、上下文理解、錯誤處理九大主要功能。

最後再整理這 30 天到底完成了什麼,以及這次用 ChatGPT / Codex 進行 Vibe Coding 的過程中,真正學到了什麼。Day 30,將會是這個 SubWise 專案的最後一章。 明天,正式完賽。我們明天見!


上一篇
[Day 28] 從「能用」到「可靠」:SubWise Agent 的錯誤處理、智慧防呆與查詢 UX 優化
下一篇
[Day 30] 30 天後,我真的做出了一個 AI Agent|SubWise 鐵人賽最終章
系列文
AI 時代的輕量化開發:ChatGPT 打造 LINE 多模態記帳與續訂預警 Agent30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言