iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0

1. 前言:廣告寫「限定」,點進去卻找不到哪裡限定

Day 18 的草稿只看廣告圖本身,但常常發生客人點下去之後看到的是另一個頁面,秋日棉織專案有一張 Meta 的廣告圖 cr-meta-aut-p1,左上角兩個徽章寫著「秋日」「限定」,點進活動頁從頭看到尾,沒有寫限量幾組,也沒有寫到哪一天截止,「限定」兩個字在頁面上找不到任何對應的說明,尤其是同個時段不只有一個活動檔期時,在過去往往只能靠人工來抓漏,這些細節很容易被忽略。

這種落差平常很難發現的原因之一在於廣告圖和活動頁通常不是同一個時間做的,兩邊各自上線之後,很少有人會把 24 張圖一張一張點進去對,今天把這件事交給 Gemini,每張廣告圖連同它導去的頁面一起給它看,請它列出廣告有寫、頁面找不到或說法不同的地方,再拿事先寫好的答案對照它抓到幾成,頁面用兩種方式給,一種給截圖、一種給文字,看哪一種抓得準、哪一種作法便宜。

今日核心目標:

  1. 整理 24 張廣告圖各自導去哪個頁面,並在呼叫 Gemini 之前先把兩邊的落差寫成答案表
  2. 用 AI.GENERATE 一次給多張圖,讓 Gemini 比對廣告圖與頁面,交出欄位固定的落差清單
  3. 比較頁面給截圖和給文字兩種做法抓到的落差、輸入的 Token 與費用

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

圖一:廣告圖、頁面截圖與頁面文字進題目,AI.GENERATE 交出落差清單,再和事先寫好的答案表比對

步驟 做什麼 產出
準備頁面 首頁與兩個活動頁各存一份文字、各截三段圖,廣告圖依活動代號對到頁面 ref_landing_pages 3 列、obj_landing 9 張、map_creative_landing 24 列
寫答案 廣告有寫、頁面沒有的落差逐列寫下來,先 commit 再呼叫 martech_gt.gt_ad_page_gaps 計分 21 列、有爭議 9 列
比對 24 張廣告圖 × 2 種給頁面的方式,response_schema 規定落差清單的欄位 mm_gaps_log 48 筆呼叫紀錄
對答案 同一種落差而且指到同一段廣告文字才算抓到 mart_ad_page_gaps
檢查與報表 14 項流程檢查、八段報表 check.sql、report.sql

💡 核心工程理念:

  1. 答案先寫再考:答案表在第一次呼叫 Gemini 之前就 commit,run.sh 發現答案、題目、截圖或評分的 SQL 有還沒 commit 的修改會直接停下來,每次評分都記下答案表的指紋(用內容算出來的一串檢查碼),事後改過答案檢查就不會過
  2. 兩種給法只差一個地方:給截圖和給文字用同一段檢查清單,選項也一樣,只有說明附了什麼的那一句不同,差別就在頁面是三段截圖還是一段文字,文字版把畫面上劃掉的原價另外註明,兩邊的文字資訊才對得上
  3. 題目是一份檢查清單:要查哪幾種落差直接列給 Gemini,今天量到的是照清單查能查出幾成,不是它自己會不會發現問題,清單裡另外放了兩種答案表完全沒有的落差,看它會不會因為清單上有就硬填

3. 核心技術深度拆解

3.1 哪張廣告對哪個頁面:對照表和答案表都先寫好

24 張廣告圖依活動代號對到三個頁面,常態素材 8 張到首頁,重訓襪專案 8 張到 /lp/training-socks,秋日棉織專案 8 張到 /lp/autumn-cotton,這張對照表 map_creative_landing 從 Day 07 的 dim_creative 直接算出來。

廣告圖上的字是 Day 14 之前用程式照規格畫上去的,每張圖有一行標題,文字多的圖另外有兩行賣點和兩個徽章,頁面內容來自 Day 04 的小店,兩邊逐字比對之後,查得到對錯的落差有五種:

