從 Day 16 到 Day 24,素材特徵、素材草稿、一致性審查、模型比較,再到行銷助理的問答、護欄與評測,幾乎每一天都在呼叫模型,每一篇文章的 FinOps 小節也都交代了當天花多少,可是那些數字每天各算各的散在好幾篇文章裡,如果主管問這個專案到今天為止總共花了多少、哪一天最貴、是哪個模型吃掉的,就得把那幾篇文章翻出來自己加。
明天助理就要部署上線給同事用了,到時候呼叫模型的不再只有我,更不可能靠翻文章來算,這件事要在上線之前先解決。
好在 Day 16 就先做了準備,從那一天開始,拿得到用量的每一次模型呼叫都抄一份進同一張表 ops_llm_usage,一列就是一次呼叫,記了哪一天、哪支程式、哪個模型、輸入與輸出各多少 Token,今天要做的就是把這張表變成打開就看得到的儀表板,再替它配一個超過門檻會主動寄信的警報。
今日核心目標:
今天的架構是兩條互不相干的線,一條負責看,一條負責高呼警報。
| 儀表板 | 預算警報 | |
|---|---|---|
| 回答的問題 | 錢花在哪一天、哪一篇、哪個模型 | 這個月整個專案花超過門檻了沒 |
| 資料來源 | 自己記的用量表乘上單價表 | Cloud Billing 的實際帳單 |
| 範圍 | 只有寫進用量表的模型呼叫 | 專案裡所有會收費的服務 |
| 多久更新 | 查的時候才算,預設快取 12 小時 | 官方沒有給固定數字,用量回報到帳單會晚一段時間 |
| 要不要有人去看 | 要 | 不用,超過門檻自己寄信 |
| 工具 | BigQuery view 加 Data Studio | Cloud Billing 預算加 Cloud Monitoring 通知管道 |
這個設計有三個刻意的安排。
第一,用量表只存 Token 不存錢,單價另外放一張表 ref_llm_price,一列是一個模型在一種端點、一段期間的單價,這樣做是因為單價會變,gemini-3.6-flash 現在是導入期價格,官方定價頁寫明 2027 年 1 月 1 日起恢復原價,也就是現在的兩倍,如果當初把錢直接寫死在用量表裡,調價那天就得回頭改歷史資料,分開放的話只要在單價表加一列。
第二,換算放在 view 裡,不另外存一張算好的表,view 不存資料,每次被查才去讀用量表,所以儀表板看到的永遠是用量表當下的內容,不需要排程去更新,到今天為止用量表只有 279 列,每次現算完全沒有負擔。
第三,Cloud Monitoring 今天只做一件事,就是當預算警報的通知管道,我沒有另外做自訂指標把 Token 數送進 Cloud Monitoring 畫圖,原因是用量已經在 BigQuery 裡了,再送一份到另一個系統等於同一份資料維護兩個地方,而且預算警報看的是實際帳單,比我自己記的用量更適合拿來當警報的依據。
先看用量表裡到今天為止實際出現過哪些模型和端點。
| 模型 | 端點 | 出現在哪幾天 | 呼叫次數 |
|---|---|---|---|
| gemini-3.5-flash-lite | 非 global | Day 16、20 | 72 |
| gemini-3.6-flash | 非 global | Day 18、19、20 | 97 |
| gemini-3.6-flash | global | Day 21 到 24 | 85 |
| gemini-3.1-pro-preview | global | Day 20 | 24 |
| veo-3.1-lite-generate-001 | 非 global | Day 18 | 1 |
端點分兩種是因為價格不同,Day 16 到 20 是在 BigQuery 的 SQL 裡呼叫模型,資料集在美國多區域,只寫模型名稱的走非 global 端點,例外是 Day 20 的 gemini-3.1-pro-preview,它要把端點寫成 global 的完整網址才呼叫得到,Day 21 起的助理用 Python SDK 直接呼叫,走的也是 global 端點,官方定價頁上非 global 比 global 貴一成,同一個 gemini-3.6-flash 再加上 2027 年調價前後,就有四種價格。
INSERT INTO martech_dw.ref_llm_price VALUES
('gemini-3.6-flash', 'global', DATE '2026-07-21', DATE '2026-12-31', 0.75, 3.75, 'introductory pricing'),
('gemini-3.6-flash', 'non-global', DATE '2026-07-21', DATE '2026-12-31', 0.825, 4.125, 'introductory pricing'),
('gemini-3.6-flash', 'global', DATE '2027-01-01', DATE '9999-12-31', 1.50, 7.50, 'standard pricing'),
('gemini-3.6-flash', 'non-global', DATE '2027-01-01', DATE '9999-12-31', 1.65, 8.25, 'standard pricing'),
('gemini-3.5-flash-lite', 'global', DATE '2026-07-21', DATE '9999-12-31', 0.30, 2.50, ''),
('gemini-3.5-flash-lite', 'non-global', DATE '2026-07-21', DATE '9999-12-31', 0.33, 2.75, ''),
('gemini-3.1-pro-preview', 'global', DATE '2026-01-01', DATE '9999-12-31', 2.00, 12.00, 'input up to 200K tokens');
數字是每百萬 Token 的美元單價,前一個是輸入、後一個是輸出,輸出價包含思考 Token,都是 2026 年 10 月 8 日從官方定價頁查的,單價會變,照做之前請自己再查一次。
這張表有兩件事要留意,第一是同一個模型、同一種端點的期間不能重疊,重疊的話一次呼叫會對到兩列單價,費用就算了兩次,這件事交給檢查去守,第二是表裡沒有 Veo,Day 18 那支影片是按秒計費的,用量表裡它的 Token 欄位是空的,沒辦法用同一條公式算,後面會交代它在儀表板上怎麼呈現。
第一個 view v_llm_usage_calls 維持一列一次呼叫,做三件事,把時間換成台北日期、依模型與端點與日期對到單價、算出費用,下面是節錄,完整的在 monitoring/views.sql。
SELECT
DATE(u.logged_at, 'Asia/Taipei') AS usage_date,
u.day, u.job, u.model, u.endpoint_type,
IF(u.status = '', 'ok', 'failed') AS call_result,
IFNULL(u.prompt_tokens, 0) AS prompt_tokens,
IFNULL(u.output_tokens, 0) AS output_tokens,
p.model IS NOT NULL AS priced,
IFNULL(u.prompt_tokens, 0) * p.usd_in_per_m / 1e6 * 32 AS cost_in_twd,
IFNULL(u.output_tokens, 0) * p.usd_out_per_m / 1e6 * 32 AS cost_out_twd,
(IFNULL(u.prompt_tokens, 0) * p.usd_in_per_m + IFNULL(u.output_tokens, 0) * p.usd_out_per_m) / 1e6 * 32 AS cost_twd
FROM martech_dw.ops_llm_usage u
LEFT JOIN martech_dw.ref_llm_price p
ON p.model = u.model
AND p.endpoint_type = u.endpoint_type
AND DATE(u.logged_at, 'Asia/Taipei') BETWEEN p.valid_from AND p.valid_to;
幾個地方值得說明:
priced 是 false、費用是空值第二個 view v_llm_usage_daily 把第一個彙總成一列是一天、哪一篇、哪支程式、哪個模型、哪種端點,儀表板接的是這一個,裡面多一欄 unpriced_calls,數的是對不到單價的呼叫有幾次,因為 SUM 會自動跳過空值,光看費用合計看不出少算了什麼,要有這一欄放在旁邊才知道合計不是全部。
Data Studio 是 Google 的免費報表工具,2026 年 4 月以前叫 Looker Studio,舊網址 lookerstudio.google.com 現在會自動轉到 datastudio.google.com,接 BigQuery 當資料來源本身不收費,收的是 BigQuery 的查詢費,記在資料來源設定的帳單專案上。
先講一個限制,Data Studio 沒有可以從零建立報表的 API,也沒有 Terraform 資源,所以這個系列一路堅持的一行指令做完,今天在儀表板這一步做不到,最接近的做法是 Linking API,把資料來源寫進一個網址,點開之後報表和資料來源就建好了,剩下的圖表要在瀏覽器裡用拖拉的方式完成。
https://datastudio.google.com/reporting/create?r.reportName=MarTech%20AI%20Token%20Cost&ds.connector=bigQuery&ds.type=TABLE&ds.projectId=你的專案ID&ds.datasetId=martech_dw&ds.tableId=v_llm_usage_daily&ds.billingProjectId=你的專案ID
點開網址之後會連續遇到四個確認,授權 Data Studio 讀取 BigQuery、確認資料來源用的是擁有者憑證、同意報表使用你的帳號資訊做稽核紀錄、第一次使用還要選國家並同意服務條款,全部通過之後按 Edit and share 進入編輯模式。

