iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Build on Google AI

AI-Driven MarTech:用 Google Cloud + Vertex AI 打造全自動廣告歸因與多模態素材分析系統系列 第 10 篇

Day 10 | 同一份資料問 AI 十次,不用付十次錢的快取機制

  • 分享至 

  • xImage
  •  

1. 前言:每一題都在重付同一段內容的錢

昨天 Day 09 讓 Gemini 在 BigQuery 裡判讀四筆廣告異常,仔細看每一題會發現真正不一樣的只有中間幾行數字,前面的角色說明、後面的六個候選原因和四條規則每題都一模一樣,Gemini 每收到一題就把整段重新讀一次,也重新算一次錢。

Day 09 的題目很短,每題約 270 到 310 個 Token,重複的部分付了也沒多少錢,但實際要讓 AI 判斷得準,通常得附上背景資料,例如商品清單、檔期、每個廣告群組過去幾個月的成效,背景一長,每題重複的部分就變成好幾千個 Token,題目越多、重跑越多次,這段一樣的內容就被重複付費越多次。

Gemini 有一個快取機制專門處理這種狀況,簡單說就是先把每次都一樣的內容存在 Gemini 那邊,下次直接拿來用,讀取快取裡的內容只收一折,今天就用 Day 09 的四筆異常加上真正的背景資料來實測,看看能省多少、要問幾次才划得來。

今日核心目標:

  1. 從倉儲整理背景資料,和 Day 09 的角色、選項、規則組成一段 6,234 個 Token、每題都一樣的固定內容
  2. 同一批題目用三種做法各跑三輪:數字在前、固定內容在前、先建明確快取,比較命中多少、花多少錢
  3. 算出明確快取要問幾次才划得來,並把建快取、用快取、刪快取做成一行指令

2. 系統架構全景與設計理念

圖一:固定內容存進快取後,每題只送出會變的數字,Gemini 把快取裡的固定內容接在題目前面一起判讀,回答與 Token 用量寫進 cache_runs

步驟 做什麼 產出
組固定內容 從倉儲整理商品、檔期、素材、廣告群組每週成效,加上角色、選項、規則 cache_context,一列 6,234 個 Token
拆出會變的部分 每題只留那一筆異常的數字 cache_prompt 檢視表,每題 139 到 179 個 Token
建快取 用 Cloud Shell 把固定內容送進 Gemini 的快取,設定存活 30 分鐘 一個快取名稱
三種做法各跑三輪 同樣 4 題,分別用三種方式問 cache_runs,每題記下輸入、命中、輸出的 Token 數
用完就刪 跑完立刻刪掉快取 不再收儲存費

💡 核心工程理念:

  1. 固定的放前面、會變的放後面:隱含式快取只比對題目開頭,從第一個不一樣的字開始,後面全部照原價計算
  2. 背景資料用真的:背景資料全部來自倉儲,沒有為了湊長度灌水,也讓 AI 有可以比較的基準
  3. 快取用完就刪:明確快取活著就一直收錢,建立、使用、刪除要寫在同一支腳本裡

3. 核心技術深度拆解

3.1 快取在省什麼

Gemini 的快取有兩種,差別在要不要自己動手,今天的金額都以 1 美元約 32 元換算成新台幣:

隱含式快取 明確快取
怎麼開 預設就開著,不用設定 自己先建一個快取,每次呼叫帶上快取名稱
什麼時候命中 Gemini 發現這次的開頭和最近某次一樣時,由 Google 決定 每次都命中
命中的部分 打一折 打一折
額外費用 沒有 建立那次照原價算,另外每百萬 Token 每小時收約新台幣 32 元儲存費
最短長度 4,096 個 Token 4,096 個 Token

最短長度是官方文件寫明的門檻,所以第一件事是檢查題目的順序,第二件事是背景夠不夠長,Day 09 每題約 300 個 Token,離門檻還差很遠。

今天的背景資料從倉儲整理出四塊,全部是 Day 07 建好的表:

區塊 內容
商品清單 5 項商品的定價與第一次出現的日期
專案檔期 秋日棉織專案 9/1 到 9/16
素材清單 30 支素材的通路、廣告群組、受眾、格式、上下檔日、主打商品
各廣告群組每週成效 15 個廣告群組從 6/22 起每週的點擊、點擊率、每次點擊花費

加上 Day 09 的角色、六個候選原因與四條規則,共 9,386 字,AI.COUNT_TOKENS 數出 6,234 個 Token(建快取時 Gemini 回報 6,231 個,兩種算法差 3 個),每題會變的數字只有 139 到 179 個 Token,也就是說一題裡超過九成五的內容都是重複的。

3.2 先把題目的順序反過來