落差種類 廣告圖上寫的 頁面上的情況 張數
limited_offer 徽章「限定」 秋日活動頁沒有限量、限時或截止日期 3
special_price 徽章「專案價」 重訓活動頁上厚底毛巾訓練襪 NT$ 260,沒有優惠價 3
free_shipping 徽章「免運」 首頁只在秋日專案那一格寫「滿 NT$ 600 免運」 5
product_name 標題「天天穿的純棉短襪」 頁面上的商品叫「日常中筒襪」 8
product_option 賣點「多色可選」 頁面沒有任何顏色選項 2

合計 21 列計分,這些落差本來就存在於素材和網站裡,不是為了今天另外做的,只是從來沒有人列過,柔軟、蓬鬆這類形容觸感或質感的文案不收,因為沒有對錯可以查。

另外有 9 列標成有爭議,不管 Gemini 有沒有列都不計分,一列是 cr-line-trn-r2 的「專案價」,這張圖主打的是日常中筒襪,活動頁上標 NT$ 180、原價 NT$ 220 劃掉,但那是全站都有的價格,算不算專案價見仁見智,另外 8 列是名稱不完全一樣、指的卻是同一件商品,廣告寫「襪子+毛巾新手組」頁面叫「日常入門組合」,廣告寫「厚底毛巾襪」頁面叫「厚底毛巾訓練襪」,短襪和中筒襪就不同了,襪筒長度不一樣,客人收到的東西會和廣告說的不同所以計分。

24 張裡有 6 張沒有任何計分的落差,用來看 Gemini 會不會無中生有。

3.2 一次給四張圖:長截圖先切開,欄位用 enum 鎖住

Day 14 到 Day 18 每次呼叫都只給一張圖,今天給截圖的那一半要一次給四張,AI.GENERATE 的第一個參數可以把文字和圖片依序排在一起,題目裡再說明哪一張是什麼:

AI.GENERATE(
  (CONCAT(t.intro, '第一張圖是廣告圖,後面三張圖是那個頁面的截圖,由上到下切成三段,相鄰兩段有一小部分重疊。\n\n', task_text),
   a.ref, l1.ref, l2.ref, l3.ref),
  connection_id => 'us.vertex_ai_conn',
  endpoint => 'gemini-3.6-flash',
  ...
)

a.ref 來自 Day 14 的物件表 obj_creatives,l1 到 l3 來自今天新建的物件表 obj_landing,指向素材 bucket 的 landing/ 資料夾。

頁面截圖沒有整張丟進去,首頁的整頁截圖寬 1,200、高 2,685 像素,Day 14 量過一張 1,200 × 628 的廣告圖大約算 1,100 個 Token,如果長圖也只給這麼多,小字就會糊掉,動手之前先把首頁截圖縮小來看,「滿 NT$ 600 免運」那一行已經很難辨識,所以每個頁面都由上到下切成三段,首頁等分三段,兩個活動頁照內容切成主視覺、專案商品和頁尾,這是用縮圖模擬的判斷,沒有實際拿整頁長圖去問 Gemini,今天實測首頁的三段比活動頁的三段高,算出來的 Token 卻幾乎一樣,在今天這幾種尺寸下看不出 Token 數跟著圖片大小變。

給文字的那一半只給廣告圖,頁面上看得到的文字接在題目最後面,文字是用不開視窗的瀏覽器程式從同一個頁面擷取的,純文字看不出哪個價格被劃掉,所以擷取時把劃掉的價格寫成「NT$ 180(原價 NT$ 220,已劃掉)」。

回答的格式用 response_schema 規定,先把廣告圖上的每一段文字抄進 ad_texts,再把落差一項一項列出來,落差種類用 enum 鎖在八個選項裡,五種要查的、兩種答案表沒有的(gift 贈品、warranty 保固或退換貨),再加一個 other:

"response_schema": {"type": "OBJECT", "properties": {
  "ad_texts": {"type": "ARRAY", "items": {"type": "STRING"}},
  "gaps": {"type": "ARRAY", "items": {"type": "OBJECT", "properties": {
    "gap_type": {"type": "STRING", "enum": ["limited_offer", "special_price", "free_shipping",
                 "gift", "warranty", "product_name", "product_option", "other"]},
    "ad_text": {"type": "STRING"},
    "page_evidence": {"type": "STRING"}
  }, "required": ["gap_type", "ad_text", "page_evidence"]}}
}, "required": ["ad_texts", "gaps"]}