我放了五個元件,做法都是從右邊的欄位清單把欄位拖到畫布或圖表的設定欄裡。
| 元件 | 維度 | 指標 | 要回答的問題 |
|---|---|---|---|
| 表格 | day | cost_twd、calls、unpriced_calls | 每一篇花多少、呼叫幾次 |
| 長條圖 | model | cost_twd、calls | 哪個模型用得多、哪個模型花得多 |
| 計分卡 | 無 | cost_twd | 到目前為止總共花多少 |
| 計分卡 | 無 | unpriced_calls | 有幾次呼叫沒有算進上面的合計 |
| 長條圖 | usage_date | total_tokens | 每一天用掉多少 Token |
資料來源用的是擁有者憑證,意思是看報表的人不需要自己有 BigQuery 的權限,查詢都用我的身分去跑、費用記在我的專案,換來的代價是任何拿得到報表的人都看得到資料,所以分享設定維持預設的 Restricted,只有被加進名單的 Google 帳號打得開,不要改成知道連結的人都能看。
第一件事,Day 16 到 Day 24 共 279 次呼叫,算得出來的費用合計是新台幣 22.73 元。
| 篇 | 呼叫次數 | 輸入 Token | 輸出 Token | 費用(新台幣) |
|---|---|---|---|---|
| Day 16 | 48 | 51,408 | 2,748 | 0.78 |
| Day 18 | 25 | 54,100 | 12,245 | 3.04(不含影片) |
| Day 19 | 48 | 171,520 | 7,509 | 5.52 |
| Day 20 | 73 | 140,245 | 10,411 | 7.60 |
| Day 21 | 16 | 9,111 | 5,466 | 0.87 |
| Day 22 | 8 | 30,761 | 2,920 | 1.09 |
| Day 23 | 37 | 61,429 | 8,882 | 2.54 |
| Day 24 | 24 | 14,294 | 7,752 | 1.27 |
最貴的是 Day 20 的模型比較,那一天同一批題目讓三個模型各做一次,Day 23 的 2.54 元和 Day 24 的 1.27 元,跟那兩天文章裡寫的數字一樣,這也順便驗證了 view 的算法和當時程式裡的算法是一致的。
第二件事,輸出整體不到 Token 的一成,卻佔了費用的三到五成,下面這張表是報表第 3 段印出來的。
| 模型 | 端點 | 呼叫次數 | 費用(新台幣) | 輸出佔 Token | 輸出佔費用 |
|---|---|---|---|---|---|
| gemini-3.6-flash | 非 global | 97 | 9.75 | 7.5% | 28.9% |
| gemini-3.6-flash | global | 85 | 5.78 | 17.8% | 52.0% |
| gemini-3.1-pro-preview | global | 24 | 5.63 | 10.5% | 41.4% |
| gemini-3.5-flash-lite | 非 global | 72 | 1.57 | 5.1% | 30.9% |
原因是輸出的單價是輸入的五倍以上,gemini-3.6-flash 輸入 0.75 美元、輸出 3.75 美元,global 那一列是助理的問答,回答寫得長、還有思考 Token,輸出佔到 Token 的 17.8%,費用就有一半以上花在輸出,所以助理這種回答長、會思考的用法,限制輸出長度和思考的額度省得比較多,看圖和比對這種輸入大、回答短的用法,要省的反而是輸入。
第三件事,模型的選擇比呼叫次數更影響費用,gemini-3.1-pro-preview 只呼叫了 24 次就花了 5.63 元,gemini-3.6-flash 在 global 端點呼叫 85 次是 5.78 元,兩個幾乎一樣,而 gemini-3.5-flash-lite 呼叫 72 次只要 1.57 元,圖二右上角那張長條圖把費用和呼叫次數並排,gemini-3.6-flash 兩種端點合在一起所以兩根都高,gemini-3.5-flash-lite 次數多費用少,gemini-3.1-pro-preview 次數少費用多,一眼就看得出來。
第四件事最重要,儀表板上的 22.73 元不是這個專案的全部花費,至少有三筆不在裡面:
unpriced_calls 的 1 裡另外還有模型以外的費用,BigQuery、Cloud Storage、Cloud Run 就算都在免費額度內,也不會出現在這張儀表板上,所以儀表板適合回答錢是怎麼花的、趨勢往哪裡走,實際花了多少要看 Cloud Billing 的帳單。
儀表板要有人打開才有用,超過門檻這件事不能靠人記得去看,Day 03 用 Terraform 建的預算警報本來就在做這件事,每月預算新台幣 300 元,在 50%、80%、100% 三個門檻寄信,預設的收件人是帳單帳戶的管理員與使用者。
今天加的是讓它多寄一份到指定的信箱,做法是在 Cloud Monitoring 建一個 email 類型的通知管道,再把預算連到這個管道。
resource "google_monitoring_notification_channel" "budget_email" {
count = var.billing_account_id != "" && var.alert_email != "" ? 1 : 0
project = var.project_id
display_name = "MarTech Budget Alert Email"
type = "email"
labels = {
email_address = var.alert_email
}
}
預算那一邊多一個 all_updates_rule 區塊,把通知管道的 ID 填進 monitoring_notification_channels,disable_default_iam_recipients 維持 false,原本寄給帳單帳戶管理員與使用者的那一份照舊,一個預算最多可以連 5 個通知管道,團隊裡要收到警報的人不一定有帳單帳戶的權限,這個管道就是給他們用的。
這裡要講清楚預算警報做不到的兩件事,它只會寄信,不會幫你把服務停掉,錢還是會繼續花,另外它有延遲,官方文件只說用量回報到 Cloud Billing 需要時間、沒有給數字,另外提到預算剛建好的時候第一封通知可能要等幾個小時,所以它擋不住幾分鐘內就燒完預算的那種意外,那一類要靠前面每一天都在做的第二道防線,也就是程式裡的呼叫次數上限、Token 上限和花錢前的估價確認。
| 項目 | 今天的費用(新台幣) | 說明 |
|---|---|---|
| 模型呼叫 | 0 元 | 今天沒有呼叫任何模型 |
| BigQuery 查詢 | 0 元 | 在每月 1 TiB 免費額度內 |
| Data Studio | 0 元 | 免費版 |
| 通知管道與預算警報 | 0 元 | 不收費 |
~/ai-driven-martech-pipeline 執行 git pull,取得 Day 25 新增的 monitoring/ 目錄gcloud config get-value project 要印出你的專案 IDops_llm_usage 是 Day 16 建的,至少要跑過 Day 16 之後任何一天的程式,表裡才有資料cd ~/ai-driven-martech-pipeline
bash monitoring/run.sh
這個指令會建立單價表和兩個 view,跑 12 項檢查,再印出四段報表,全程不呼叫模型,最後一行會印出儀表板要接的 view 名稱,接著把 3.3 那個網址裡的兩個「你的專案ID」換成自己的,貼到瀏覽器打開,照畫面完成授權,再把欄位拖成圖表。
cd ~/ai-driven-martech-pipeline
bq query --nouse_legacy_sql --format=pretty < monitoring/probe.sql
會列出每一天、每支程式、每個模型、每種端點各有幾次呼叫,單價表要列哪些模型是看這個結果決定的,不要憑印象。
bq query --nouse_legacy_sql < monitoring/price.sql
bq query --nouse_legacy_sql < monitoring/views.sql
bq query --nouse_legacy_sql --format=pretty < monitoring/check.sql
12 項裡最值得看的是第 06、07 兩項,第 06 項確認單價表沒有期間重疊,第 07 項確認沒有「有 Token 卻對不到單價」的呼叫,如果你用了單價表裡沒有的模型,第 07 項會是 DIFF,到 price.sql 補一列再跑一次。
bq query --nouse_legacy_sql --format=pretty < monitoring/report.sql
四段依序是每一篇、每一天、每個模型與端點、對不到單價的呼叫。
cd ~/ai-driven-martech-pipeline/terraform
grep -q '^alert_email' terraform.tfvars || echo 'alert_email = ""' >> terraform.tfvars
sed -i 's/^alert_email.*/alert_email = "你的信箱"/' terraform.tfvars
~/bin/terraform plan
~/bin/terraform apply
前兩行是把 terraform.tfvars 裡的 alert_email 改成你的信箱,檔案裡沒有這一行就先補上,記得把「你的信箱」換掉,先看 plan 的結果再決定要不要 apply,這一次 plan 除了預算警報的變更與通知管道,還會列出 Day 26 到 28 要用的資源(三個 API、映像檔存放區、兩個服務帳號、一個空的密鑰,以及六個權限綁定),我的環境是 14 個新增、1 個變更、0 個刪除,這些資源建立當下都不收費。
check.sql 的 12 項都是 OK單價表和兩個 view 都很小,留著不會產生費用,Day 26 助理上線之後的用量會繼續寫進同一張用量表,儀表板不用改就會多出新的資料,真的要清掉的話:
bq rm -f -t martech_dw.v_llm_usage_daily
bq rm -f -t martech_dw.v_llm_usage_calls
bq rm -f -t martech_dw.ref_llm_price
Data Studio 的報表在 datastudio.google.com 首頁選移除,預算警報的通知信箱把 terraform.tfvars 裡的 alert_email 改回空字串再 apply 一次。
ds.ds0.connector 這種帶別名的參數,在沒有指定範本、用預設範本建立的報表上會出現「ds0 is not a valid data source alias」,把別名拿掉寫成 ds.connector 才會成功今天把 Day 16 以來累積的 279 次模型呼叫,用一張單價表和兩個 view 換算成費用,接上 Data Studio 做成儀表板,算得出來的部分合計新台幣 22.73 元,最貴的是 Day 20 的模型比較,輸出整體不到 Token 的一成卻佔了費用的三到五成,24 次 gemini-3.1-pro-preview 花的錢和 global 端點那 85 次 gemini-3.6-flash 差不多,另外沿用 Day 03 的預算警報,多連了一個通知信箱,今天沒有呼叫模型,花費是 0 元。
回到篇名,打開儀表板確實一眼就看得到每天被扣了多少 Token、每一篇換算成多少錢,但今天更想留下的是它的邊界,按秒計費的影片、不回報用量的評分服務、建表之前的呼叫,這三筆它都看不到,儀表板回答的是錢怎麼花的,花了多少要回到帳單,超過了沒要交給預算警報,三樣東西各有各的用處,少了哪一樣都會有看不到的地方。
明日預告:Day 26《把 AI 助理部署上線,讓全團隊都能直接用》,把 Day 21 到 23 做好的助理連同護欄包成 Cloud Run 服務,只開給指定的 Google 帳號,同事用的每一次呼叫都會出現在今天的儀表板上。