第 15 週 · 單元 6-1 · 專案三
幫平台加上 AI 功能(下):不花錢也能測試 AI,然後上線
AI 每次回答都不一樣,又要花額度,要怎麼寫自動測試?答案是用「假的 AI」。本週完成每日上限、用假客戶端測試所有情況,最後部署並設定金鑰。
W15AI 功能測試+上線
本週結束時你會
今天的時間安排
| 0:00–0:30 | 【自己做】每日上限 |
| 0:30–1:15 | 【跟著做】用假的 AI 客戶端寫測試 |
| 1:15–1:25 | 休息 |
| 1:25–2:00 | 上線:Vercel 環境變數、線上驗收 |
| 2:00–2:30 | Demo、專案回顧、期末專題提案預告 |
每日上限【自己做】
需求:資料表 ai_usage(day, calls) 記錄每天呼叫次數;每次真的呼叫 API 前加 1;達到上限(環境變數 AI_DAILY_LIMIT,預設 50)時不呼叫,顯示「今天的 AI 使用次數已達上限」。
為什麼是全站上限,而不是每人上限:這個網站沒有登入,無法分辨是誰。全站上限是最後一道保險:就算有人寫程式狂按按鈕,一天最多也只會花 50 次的額度。
用假的 AI 客戶端寫測試【跟著做】
ai.summarize 有一個 client 參數。測試時傳入一個「長得像 Gemini 客戶端」的假物件:它不連網、回傳固定內容,還會記錄收到的提示詞,讓我們檢查 API 被呼叫了幾次、提示詞長什麼樣子。
提示詞 Antigravity
請在 tests/test_ai.py 寫 AI 摘要功能的測試,全部不可以真的呼叫 Gemini: 1. 寫一個 FakeClient 類別,模仿 google-genai 的 client.interactions.create(model, input):記錄每次收到的 input,回傳有 output_text 的物件;也可以設定成丟出錯誤 2. 測試前把 app.config["AI_CLIENT"] 換成 FakeClient 3. 測試這些情況:產生並顯示摘要;評論沒變時第二次不呼叫;新增評論後會重新呼叫;評論少於 3 則不呼叫;達到每日上限;AI 丟出錯誤時店家頁仍正常;含「忽略以上指示」的評論只出現在 <reviews> 區塊內;AI 回傳 <script> 時頁面有跳脫且長度被截斷;沒有金鑰時丟出 AIUnavailable 執行 python -m pytest -q。原本吃貨站的測試也要一起通過。
參考解答:原本吃貨站 17 項,加上 AI 功能 8 項,共 25 項全部通過。整套測試約 3 秒跑完,一毛錢都不花。
參考解答的測試(節錄概念)
class FakeClient:
def __init__(self, reply="湯頭鮮甜最常被稱讚,缺點是要排隊。", error=None):
self.prompts, self.reply, self.error = [], reply, error
self.interactions = SimpleNamespace(create=self._create)
def _create(self, model, input):
self.prompts.append(input) # 記錄提示詞,之後可以檢查
if self.error:
raise self.error # 模擬 AI 服務掛掉
return SimpleNamespace(output_text=self.reply)
完整檔案:practice/s3-6-1_AI功能/參考解答/foodie-ai/tests/test_ai.py
製作參考解答時,注入測試一開始失敗:提示詞的說明文字本身也提到「<reviews> 標記」,測試抓到的是說明文字裡的那一個,而不是資料區塊。修正方式是取最後一組標記。這個例子很適合說明「測試失敗時,先確認是程式錯還是測試錯」。
上線
- 吃貨站要先完成第 8 週的做法:db.py 支援 Postgres、Vercel 連上 Neon,並在 Neon 建立 ai_summaries 與 ai_usage 兩張表。
- Vercel → Settings → Environment Variables,新增
GEMINI_API_KEY(自己貼上金鑰)與SECRET_KEY,可選擇性新增AI_DAILY_LIMIT。 - 重新部署,打開派森牛肉湯產生一次摘要。
| 線上驗收 | 正確結果 |
|---|---|
| 產生摘要 | 出現摘要,重新整理後仍在(存在 Neon) |
| Vercel 刪掉 GEMINI_API_KEY 再部署 | 店家頁正常,只有摘要顯示暫時無法使用 |
| GitHub 上搜尋金鑰的前幾個字元 | 找不到 |
本週檢核
驗證紀錄:參考解答的 25 項測試全部通過(google-genai 2.31)。真正的 Gemini API 需要個人金鑰,參考解答沒有實際呼叫;請老師在課前用自己的金鑰執行一次 ai_hello,確認目前可用的模型名稱。
第 16 週預告:期末專題提案。請帶著第 2 週寫的 PROJECT.md 初稿來。