先抄廣告文字這一步是為了事後分得出兩種漏法,一種是字有讀到但沒列成落差,一種是字根本沒讀對。

3.3 結果:21 個落差抓到 18 和 20 個,沒有無中生有

圖二:三張廣告圖和它導去的頁面截圖,右邊是答案表裡的落差與兩種給法引用的頁面證據,綠色是抓到的,紅色是漏掉的,橘色是有爭議不計分的

48 次呼叫全部成功,沒有一次撞到輸出上限,對答案的規則是同一種落差、而且 Gemini 抄下來的那段廣告文字裡有答案表的那個詞才算抓到,只有種類對不算。

落差種類 答案 給截圖抓到 給文字抓到
free_shipping 免運 5 5 5
special_price 專案價 3 3 3
product_name 短襪 8 8 8
limited_offer 限定 3 2 3
product_option 多色可選 2 0 1
合計 21 18 20

免運、專案價和商品名稱三種全部抓到,免運那五張 Gemini 引用的頁面原文都是「滿 NT$ 600 免運」那一句,引用的正是寫了門檻的那一句,6 張沒有計分落差的廣告圖,除了下面會提到的有爭議名稱之外,兩種給法都沒有多列任何一項,清單上那兩種答案表沒有的落差也一次都沒有被填。

漏掉的有四格,給截圖的 cr-line-aut-p2 有把「限定」抄進廣告文字,卻沒有列成落差,cr-line-trn-r2 的「多色可選」也是有讀到沒列,另外兩格都在 cr-line-evg-p1,這張圖上的「多色可選」兩種給法都被抄成「多色選」,少了一個字,給截圖的那次沒有列,給文字的那次有列出來,但因為抄下來的字裡沒有「多色可選」,照事先定好的規則算成漏掉一個、多列一個,所以給文字那一欄實際上是 21 個落差都有指出來,其中一個字抄錯。

抓到不代表理由都對,短襪對中筒襪這一種 8 張都抓到,可是導到重訓活動頁的 4 張,兩種給法共 8 次,Gemini 引用的頁面證據有 6 次含「厚底毛巾訓練襪」,只有 2 次提到真正對不上的那個商品「日常中筒襪」,而且這 2 次都是給截圖的,看起來像是把頁面主打的訓練襪當成對不上的對象,結論一樣是對不上,理由卻不是答案表寫的那一個,有爭議的 cr-line-trn-r2 兩種給法都列了「專案價」,引用的價格是訓練襪的 NT$ 260,不是這張圖主打的中筒襪。

有爭議的名稱差異兩種給法的做法不太一樣,「新手組」對「日常入門組合」兩張都被列出來,「厚底毛巾襪」對「厚底毛巾訓練襪」給截圖的列了 6 張裡的 5 張,給文字的只列 1 張,這幾列不計分,但實際使用時會多出一批需要人判斷的項目。

3.4 截圖和文字兩種給法:抓到的差不多,輸入是 2.3 倍

項目 給截圖(廣告圖+三段截圖) 給文字(廣告圖+頁面文字)
抓到的計分落差 18/21 20/21
沒有計分落差卻被多列的廣告圖 0/6 0/6
有爭議的 9 列被列出來 8 4
填 other 的項目 0 1(徽章「新品」)
平均每次輸入 Token 4,998 2,148
平均每次輸出 Token(含思考) 123 190
24 次費用 新台幣 3.56 元 新台幣 1.96 元

兩種給法差 2 格,每一格只問了一次,而且 21 列其實是五種落差在不同圖上重複出現,這個差距不足以說文字比較準,看得出來的是兩種給法都能用,五種落差裡有四種兩種給法都抓得到,多色可選這一種給截圖 0/2、給文字 1/2,但它只有 2 列,其中一列還是字抄錯,同樣不足以下結論。

差別明確的是成本,給截圖一次是四張圖,每張大約 1,100 個 Token,光圖片就 4,400 上下,給文字只有一張圖加上幾百個字,給截圖的輸入是 4,998、給文字是 2,148,是 2.3 倍,費用是 1.8 倍,費用的倍數比較小有一部分是運氣,給文字的 24 次裡有 4 次多用了思考 Token,給截圖的只有 1 次,兩邊真正寫出來的回答長度幾乎一樣。