Day 09 的題目是先講這一筆的數字,最後才列出候選原因和規則,這個順序對人來說很自然,但每題很快就出現不一樣的字,隱含式快取派不上用場,今天把順序改成固定內容在前、數字在後,下面括號裡那一行只是說明,不會送出:

你是電商公司的廣告分析師,接下來會陸續收到系統自動找出的成效異常……
候選原因只能從這六個選一個:競價變貴、追蹤碼失效、素材疲乏、需求或季節變化、其他、資料不足
規則:……
【背景一】商品清單……
【背景四】各廣告群組每週成效(廣告群組|週一日期|有資料天數|點擊|點擊率%|每次點擊花費元)
meta-trn-prospecting|2026-08-10|7|1727|2.39|13.4
……
(以上每題都一樣,以下每題不同)
檢查批次:第 1 批
【這次要判斷的異常】
對象:廣告群組 meta-trn-prospecting(通路 meta)……

背景四用直線分隔的精簡格式,每一列只放名稱和數字,是為了讓背景資料不要膨脹得太長。

明確快取則是把「以上每題都一樣」那一段先送進 Gemini 存起來,之後每題只送出底下那幾行,再附上快取名稱,建快取要呼叫 Vertex AI 的服務,我寫成 caching/cache.sh,一行指令就能建立、列出或刪除,SQL 這邊改用 AI.GENERATE 並在 model_params 裡帶上快取名稱:

AI.GENERATE(
  question,
  endpoint => 'https://aiplatform.googleapis.com/v1/projects/專案ID/locations/global/publishers/google/models/gemini-3.5-flash-lite',
  connection_id => 'us.vertex_ai_conn',
  model_params => JSON '''{"cachedContent": "快取名稱", "generation_config": {...}}''')

endpoint 是請求要送去的地址,global 代表不指定機房地區的入口,這裡一定要寫完整網址,原因放在第 6 章,完整的腳本與參數說明在 caching/README.md。

3.3 三種做法各跑三輪

同樣 4 題、同一個模型 gemini-3.5-flash-lite、同一個端點,三種做法各跑三輪共 36 次,每一輪在會變的那一段開頭加上「檢查批次:第 N 批」,模擬每次都是新的一批數字,數字在前的做法會變的部分本來就在最前面,所以批次編號也就在整題的最前面:

做法 12 題命中幾題 輸入 Token 其中從快取讀取 輸出 Token 費用
數字在前(和 Day 09 一樣把數字放在固定內容前面) 0 78,657 0 1,357 約新台幣 0.86 元
固定內容在前(隱含式) 1 78,657 6,016 1,519 約新台幣 0.82 元
明確快取(含建立與儲存費) 12 78,645 74,772 1,434 約新台幣 0.30 元

明確快取 12 題全部命中,每題都從快取讀了 6,231 個 Token,實際照原價付費的只剩題目本身和回答格式設定約 320 個 Token,連同建立快取的新台幣 0.06 元、存活約 6 分鐘的儲存費新台幣 0.02 元,總共約新台幣 0.30 元,只看輸入的部分從新台幣 0.76 元降到 0.19 元(含建立與儲存費),省了七成五。

固定內容在前的隱含式快取就沒那麼理想,12 題只有第一輪的一題命中,稍早我用 Day 09 的遠端模型測過同樣的內容,第二輪 4 題有 3 題命中,發文前用 run.sh 重跑一次則是 12 題都沒命中,幾次的呼叫方式和間隔都不一樣,實測分不出原因,隱含式快取有命中就賺到,但不能拿來編預算。

判斷結果方面,三個植入的狀況 S1、S2、S3 三種做法共 27 題全部答對,第四筆 meta-evg-prospecting 是 S3 那支素材所在的廣告群組,答案表裡沒有它的標準答案,Day 09 沒有背景資料時 flash-lite 選了「資料不足」,今天附上 13 週的成效基準後 9 題都選素材疲乏,和 Day 09 我的判讀一致,但這一筆只有 3 天資料,呼叫方式也和 Day 09 不同,要多看幾個案例才能說背景資料讓判斷更準。

3.4 什麼時候划得來

明確快取每一題會幫忙省下固定內容九成的輸入費,代價是建立時要照原價付一次,加上活著的每一個小時都要付儲存費,用今天的數字走一遍,單價都是每百萬 Token:

  • 每題省下:6,231 個 Token × (原價 9.6 元 − 快取價 0.96 元)≈ 新台幣 0.054 元
  • 建立一次:6,231 個 Token × 9.6 元 ≈ 新台幣 0.06 元
  • 存活 30 分鐘:6,231 個 Token × 每小時 32 元 × 0.5 小時 ≈ 新台幣 0.10 元
  • 兩平:(0.06 + 0.10)÷ 0.054 ≈ 3 題

