前幾天完成消費分析與資料修改後,測試自然語言查詢時發現了一個很重要的問題——不只是「查詢體驗不夠自然」,而是功能雖然能跑,但 Agent 還不夠可靠。
輸入「查詢 2026-08-25 的消費」,Gemini 已經正確理解成:
{
"type": "query",
"target": "expense",
"period": "date",
"date": "2026-08-25"
}
但後端原本只認得 today、yesterday、week、month、all 五種期間,date 沒有被正確處理。結果就是:明明 Google Sheets 裡有 8/25 的消費,卻查不到指定日期。
這是一個很典型的**「AI 已經理解,但後端沒有跟上」**的問題。所以 Day 28 的重點,除了把「指定日期查詢」完整補上,也順勢檢查了 Agent 在各種非正常情況下的表現,並從本機測試一路驗證到真正的 LINE 對話。
原本的消費查詢主要支援 today、yesterday、week、month、all 五種期間。例如「查詢今天的消費」,Gemini 能正確轉成 period: today。但當使用者指定一個明確日期,例如「查詢 2026-08-25 的消費」,這其實不屬於任何一種既有分類,它應該是一個新的查詢模式:period = date, date = 2026-08-25。
實際測試 ask_gemini("查詢 2026-08-25 的消費"),Gemini 成功回傳:
{
"type": "query",
"target": "expense",
"period": "date",
"date": "2026-08-25",
"keyword": null,
"category": null,
"upcoming": false
}
代表 AI 已經正確理解使用者不是要查整個月份,而是只查指定日期。
接下來要處理的問題是:Gemini 知道日期了,但 Google Sheets 裡的資料要怎麼只留下那一天?修改 filter_expenses(),加入新的分支:
elif period == "date":
if not target_date:
return []
try:
target_date = date.fromisoformat(str(target_date))
except ValueError:
return []
start_date = target_date
end_date = target_date
概念很簡單:指定日期 2026-08-25,就把查詢範圍的開始日期與結束日期都設成同一天,這樣只有那一天的資料會被留下。
光修改篩選函式還不夠,因為 Gemini 回傳的日期存在 data.get("date") 裡,因此在 query_data() 中加入 target_date = data.get("date"),再把它一併傳給 filter_expenses(records, period, target_date)。至此,整條資料流程完整串起來:
使用者「查詢 2026-08-25 的消費」→ Gemini(period=date, date=2026-08-25)
→ query_data() → filter_expenses()(只留下 2026-08-25)
→ format_expense_result() → LINE 回覆
原本查詢結果會顯示「📅 查詢期間:date」,對使用者來說並不直覺,因此加入判斷:指定日期查詢時顯示「📅 查詢日期:2026-08-25」,其他期間則維持「📅 查詢期間:month」這種原本的格式,讓使用者能直接知道 Bot 到底查了哪一天。
這是 Day 28 很重要的一部分。除了修正查詢邏輯,也開始檢查 Agent 在「正常情況以外」會不會壞掉:
| 情境 | SubWise 的處理 |
|---|---|
| Google Sheets API 錯誤 | 顯示友善錯誤訊息 |
| Gemini 429 | 進入 Gemini 錯誤處理 |
| Gemini 503 | 進入 Gemini 錯誤處理 |
| 查不到資料 | 顯示「目前查不到符合條件的消費資料」 |
| 無效分類 | 顯示支援的分類清單 |
| 修改找不到資料 | 要求提供更明確日期或金額 |
| 多筆符合條件 | 防止直接修改錯誤資料 |
| Gemini 無有效回傳 | 使用 Fallback |
| 無法判斷意圖 | 顯示預設提示 |
這讓 SubWise 不再是「輸入正確 → 功能才會正常」,而是開始變成:即使使用者輸入不完整、資料不存在或 API 發生問題,也能知道接下來該怎麼做。
修改完成後,沒有直接丟到 LINE 測試,而是照著一貫的分層驗證方式,一步步往上確認:
第一層:Python 語法檢查
執行 python -m py_compile query_service.py,確認沒有語法錯誤。
第二層:篩選函式單元測試
用三筆測試資料(兩筆 8/25、一筆 8/26)驗證 filter_expenses(test_records, "date", "2026-08-25"),成功只留下 8/25 的兩筆資料,8/26 的資料被正確排除,代表「指定日期篩選」本身正常。
第三層:完整 query_data 流程測試
模擬 Gemini 真正回傳的 JSON,執行 query_data(test_query),成功得到完整格式化的查詢結果(總支出 NT$70,1 筆消費,最高單筆消費明細也正確顯示),確認 query_data()、filter_expenses()、format_expense_result() 三個部分可以正常串接。
第四層:process_ai_message 主流程測試
執行 process_ai_message("查詢 2026-08-25 的消費"),確認從 Gemini 意圖判斷、query_service、Google Sheets 篩選到 LINE 格式化的整條流程都沒有問題。
本機測試通過後,才進入真正讓使用者透過 LINE 使用的測試,這次總共測試了四種情境:
測試一:查詢指定日期
輸入「查詢 2026-08-25 的消費」,SubWise 正確回覆「📅 查詢日期:2026-08-25」,總支出 NT$70,並列出正確的消費明細。指定日期查詢成功。
測試二:查詢今天(確認沒有影響原本功能)
輸入「查詢今天的消費」,Bot 依然正確回覆「📅 查詢期間:today」,總支出 NT$100,代表新增的 date 查詢邏輯沒有影響原本的 today。
測試三:查詢本月(再次確認舊功能沒被改壞)
輸入「查詢這個月的消費」,成功回覆「📅 查詢期間:month」,總支出 NT$4309,22 筆消費,明細仍然能正常按照日期由新到舊排列。這個測試很重要,因為新增功能時不能只確保新功能正常,也要確認原本已經完成的功能沒有被改壞。
測試四:查詢沒有資料的日期
故意測試「查詢 2026-01-01 的消費」,SubWise 回覆「📭 目前查不到符合條件的消費資料。」代表系統沒有因為查不到資料而發生錯誤,而是提供了使用者可以理解的提示——「沒有資料」本身也是一種正常狀態,不應該被當成系統錯誤。
period = date 與 date 欄位filter_expenses() 新增指定日期篩選邏輯query_data() 正確傳遞指定日期目前的完整資料流程:
自然語言 → Gemini 意圖判斷 → 結構化 JSON(period=date, date=...)
→ query_data() → Google Sheets → 指定日期篩選 → LINE UX 回覆
Day 28 解決了消費查詢的 UX 問題,現在 SubWise 已經能理解「查今天」、「查這個月」,甚至「查指定日期」的自然語言。
Day 29 將進一步強化消費分析功能,讓使用者不只是查詢資料,而是可以直接問:
「分析一下我這個月的消費」
明天預計完成:
目標是讓 SubWise 從:
「你問,我幫你找資料」
進一步變成:
「你問,我幫你整理並分析資料。」
這也會是 SubWise 從「智慧記帳工具」逐漸走向 AI 消費分析管家的重要一步。我們明天見!