頁面文字拿得到的時候給文字就夠了,但文字擷取會漏掉只存在於畫面上的資訊,今天碰到的是劃掉的原價,如果沒有另外註明,文字版的 Gemini 會看到同一個商品有兩個價格,價格寫在圖片裡的橫幅也是同樣的情況,這時候截圖才派得上用場並且要記得切開。


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

  1. 第一道防線:善用 Google Cloud 每月免費額度:對照表、答案表、對答案、檢查與報表都是查詢,在 BigQuery 每月 1 TiB 的查詢免費額度內,九張頁面截圖合計不到 1 MB,在 Cloud Storage 的免費額度內
  2. 第二道防線:架構層被動成本防護:run.sh 呼叫 Gemini 前先依「這次真的要呼叫的次數」印出估價,輸入平均以每次 4,250 個 Token、輸出以上限 2,048 個 Token 計,48 次約新台幣 18.4 元,輸入 yes 才會呼叫,跑過的組合不重跑,同一輪裡緊接著的重跑呼叫 0 次
  3. 第三道防線:Cloud Billing 預算警報:沿用 Day 03 由 Terraform 建立的預算警報,50%、80%、100% 三段通知,今天的操作不會觸發
項目 呼叫次數 輸入 Token 輸出 Token(含思考) 費用
給截圖 24 119,960 2,952 新台幣 3.56 元
給文字 24 51,560 4,557 新台幣 1.96 元
合計 48 171,520 7,509 新台幣 5.52 元

費用依 gemini-3.6-flash 非 global 端點的單價(輸入每百萬 Token 0.825 美元、輸出 4.125 美元)與實際 Token 數算出,匯率以 1 美元約 32 元計,實付不到估價的三分之一,因為回答都很短,平均每次輸出只有一百多個 Token,估價是用輸出上限算的,48 次都記進 Day 16 建的共用用量表 ops_llm_usage。


5. Cloud Shell 實戰演練:一行指令從截圖到成績

5.1 事前準備

  • 先在 ~/ai-driven-martech-pipeline 執行 git pull,取得 Day 19 的 consistency/ 目錄與 creatives/landing/ 的九張截圖
  • gcloud config get-value project 要印出你的專案 ID
  • 已完成 Day 07(dim_creative)、Day 11(答案資料集 martech_gt)與 Day 14(素材 bucket 與物件表 obj_creatives)
  • 確認 gcloud 有登入中的帳號,輸入 gcloud auth list,帳號前面要有星號

5.2 路線 A|懶人包:一行指令跑完

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

run.sh 先把九張截圖上傳到素材 bucket,建好頁面文字、截圖物件表、對照表和答案表,印出這次要呼叫幾次和估價,輸入 yes 才會呼叫 Gemini,接著馬上重跑一次確認不重複收費,最後是對答案、14 項檢查和八段報表。

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

步驟 1:頁面與答案