仔細看這三行,每一行都乘上同一個 6,231,換成更長或更短的背景,三行會一起放大或縮小,除完之後長度剛好互相抵銷,所以要問幾次才划得來只跟快取活多久有關,公式是(9.6 + 32 × 存活小時)÷ 8.64:

快取存活 至少要問幾次才划得來
10 分鐘 2 次
30 分鐘 3 次
1 小時 5 次
6 小時 24 次
24 小時 90 次

今天 12 題、存活 6 分鐘,遠遠超過兩平點,但如果建了快取卻讓它放一整天,一天要問滿 90 題才回本,重建一次的成本等於保留約 18 分鐘的儲存費,所以兩批之間相隔超過約 18 分鐘,就該跑完立刻刪、下一批再重建。

背景長度雖然不影響要問幾次,但決定了能不能用,低於 4,096 個 Token 建不起來,而且背景越長,每題省下的絕對金額越大。


4. FinOps 成本防護實踐:三道防線體系

  1. 第一道防線:善用 Google Cloud 每月免費額度:今天在 BigQuery 跑了 61 個查詢,實際只讀了 0.8 MB,因為每個查詢每讀一張表至少算 10 MiB,計費量是 1,153.4 MB,約每月 1 TiB 免費額度的千分之一,Gemini 另外計費,今天含開工驗證與發文前重跑共呼叫 82 次,約新台幣 4.5 元
  2. 第二道防線:架構層被動成本防護:cost.sql 在呼叫前用 AI.COUNT_TOKENS 數出固定內容與題目的長度,估出三種做法的最壞情況合計約新台幣 3.25 元,實際約新台幣 2 元,run.sh 要輸入 yes 才會建快取,而且不管中途有沒有出錯,腳本結束時都會去刪快取,刪不掉會印出警告
  3. 第三道防線:Cloud Billing 預算警報:沿用 Day 03 由 Terraform 建立的預算警報(新台幣帳戶 NT$ 300/美元帳戶 US$ 10),50%、80%、100% 三段通知,今天的操作不會觸發

5. Cloud Shell 實戰演練:一行指令比較三種做法

5.1 事前準備

  • 已完成 Day 09,martech_dw 裡有 diag_prompt,如果照 Day 09 第 5.5 節刪掉了,重跑 diagnosis/summary.sql 與 diagnosis/prompt.sql 即可,不會呼叫 Gemini
  • 已完成 Day 03 的 Terraform,連線 us.vertex_ai_conn 存在,而且連線的服務帳號有 Vertex AI User 角色
  • 確認 gcloud 有登入中的帳號,輸入 gcloud auth list,帳號前面要有星號

5.2 路線 A|懶人包:一行指令從建快取到出對照表

cd ~/ai-driven-martech-pipeline && git pull && bash caching/run.sh

畫面印出預估費用後輸入 yes,看到「16 項通過、0 項不通過」、三段對照表與明確快取的額外成本就完成了。

5.3 路線 B|逐步教學:理解每一個步驟

步驟 1:取得最新程式碼

cd ~/ai-driven-martech-pipeline
git pull
ls caching

會看到 context.sql、cost.sql、cache.sh、experiment.sql、check.sql、report.sql、run.sh 與說明文件 README.md。

步驟 2:組固定內容並估費用

bq query --nouse_legacy_sql < caching/context.sql
bq query --nouse_legacy_sql --format=pretty < caching/cost.sql

context_tokens 至少要 4,096 才建得了快取,worst_twd 是最壞情況的新台幣費用。

步驟 3:建立明確快取

bash caching/cache.sh create

會印出快取名稱、Token 數與到期時間,名稱同時存進 caching/.cache_name,從這一刻起開始收儲存費,快取 30 分鐘後會自動過期,請在時間內接著做步驟 4。

步驟 4:三種做法各跑三輪

PROJECT=$(gcloud config get-value project)
CACHE=$(cat caching/.cache_name)
sed -e "s#PROJECT_ID#${PROJECT}#g" -e "s#CACHE_NAME#${CACHE}#g" caching/experiment.sql \
  | bq query --nouse_legacy_sql

endpoint 在 SQL 裡只能寫常數,所以用 sed 把專案 ID 與快取名稱代進去,36 題約半分鐘到一分鐘跑完。

步驟 5:刪快取、檢查並看結果