cd ~/ai-driven-martech-pipeline
PROJECT_ID=$(gcloud config get-value project)
gcloud storage cp creatives/landing/*.jpg gs://${PROJECT_ID}-martech-assets/landing/
sed "s/PROJECT_ID/${PROJECT_ID}/g" consistency/pages.sql | bq query --nouse_legacy_sql --format=pretty
bq query --nouse_legacy_sql --format=pretty < consistency/answers.sql

pages.sql 建立頁面文字 ref_landing_pages、截圖物件表 obj_landing 和對照表 map_creative_landing,answers.sql 把 30 列答案寫進 martech_gt.gt_ad_page_gaps,這兩步都不呼叫 Gemini。

步驟 2:比對

bq query --nouse_legacy_sql --format=pretty < consistency/compare.sql

這一步會呼叫 Gemini,48 次約新台幣 5.5 元,直接執行不會先問,只補還沒成功的組合,印出兩種給法各呼叫幾次、成功幾次和 Token 數。

步驟 3:對答案、檢查與報表

bq query --nouse_legacy_sql --format=pretty < consistency/score.sql
bq query --nouse_legacy_sql --format=pretty < consistency/check.sql
bq query --nouse_legacy_sql --format=pretty --max_rows=200 < consistency/report.sql

score.sql 把每一格判成抓到、漏掉、多列、有爭議或其他,放進 mart_ad_page_gaps,check.sql 是 12 項流程檢查,另外兩項由 run.sh 補上,一項確認緊接著的重跑沒有重複呼叫,一項用 grep 確認準備題目與呼叫 Gemini 的 SQL 沒有讀答案資料集,report.sql 八段分別是對照表、總成績、各種落差、漏掉與多列的原文、有爭議的列、填 other 的原文、兩種給法逐格比較與費用。

5.4 驗證成果

  • mm_gaps_log 48 列,image、text 各 24 列,finish_reason 沒有 MAX_TOKENS
  • 報表第 2 段兩種給法的 clean_flagged(沒有計分落差卻被多列的張數)與 decoy(清單上兩種不存在的落差被填的次數)都是 0
  • run.sh 的 14 項檢查全部通過,緊接著的重跑呼叫 0 次

Gemini 每次的回答不會完全一樣,你跑出來抓到的格數可能和這裡不同。

5.5 用完後怎麼處理

mart_ad_page_gaps、mm_gaps_log 和答案表都留著,素材 bucket 的 landing/ 資料夾九張截圖不到 1 MB,不需要的話可以自己刪掉,題目改過之後想重問,先把 mm_gaps_log 改名留存再執行,成功過的組合不會因為題目變了就自動重問。


6. 工程實務避坑指南

  1. 長截圖要先切開:一張圖的 Token 數大致固定,整頁長截圖丟進去小字可能讀不到,今天沒有實測,只用縮圖看過,照畫面內容切成幾段,相鄰兩段留一點重疊,不要剛好切在一行字或一張商品卡中間
  2. 純文字看不到刪除線:從頁面擷取文字時,劃掉的原價和現價會變成並排的兩個數字,擷取時要把這類只存在於樣式裡的資訊寫成文字
  3. 抓到落差不等於理由正確:短襪對中筒襪 8 張都抓到,導到重訓活動頁的那幾次引用的卻多半是另一個商品,交給人處理之前,頁面證據那一欄要一起看
  4. 抄錯一個字就對不上答案:「多色可選」被抄成「多色選」,對答案的規則是抄下來的文字要包含那個詞,這一格就變成漏掉加多列,規則是事先定好的所以照算,報表把原文印出來才看得出真正的原因
  5. 清單會決定它查什麼:題目把要查的五種落差直接列出來,量到的是照清單檢查的能力,清單以外的落差今天唯一看得到的例子是「新品」,首頁沒有任何地方說是新品,徽章寫「新品」的 5 張圖兩種給法共 10 次,只有 1 次被填進 other

7. 總結與明日預告

今天把 24 張廣告圖和它們導去的三個頁面交給 gemini-3.6-flash,在 BigQuery 裡一次給多張圖做比對,事先寫好的 21 個落差,給截圖抓到 18 個、給文字抓到 20 個,6 張沒有計分落差的廣告圖除了有爭議的名稱差異(給截圖列了 2 張)之外沒有被多列,清單上兩種不存在的落差也沒有被硬填,48 次呼叫合計約新台幣 5.5 元。

回到篇名,廣告說一套、網站寫一套這種事 AI 抓得出來,免運少了門檻、專案價找不到優惠、短襪變成中筒襪都被列出來了,但它引用的頁面證據有時候指錯商品,名稱不完全一樣這種見仁見智的項目也會一起列出來,適合拿來當上線前的第一輪檢查,列出來的每一項還是要有人看過,兩種給法抓到的差不多,給截圖的輸入是給文字的 2.3 倍,頁面文字拿得到就給文字,只有畫面上才看得到的資訊再用截圖。

明日預告:Day 20《便宜的輕量模型到底夠不夠用?直接實測來看》,今天和 Day 18 用的是 gemini-3.6-flash,Day 14 到 Day 16 主要用 gemini-3.5-flash-lite,明天把同一批看圖的題目交給不同等級的模型,比正確率、速度和費用。


上一篇
Day 18 | 靈感卡關時,讓 Gemini 根據成效幫你打下一版素材草稿
下一篇
Day 20 | 便宜的輕量模型到底夠不夠用?直接實測來看
系列文
AI-Driven MarTech:用 Google Cloud + Vertex AI 打造全自動廣告歸因與多模態素材分析系統 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言