bash caching/cache.sh delete
bash caching/cache.sh list
bq query --nouse_legacy_sql --format=pretty --max_rows=100 < caching/check.sql
sed -n '/-- ①/,/;/p' caching/report.sql | bq query --nouse_legacy_sql --format=pretty
sed -n '/-- ②/,/;/p' caching/report.sql | bq query --nouse_legacy_sql --format=pretty
sed -n '/-- ③/,/;/p' caching/report.sql | bq query --nouse_legacy_sql --format=pretty

list 最後一行要顯示「還活著的快取:0」,check.sql 會確認固定內容夠長、三種做法都有 12 列、沒有錯誤、原因都在選項內、三個植入的狀況都答對、數字在前的做法沒有命中、明確快取 12 題全部命中,後面三行分別印出每一輪的費用、三種做法合計,以及不同存活時間要問幾次才划得來。

5.4 驗證成果

  • 固定內容 6,234 個 Token,超過 4,096 的門檻
  • 明確快取 12 題全部命中,隱含式命中幾題每次可能不同
  • check.sql 16 項全部通過,cache.sh list 顯示沒有活著的快取

5.5 用完後全部清除

bash caching/cache.sh list
bq rm -f -t martech_dw.cache_prompt
bq rm -f -t martech_dw.cache_context
bq rm -f -t martech_dw.cache_runs

先確認沒有活著的快取,三張表都很小放著不會產生費用,真正會一直收錢的只有還沒過期的快取。


6. 工程實務避坑指南

  1. 開頭一不一樣決定了隱含式快取命中多少:從第一個不一樣的字開始,後面全部照原價計算,把日期、批次編號這類每次都會變的內容放在固定內容前面,整段固定內容就等於沒快取到
  2. 太短的內容不能快取:固定內容至少要 4,096 個 Token,Day 09 那種 300 個 Token 左右的題目直接照原價付費就好
  3. 存活時間設太長又忘了刪,會一直收錢:今天這份 6,231 個 Token 的快取如果把存活時間設成一個月,儲存費約新台幣 144 元,是今天全部 Gemini 費用約 4.5 元的三十幾倍,cache.sh 預設 30 分鐘就會自動過期,run.sh 結束時也會主動刪除
  4. 不是每個模型都有區域版本:在 us-central1(美國中部的機房)建 gemini-3.5-flash-lite 的快取會回 404,也就是找不到這個模型,要改建在 global
  5. endpoint 要寫完整網址:AI.GENERATE 只寫模型名稱時,看起來 BigQuery 會把請求送到別的區域,找不到 global 的快取,會出現「Not found: cached content metadata」,另外 endpoint 不能用變數只能寫常數,model_params 我也一併寫成常數
  6. 隱含式快取不能拿來編預算:同樣的內容稍早命中 3 題、正式跑只命中 1 題、發文前重跑 0 題,要穩定省錢就用明確快取
  7. 更正 Day 09 的思考設定:Day 09 寫到 thinking_level 會被 BigQuery 擋下,今天確認是大小寫的問題,寫成大寫 "LOW" 就能通過,但 flash-lite 在 LOW 仍然會先思考約 60 個 Token,像今天這種選擇題還是用 thinking_budget 設 0 最省

7. 總結與明日預告

今天把 Day 09 每題都重送的角色、選項、規則,加上從倉儲整理出來的商品、檔期、素材與每週成效,組成一段 6,234 個 Token 的固定內容,同樣 4 題用三種做法各跑三輪,數字在前完全不命中,固定內容在前靠隱含式快取只命中一題,明確快取則 12 題全部命中,連同建立與儲存費在內約新台幣 0.30 元,是數字在前的三分之一左右。

回到篇名,同一份資料問 AI 十次,只要先把資料存進快取,除了建立時付一次原價和一點儲存費,十次裡重複的部分都只收一折,而且算下來要問幾次才划得來只跟快取活多久有關,活 30 分鐘問 3 次就回本,所以最實用的習慣是批次開跑前建、跑完就刪。

另外附上背景資料之後,Day 09 判「資料不足」的那一筆今天改選素材疲乏,快取讓我們付得起更長的背景資料,也讓 AI 有了可以比較的基準,至於判斷有沒有因此變準,還要等之後有更多案例再下結論。

明日預告:Day 11《讓資料自己分組,才發現你的顧客其實只有這幾種人》,我們將回到倉儲裡的顧客與訂單,用 BigQuery ML 的 K-means 讓資料自己把顧客分成幾群,看看每一群的購買頻率、客單價和偏好的商品有什麼不同!


上一篇
Day 09 | 廣告成效突然跳水?直接在 SQL 裡叫 AI 找出原因
下一篇
Day 11 | 讓資料自己分組,才發現你的顧客其實只有這幾種人
系列文
AI-Driven MarTech:用 Google Cloud + Vertex AI 打造全自動廣告歸因與多模態素材分析系統 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言