AIO / GEO - Part 5 - 量測與案例篇:建立監測系統與六個月實戰復盤

大多數人的做法:改完網站,等三個月,然後憑感覺說「好像有效」。 真正該做的事:在改之前先量基線,改之後每週量一次,把「哪一次改動讓哪一題上升」講清楚。

GEO 最大的風險不是做錯,是做完不知道有沒有用, 於是第二季預算被砍掉。


一、為什麼傳統分析工具在這裡失效

你想知道的                     GA4 能告訴你          GSC 能告訴你
──────────────────────────────────────────────────────────────────
ChatGPT 提到我幾次?            ✘                    ✘
Perplexity 引用了我哪一頁?      部分(有 referrer)    ✘
AI Overview 有沒有引用我?       ✘                    ✘(曝光混在一起)
模型怎麼描述我的產品?           ✘                    ✘
競品的引用份額是多少?           ✘                    ✘

核心問題:AI 引用大多不產生可歸因的流量

使用者旅程的真實樣貌

Day 1   問 ChatGPT「台灣有哪些 OMS 系統」
        → 答案中提到 OrderFlow,附連結
        → 使用者沒有點連結,只是記住了名字
        → GA4:無任何紀錄

Day 4   在 Perplexity 問「OrderFlow 好用嗎」
        → 讀了摘要,點了一個連結
        → GA4:referrer = perplexity.ai(唯一看得到的一次)

Day 11  直接 Google 搜尋「OrderFlow 價格」
        → 點進官網定價頁
        → GA4:Organic Search,query = 品牌詞

Day 14  填表單
        → GA4 歸因:Organic Search / 品牌詞

真正的第一因是 Day 1 的 ChatGPT,但它在報表上完全不存在。

結論:你必須主動去問模型,而不是被動等流量。這就是監測系統要做的事。


二、指標體系

2.1 主指標:AI Visibility Score

AVS = 0.30 × 引用頻率
    + 0.30 × 引用份額
    + 0.25 × 位置加權分
    + 0.15 × 描述正確率

其中:
  引用頻率   = 被引用的題數 / 總題數
  引用份額   = Σ(你的引用數) / Σ(所有品牌的引用數)
  位置加權分 = 平均 1/log2(提及位置 + 1),位置以「第幾個被提到的品牌」計
  描述正確率 = 對你的事實陳述中正確的比例(需人工或 LLM 標註)

2.2 輔助指標

指標                    定義                          健康值      用途
────────────────────────────────────────────────────────────────────────
Coverage Gap            prompt set 中你完全沒有        < 15%      找內容缺口
                        對應頁面的題數比例

Answer Leakage          被引用但描述有誤的比例          < 10%      找內容歧義
                                                                (比不被引用更嚴重)

Competitor Delta        你的份額 - 最大競品的份額       > 0        競爭態勢

Page Concentration      引用集中在前 3 個 URL 的比例    < 60%      過度集中代表
                                                                其他頁沒發揮

Engine Variance         各引擎間引用率的標準差          < 15pp     差異大代表
                                                                某引擎有技術問題

Brand Search Lift       品牌詞搜尋量的月成長            > 0        GEO 的下游效果

Engine Variance 特別有用:如果 Perplexity 引用率 32%、ChatGPT 引用率 4%,那幾乎一定是 OAI-SearchBot 被擋了,而不是內容問題。這個指標能把「內容問題」和「技術問題」分開。


三、Prompt Set 設計

監測系統的品質上限,取決於 prompt set 的品質。

3.1 五類問題,各有配額

類別            佔比    範例                              量什麼
──────────────────────────────────────────────────────────────────────
① 品類發現      30%    「台灣有哪些訂單管理系統?」          你在不在名單裡
                       「多通路電商用什麼工具管訂單?」       ← 最重要的一類

② 問題解決      25%    「蝦皮和 momo 的訂單怎麼統一管理?」   你的內容有沒有被引用
                       「電商庫存超賣怎麼解決?」

③ 品牌直問      20%    「OrderFlow 是什麼?」               描述正確率
                       「OrderFlow 的定價?」               ← 錯誤最傷的一類

④ 競品比較      15%    「OrderFlow vs 易普印 哪個好?」      競爭位置
                       「OMS 選型該看什麼?」

⑤ 長尾具體      10%    「OrderFlow 支援蝦皮直播訂單嗎?」    深度內容是否被讀到
                       「OMS 導入要多少錢?」

3.2 數量與變體

建議規模:40-60 題(含變體後 120-180 次查詢/輪)

每題要有 2-3 個變體:
  基本:「台灣有哪些訂單管理系統?」
  口語:「我開網店,訂單太多管不動,有什麼系統推薦?」
  英文:「What are the best OMS platforms in Taiwan?」

  → 變體能測出你的語意覆蓋廣度(Part 3 §2 規則 1 的驗證)

3.3 定義檔格式

 1# prompts.yaml
 2brand: "OrderFlow"
 3aliases: ["OrderFlow", "orderflow.tw", "訂單流"]
 4competitors:
 5  - { name: "易普印", aliases: ["易普印", "EasyPrint"] }
 6  - { name: "SHOPLINE", aliases: ["SHOPLINE", "shopline.tw"] }
 7  - { name: "91APP", aliases: ["91APP", "九一"] }
 8
 9prompts:
10  - id: DISC-001
11    category: discovery
12    text: "台灣有哪些多通路電商訂單管理系統(OMS)?請列出主要選項。"
13    variants:
14      - "我在台灣做電商,蝦皮 momo 官網都有賣,有什麼系統可以統一管訂單?"
15      - "What OMS platforms are available for Taiwanese e-commerce sellers?"
16    target_url: "/product/"
17
18  - id: PROB-014
19    category: problem
20    text: "多通路電商如何避免庫存超賣?"
21    variants:
22      - "蝦皮和官網同時賣,庫存不同步怎麼辦?"
23    target_url: "/blog/inventory-sync/"
24
25  - id: BRAND-003
26    category: brand
27    text: "OrderFlow 的定價方案是什麼?"
28    facts:                      # 用於描述正確率評分
29      - "基本版每月 NT$500"
30      - "專業版每月 NT$1,500"
31      - "提供 14 天免費試用"
32    target_url: "/pricing/"

四、監測系統實作

4.1 架構

┌──────────────┐
│ prompts.yaml │
└──────┬───────┘
       ▼
┌────────────────────────────────────────────────────┐
│  Runner(每週一次,或改版後立即跑)                   │
│  ┌──────────┬──────────┬──────────┬──────────┐    │
│  │ OpenAI   │ Anthropic│Perplexity│  手動     │    │
│  │ (web     │ (web     │ (Sonar   │  AI       │    │
│  │  search) │  search) │  API)    │  Overview │    │
│  └────┬─────┴────┬─────┴────┬─────┴────┬─────┘    │
└───────┼──────────┼──────────┼──────────┼──────────┘
        └──────────┴────┬─────┴──────────┘
                        ▼
        ┌───────────────────────────────┐
        │  Parser:抽取答案文字 + 引用 URL │
        └───────────────┬───────────────┘
                        ▼
        ┌───────────────────────────────┐
        │  Scorer:品牌命中、位置、份額    │
        │          + LLM 判斷描述正確率   │
        └───────────────┬───────────────┘
                        ▼
        ┌───────────────────────────────┐
        │  Store:SQLite / BigQuery      │
        │  一列 = (日期, 引擎, 題目, 結果) │
        └───────────────┬───────────────┘
                        ▼
        ┌───────────────────────────────┐
        │  Report:AVS 趨勢圖 + 逐題明細  │
        └───────────────────────────────┘

4.2 核心程式碼

  1#!/usr/bin/env python3
  2"""geo_monitor.py —— 多引擎 GEO 引用監測。
  3
  4用法:
  5  python3 geo_monitor.py run    --config prompts.yaml --db geo.db
  6  python3 geo_monitor.py report --db geo.db --weeks 12
  7"""
  8from __future__ import annotations
  9import argparse, json, os, re, sqlite3, math, datetime as dt
 10from dataclasses import dataclass, asdict
 11from urllib.parse import urlparse
 12
 13import yaml  # pip install pyyaml
 14
 15
 16# ────────────────────────────── 資料模型 ──────────────────────────────
 17@dataclass
 18class Result:
 19    run_date: str
 20    engine: str
 21    prompt_id: str
 22    category: str
 23    prompt_text: str
 24    answer: str
 25    citations: str          # JSON list of URLs
 26    brand_mentioned: int
 27    brand_cited: int
 28    mention_position: int   # 第幾個被提到的品牌,0 = 未提及
 29    competitor_hits: str    # JSON dict
 30    accuracy: float         # 0-1,-1 表示不適用
 31
 32
 33# ────────────────────────────── 引擎介接 ──────────────────────────────
 34def ask_openai(prompt: str) -> tuple[str, list[str]]:
 35    """使用 OpenAI Responses API 的 web_search 工具。"""
 36    from openai import OpenAI
 37    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
 38    r = client.responses.create(
 39        model="gpt-4.1",
 40        tools=[{"type": "web_search"}],
 41        input=prompt,
 42    )
 43    text = r.output_text
 44    urls = []
 45    for item in getattr(r, "output", []) or []:
 46        for c in getattr(item, "content", []) or []:
 47            for ann in getattr(c, "annotations", []) or []:
 48                u = getattr(ann, "url", None)
 49                if u:
 50                    urls.append(u)
 51    return text, list(dict.fromkeys(urls))
 52
 53
 54def ask_anthropic(prompt: str) -> tuple[str, list[str]]:
 55    """使用 Claude 的 web_search 工具。"""
 56    import anthropic
 57    client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
 58    msg = client.messages.create(
 59        model="claude-sonnet-5",
 60        max_tokens=2048,
 61        tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 6}],
 62        messages=[{"role": "user", "content": prompt}],
 63    )
 64    text, urls = [], []
 65    for block in msg.content:
 66        if block.type == "text":
 67            text.append(block.text)
 68            for cit in (getattr(block, "citations", None) or []):
 69                u = getattr(cit, "url", None)
 70                if u:
 71                    urls.append(u)
 72        elif block.type == "web_search_tool_result":
 73            for item in (block.content or []):
 74                u = getattr(item, "url", None)
 75                if u:
 76                    urls.append(u)
 77    return "\n".join(text), list(dict.fromkeys(urls))
 78
 79
 80def ask_perplexity(prompt: str) -> tuple[str, list[str]]:
 81    import requests
 82    r = requests.post(
 83        "https://api.perplexity.ai/chat/completions",
 84        headers={"Authorization": f"Bearer {os.environ['PERPLEXITY_API_KEY']}"},
 85        json={"model": "sonar-pro", "messages": [{"role": "user", "content": prompt}]},
 86        timeout=90,
 87    )
 88    r.raise_for_status()
 89    d = r.json()
 90    return d["choices"][0]["message"]["content"], d.get("citations", [])
 91
 92
 93ENGINES = {
 94    "openai": ask_openai,
 95    "anthropic": ask_anthropic,
 96    "perplexity": ask_perplexity,
 97}
 98
 99
100# ────────────────────────────── 評分 ──────────────────────────────
101def first_position(answer: str, brand_aliases: list[str],
102                   competitors: list[dict]) -> int:
103    """回傳品牌在答案中是第幾個被提到的(1-based),未提及回 0。"""
104    def first_idx(aliases):
105        idxs = [answer.find(a) for a in aliases if answer.find(a) >= 0]
106        return min(idxs) if idxs else math.inf
107
108    mine = first_idx(brand_aliases)
109    if mine is math.inf:
110        return 0
111    others = [first_idx(c["aliases"]) for c in competitors]
112    return 1 + sum(1 for o in others if o < mine)
113
114
115def cited(urls: list[str], domain: str) -> bool:
116    return any(domain in (urlparse(u).netloc or "") for u in urls)
117
118
119def judge_accuracy(answer: str, facts: list[str]) -> float:
120    """用 LLM 判斷答案中對本品牌的陳述是否與已知事實一致。"""
121    if not facts:
122        return -1.0
123    import anthropic
124    client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
125    prompt = (
126        "以下是一段 AI 回答,以及一組已知為真的事實。\n"
127        "請判斷回答中關於該品牌的陳述,有多少比例與事實一致。\n"
128        "只輸出一個 0 到 1 之間的小數,不要其他文字。\n"
129        "若回答完全沒有提及該品牌,輸出 -1。\n\n"
130        f"【已知事實】\n" + "\n".join(f"- {f}" for f in facts) +
131        f"\n\n【AI 回答】\n{answer[:4000]}"
132    )
133    m = client.messages.create(
134        model="claude-sonnet-5", max_tokens=16,
135        messages=[{"role": "user", "content": prompt}],
136    )
137    try:
138        return float(re.search(r"-?\d*\.?\d+", m.content[0].text).group())
139    except (AttributeError, ValueError):
140        return -1.0
141
142
143# ────────────────────────────── 儲存 ──────────────────────────────
144SCHEMA = """
145CREATE TABLE IF NOT EXISTS results (
146  run_date TEXT, engine TEXT, prompt_id TEXT, category TEXT,
147  prompt_text TEXT, answer TEXT, citations TEXT,
148  brand_mentioned INT, brand_cited INT, mention_position INT,
149  competitor_hits TEXT, accuracy REAL,
150  PRIMARY KEY (run_date, engine, prompt_id)
151);
152"""
153
154
155def save(db: str, rows: list[Result]):
156    con = sqlite3.connect(db)
157    con.executescript(SCHEMA)
158    con.executemany(
159        "INSERT OR REPLACE INTO results VALUES "
160        "(:run_date,:engine,:prompt_id,:category,:prompt_text,:answer,"
161        ":citations,:brand_mentioned,:brand_cited,:mention_position,"
162        ":competitor_hits,:accuracy)",
163        [asdict(r) for r in rows],
164    )
165    con.commit()
166    con.close()
167
168
169# ────────────────────────────── 執行 ──────────────────────────────
170def run(cfg_path: str, db: str, engines: list[str]):
171    cfg = yaml.safe_load(open(cfg_path, encoding="utf-8"))
172    domain = cfg.get("domain", "orderflow.tw")
173    aliases = cfg["aliases"]
174    comps = cfg["competitors"]
175    today = dt.date.today().isoformat()
176    rows: list[Result] = []
177
178    for p in cfg["prompts"]:
179        texts = [p["text"]] + p.get("variants", [])
180        for engine in engines:
181            fn = ENGINES[engine]
182            for vi, text in enumerate(texts):
183                pid = p["id"] if vi == 0 else f"{p['id']}-v{vi}"
184                try:
185                    answer, urls = fn(text)
186                except Exception as e:
187                    print(f"  ! {engine} {pid}: {e}")
188                    continue
189
190                pos = first_position(answer, aliases, comps)
191                hits = {
192                    c["name"]: any(a in answer for a in c["aliases"])
193                    for c in comps
194                }
195                acc = judge_accuracy(answer, p.get("facts", [])) if pos else -1.0
196
197                rows.append(Result(
198                    run_date=today, engine=engine, prompt_id=pid,
199                    category=p["category"], prompt_text=text, answer=answer,
200                    citations=json.dumps(urls, ensure_ascii=False),
201                    brand_mentioned=int(pos > 0),
202                    brand_cited=int(cited(urls, domain)),
203                    mention_position=pos,
204                    competitor_hits=json.dumps(hits, ensure_ascii=False),
205                    accuracy=acc,
206                ))
207                print(f"  {engine:<11} {pid:<14} 提及={'✔' if pos else '✘'} "
208                      f"位置={pos} 引用={'✔' if cited(urls, domain) else '✘'}")
209
210    save(db, rows)
211    print(f"\n已寫入 {len(rows)} 筆 → {db}")
212
213
214# ────────────────────────────── 報表 ──────────────────────────────
215def report(db: str, weeks: int):
216    con = sqlite3.connect(db)
217    con.row_factory = sqlite3.Row
218    dates = [r[0] for r in con.execute(
219        "SELECT DISTINCT run_date FROM results ORDER BY run_date DESC LIMIT ?",
220        (weeks,))][::-1]
221
222    print(f"\n{'日期':<12}{'題數':>6}{'提及率':>9}{'引用率':>9}"
223          f"{'位置分':>9}{'正確率':>9}{'AVS':>8}")
224    print("─" * 64)
225
226    for d in dates:
227        rs = list(con.execute("SELECT * FROM results WHERE run_date=?", (d,)))
228        n = len(rs)
229        if not n:
230            continue
231        mention = sum(r["brand_mentioned"] for r in rs) / n
232        citation = sum(r["brand_cited"] for r in rs) / n
233        positions = [r["mention_position"] for r in rs if r["mention_position"] > 0]
234        posscore = (sum(1 / math.log2(p + 1) for p in positions) / len(positions)
235                    if positions else 0.0)
236        accs = [r["accuracy"] for r in rs if r["accuracy"] >= 0]
237        acc = sum(accs) / len(accs) if accs else 0.0
238
239        # 引用份額:本品牌提及數 / (本品牌 + 所有競品) 提及數
240        comp_total = 0
241        for r in rs:
242            comp_total += sum(1 for v in json.loads(r["competitor_hits"]).values() if v)
243        mine = sum(r["brand_mentioned"] for r in rs)
244        share = mine / (mine + comp_total) if (mine + comp_total) else 0.0
245
246        avs = 100 * (0.30 * citation + 0.30 * share + 0.25 * posscore + 0.15 * acc)
247        print(f"{d:<12}{n:>6}{mention:>8.0%}{citation:>9.0%}"
248              f"{posscore:>9.2f}{acc:>9.0%}{avs:>8.1f}")
249
250    # 逐題:最近一次 vs 上一次
251    if len(dates) >= 2:
252        cur, prev = dates[-1], dates[-2]
253        print(f"\n逐題變化({prev}{cur})")
254        print("─" * 64)
255        q = ("SELECT prompt_id, category, AVG(brand_cited) c "
256             "FROM results WHERE run_date=? GROUP BY prompt_id")
257        a = {r["prompt_id"]: r for r in con.execute(q, (prev,))}
258        b = {r["prompt_id"]: r for r in con.execute(q, (cur,))}
259        deltas = sorted(
260            ((k, b[k]["c"] - a.get(k, {"c": 0})["c"], b[k]["category"]) for k in b),
261            key=lambda x: x[1])
262        for pid, d_, cat in deltas[:5]:
263            if d_ < 0:
264                print(f"  ↓ {pid:<16} {cat:<12} {d_:+.0%}")
265        for pid, d_, cat in deltas[-5:]:
266            if d_ > 0:
267                print(f"  ↑ {pid:<16} {cat:<12} {d_:+.0%}")
268    con.close()
269
270
271if __name__ == "__main__":
272    ap = argparse.ArgumentParser()
273    ap.add_argument("cmd", choices=["run", "report"])
274    ap.add_argument("--config", default="prompts.yaml")
275    ap.add_argument("--db", default="geo.db")
276    ap.add_argument("--engines", default="openai,anthropic,perplexity")
277    ap.add_argument("--weeks", type=int, default=12)
278    a = ap.parse_args()
279    if a.cmd == "run":
280        run(a.config, a.db, a.engines.split(","))
281    else:
282        report(a.db, a.weeks)

4.3 成本

規模:50 題 × 2.4 變體 × 3 引擎 = 360 次查詢/輪

項目                      單價(概估)      每輪成本
──────────────────────────────────────────────────
帶 web search 的生成       $0.02-0.05/次   $7-18
準確率評分(小模型)        $0.002/次       $0.7
──────────────────────────────────────────────────
每輪合計                                    約 $8-19
每週一次 → 每月                              約 $32-76

這是整個 GEO 專案中最便宜、也最不該省的一筆。 沒有它,你無法向管理層證明任何事。

4.4 AI Overview 的處理

AI Overview 沒有官方 API。三個選擇:

方法                    可靠度    成本      建議
────────────────────────────────────────────────────────
第三方 SERP API          高       $50-300/月  推薦,多數已支援 AI Overview 欄位
自建瀏覽器自動化          中       工程時間     易被反爬,維護成本高
人工每月抽查 20 題        中       2 小時/月    小團隊的務實選擇

務實建議:API 監測涵蓋 ChatGPT / Claude / Perplexity(可程式化的部分),AI Overview 用人工每月抽查 20 題。趨勢方向通常一致,不需要三個都自動化。


五、從流量側辨識 AI 曝光

程式化監測看的是「模型怎麼說」,流量側看的是「有沒有人來」。兩者互補。

5.1 伺服器日誌:AI crawler 活動

crawler 抓取頻率是「引擎對你有多少興趣」的領先指標,通常領先引用率變化 2-4 週。

 1# 從 nginx log 統計各 AI bot 的抓取量與熱門頁
 2awk '{print $0}' /var/log/nginx/access.log \
 3| grep -Ei "GPTBot|OAI-SearchBot|ClaudeBot|Claude-SearchBot|PerplexityBot|Applebot|Bytespider" \
 4| awk '{
 5    ua="other";
 6    if ($0 ~ /OAI-SearchBot/) ua="OAI-SearchBot";
 7    else if ($0 ~ /GPTBot/) ua="GPTBot";
 8    else if ($0 ~ /Claude-SearchBot/) ua="Claude-SearchBot";
 9    else if ($0 ~ /ClaudeBot/) ua="ClaudeBot";
10    else if ($0 ~ /PerplexityBot/) ua="PerplexityBot";
11    else if ($0 ~ /Applebot/) ua="Applebot";
12    print ua, $9, $7
13  }' \
14| sort | uniq -c | sort -rn | head -40

要盯的三件事:

訊號                        意義
──────────────────────────────────────────────────────────
某 bot 的 4xx/5xx 比例上升    存取層出問題 → 立刻查 CDN
某 bot 抓取量歸零             被封鎖或被降級 → 查 WAF 規則變更
抓取集中在少數頁              其他頁沒被發現 → 查 sitemap 與內部連結
抓取量在改版後大增             正向訊號,通常 2-4 週後反映在引用率

5.2 GA4:AI referral 流量

AI 引用帶來的點擊會有 referrer,只是量小、且預設被歸到「Referral」裡看不清楚。

建立一個自訂維度來分流:

 1// 在 GTM 或 gtag 設定中,把 AI 來源標記出來
 2(function () {
 3  var ref = document.referrer || '';
 4  var AI_SOURCES = {
 5    'chatgpt.com': 'ChatGPT',
 6    'chat.openai.com': 'ChatGPT',
 7    'perplexity.ai': 'Perplexity',
 8    'claude.ai': 'Claude',
 9    'copilot.microsoft.com': 'Copilot',
10    'gemini.google.com': 'Gemini',
11    'you.com': 'You.com',
12    'phind.com': 'Phind',
13  };
14  var src = null;
15  for (var host in AI_SOURCES) {
16    if (ref.indexOf(host) !== -1) { src = AI_SOURCES[host]; break; }
17  }
18  // 部分引擎會帶 utm 參數
19  var params = new URLSearchParams(location.search);
20  if (!src && /chatgpt|perplexity|claude|copilot/i.test(params.get('utm_source') || '')) {
21    src = params.get('utm_source');
22  }
23  if (src) {
24    gtag('event', 'ai_referral', {
25      ai_source: src,
26      landing_page: location.pathname,
27      // 設為 user property,讓後續轉換也能歸因
28      send_to: 'G-XXXXXXX',
29    });
30    gtag('set', 'user_properties', { first_ai_source: src });
31  }
32})();

GA4 探索報表的設定:

維度:ai_source, landing_page
指標:工作階段、參與率、平均參與時間、轉換
篩選:ai_referral 事件不為空

要看的是:AI 來的流量「品質」通常明顯高於一般 organic
  ——因為使用者已經在 AI 那邊被預先篩選過一輪。

5.3 品牌詞搜尋量:真正的下游指標

因為多數 AI 曝光是零點擊的,品牌詞搜尋量的成長才是 GEO 生效的最強證據

在 GSC 建立一個「品牌詞」篩選(query 包含 brand 名稱及變體),
每月記錄:
  • 品牌詞曝光數
  • 品牌詞點擊數
  • 品牌詞佔總 organic 的比例

搭配 Direct 流量的變化一起看。

如果:AI 引用率 ↑ + 品牌詞搜尋 ↑ + Direct ↑,而一般關鍵字流量持平或微降
→ 這就是 GEO 生效的典型形狀(流量結構在轉移,不是消失)

六、實戰案例 A:B2B SaaS 站的六個月

6.1 起點

公司:一家台灣的 B2B 排程/派工 SaaS(30 人,年營收約 NT$8,000 萬)
網站:Next.js(App Router,但大量 client component)
內容:87 篇部落格、12 個產品頁、1 個文件站

基線量測(2026 年 1 月第 1 週,50 題 × 3 引擎)
──────────────────────────────────────────────
提及率            18%
引用率             6%
引用份額          11%
位置加權分         0.31
描述正確率        52%   ← 模型講的定價是兩年前的
AVS               17.4

Coverage Gap      42%   ← 一半的題目沒有對應頁面
Engine Variance   21pp  ← Perplexity 19%、ChatGPT 2% ← 紅旗

Engine Variance 21pp 立刻指向技術問題,不是內容問題。

6.2 診斷(Week 1-2)

1$ ./ai-crawler-check.sh https://example.com/blog/scheduling-guide/
2USER-AGENT             CODE   BYTES      SERVER
3GPTBot/1.0             403    0          cloudflare
4OAI-SearchBot/1.0      403    0          cloudflare
5ChatGPT-User/1.0       403    0          cloudflare
6ClaudeBot/1.0          403    0          cloudflare
7PerplexityBot/1.0      200    148231     cloudflare
8Googlebot/2.1          200    148231     cloudflare
9bingbot/2.0            200    148231     cloudflare

原因:Cloudflare 的「Block AI Scrapers and Crawlers」開著,而 PerplexityBot 因為當時走另一個判定路徑漏過去了。這個開關是半年前某次資安檢視時打開的,沒有人記得。

第二個問題:

瀏覽器文字量:4,180 字
curl 文字量(Googlebot):1,090 字(26%)

主要內容包在 'use client' 元件裡,靠 useEffect 抓資料。Googlebot 因為會執行 JS 所以看得到,但即使是 Googlebot 也只拿到部分。

6.3 執行時序與逐月數據

月份    主要動作                                    AVS    引用率  正確率
──────────────────────────────────────────────────────────────────────
1月     基線量測                                    17.4    6%     52%
        關閉 Cloudflare AI 封鎖 + 加 WAF skip 規則

2月     內容頁改 SSG(generateStaticParams)         24.1   11%     55%
        Organization / Article / FAQPage JSON-LD
        修正 dateModified(原本是 build time)

3月     20 篇核心文章重寫(九條規則)                 31.8   17%     58%
        標題改問句、加 TL;DR、補數據與日期

4月     補 9 篇內容缺口(Coverage Gap 42% → 19%)    38.2   22%     61%
        每篇加比較表 + FAQ

5月     定價頁大改:把價格寫成 HTML 表格(原本是      44.6   26%     84%
        設計稿圖片)+ Product schema
        ← 正確率從 61% 跳到 84%,單一改動效果最大

6月     Wikidata 條目、G2 檔案、3 篇產業媒體投稿      49.3   29%     86%
        Reddit / 社群的真實討論開始出現

6.4 哪些有效、哪些沒效

動作                            AVS 貢獻    成本(人天)   投報率
────────────────────────────────────────────────────────────────
解除 Cloudflare AI 封鎖          +6.7        0.5         ★★★★★
定價表從圖片改成 HTML 表格        +6.4        1           ★★★★★
20 篇核心文章重寫                +7.7        22          ★★★☆☆
內容頁改 SSG                     +3.2        6           ★★★★☆
補 9 篇內容缺口                  +6.4        14          ★★★★☆
JSON-LD 全套                     +2.1        3           ★★★☆☆
實體層(Wikidata / G2 / 媒體)    +4.7        12(+持續)  ★★★☆☆
────────────────────────────────────────────────────────────────
沒有可測量效果的動作:
  • 把 87 篇舊文全部加 FAQ(只有核心 20 篇有效,長尾無感)  -8 人天
  • Core Web Vitals 從 72 分優化到 94 分                    -5 人天
  • llms.txt / llms-full.txt                               -0.5 人天
  • 大量內部連結補強                                        -3 人天

兩個最重要的教訓

  1. 最大的兩筆收益來自「修 bug」,不是「做內容」。半天的 Cloudflare 設定,效果超過三週的內容重寫。先做 Layer 1 這件事不是理論,是實測。

  2. 「全站一起做」是浪費。87 篇文章全加 FAQ 花了 8 人天,效果為零;20 篇核心文章的重寫才有效。用 prompt set 決定要改哪些頁,不要平均分配資源。

6.5 商業結果

指標                    1 月        6 月       變化
────────────────────────────────────────────────────
AI referral 工作階段     310        2,840     +816%
AI referral 轉換率       —          4.8%      (一般 organic 為 1.9%)
品牌詞曝光(GSC)        12,400     29,600    +139%
Direct 工作階段          8,900      14,200    +60%
一般關鍵字 organic       41,200     38,700    -6%
──────────────────────────────────────────────────
MQL 總數                 142        219       +54%
其中「來源不明/直接」    38%        51%       ← 歸因困難度上升

最後一列值得注意:GEO 成功的副作用是歸因變差。越多人因為 AI 而認識你,越多轉換會被歸到 Direct。這在向管理層報告時必須先講清楚,否則會被質疑「這些是自然成長」。

應對方法:在表單加一題「您怎麼知道我們的?」,選項包含「ChatGPT / Claude / Perplexity 等 AI 工具」。這是最便宜也最可靠的歸因補強。該公司加了這一題之後,6 月有 17% 的 MQL 選了 AI 工具。


七、實戰案例 B:本地服務業(對照組)

不是每個產業的結果都一樣。這是一個效果較弱的案例,用來校準期待。

公司:北部一家連鎖牙醫(6 家分院)
起點 AVS:8.2
6 個月後:19.4(+11.2)

有效的:
  ✔ LocalBusiness / Dentist schema + 每家分院獨立頁
  ✔ 診療項目頁改成問句式標題(「植牙一顆多少錢?」)
  ✔ 明確標示價格區間(原本寫「請來電洽詢」)  ← 效果最大
  ✔ Google Business Profile 與官網資訊完全一致

無效的:
  ✘ 大量衛教文章(醫療 YMYL 主題,模型強烈偏好
     衛福部、醫學會、大型醫院的內容——這是合理的)
  ✘ 醫師介紹頁(除非醫師本人有學會職務或論文)

結論:YMYL 領域(醫療、金融、法律)的 GEO 天花板明顯較低,
      權威來源的優先權遠高於任何內容優化。
      資源應該放在「交易型與在地型查詢」,不是「知識型查詢」。

這個對照很重要:如果你在 YMYL 領域,設定「引用率 30%」的目標是不切實際的。合理目標是在「XX 地區有哪些 XX」這類在地與交易型查詢上取得高份額。


八、ROI 試算

六個月投入(案例 A)
────────────────────────────────────────────────
工程                 12 人天 × NT$8,000  =  NT$ 96,000
內容                 48 人天 × NT$5,000  =  NT$240,000
實體層 / PR          12 人天 × NT$6,000  =  NT$ 72,000
監測 API 費用        6 個月 × NT$1,800   =  NT$ 10,800
SERP API(AI Overview)6 個月 × NT$3,000 =  NT$ 18,000
────────────────────────────────────────────────
合計                                       NT$436,800

六個月產出
────────────────────────────────────────────────
新增 MQL             +77 個(142 → 219,月均)
MQL → 成交率         8%(該公司歷史值)
新增成交             ≈ 6 個
平均客戶首年營收      NT$180,000
────────────────────────────────────────────────
新增年營收           ≈ NT$1,080,000
首年 ROI             ≈ 147%
(含續約的三年 LTV 計算,ROI 約 380%)

必須誠實標注的假設

  1. 這 77 個 MQL 中,有多少是 GEO 帶來、有多少是同期其他行銷活動的貢獻,無法完全切乾淨。表單自陳的 17% 是下限,實際可能在 25-40%。
  2. 若只算表單自陳的 17%,新增成交約 1 個,首年 ROI 為負,需要三年 LTV 才轉正。
  3. 不要在提案時只講樂觀版本。給區間,說明假設,比事後被質疑好。

保守版本的講法:

「六個月投入約 44 萬。可直接歸因的新增營收約 18 萬(首年),
  三年 LTV 約 54 萬 → 三年 ROI 約 23%。
  加上無法直接歸因但高度相關的品牌詞成長 139%,
  實際回報應高於此數,但我們不會用無法驗證的數字提案。」

九、常見的量測陷阱

陷阱                          後果                      解法
──────────────────────────────────────────────────────────────────────
只測一次就下結論               LLM 有隨機性,單次結果      同一題跑 3 次取多數;
                              波動可達 ±15pp            或固定 temperature=0

prompt set 都是品牌詞          看起來分數很高但無意義      品類發現題要佔 30%
                              (問你的名字當然提到你)

沒有記基線                     無法證明任何改動有效        改之前一定先跑一輪

改太多東西才量一次             不知道哪一項有效            每月只推 1-2 個大改動,
                                                       量完再推下一批

用不同的 prompt set 比較        趨勢完全失真               prompt set 一旦定案就凍結;
                                                       要擴充就另開一組並行

忽略 Engine Variance          花三個月改內容,其實是       每輪報表都看各引擎分項
                              某個引擎被 CDN 擋了

把「提及」當「引用」            高估成效                   分開記錄:提及 ≠ 附連結引用

沒有量描述正確率               被引用但被講錯,            brand 類題目一定要有
                              比不被引用更傷              facts 欄位做評分

十、系統效應:整個系列做完之後

面向              改造前                        改造後
──────────────────────────────────────────────────────────────────────
AI crawler 存取   4/8 被擋,無人知曉             8/8 通過,CI 每週自動驗
內容可見度        無 JS 時只有 26%               98%
被引用單位        整頁(且多半是首頁)            段落級(帶錨點的深層引用)
結構化資料        零散或缺失                     四類 schema 互相 @id 引用
內容標準          憑寫手個人習慣                  九條規則 + CI 分數門檻
新內容品質        上線後才發現問題                PR 階段就被擋下
量測能力          憑感覺                         AVS 週報 + 逐題變化
歸因能力          AI 流量完全隱形                 ai_source 維度 + 表單自陳
組織能力          一次性專案                     六個角色的固定職責

量化(案例 A,六個月)
──────────────────────────────────────────────────────────────────────
AVS               17.4                          49.3        +183%
引用率            6%                            29%         +23pp
描述正確率        52%                           86%         +34pp
Coverage Gap      42%                           11%         -31pp
Engine Variance   21pp                          4pp         技術問題消失
AI referral       310 sessions/月                2,840       +816%
品牌詞曝光        12,400                        29,600      +139%
MQL               142/月                        219/月      +54%

最後三句話

  1. 先修管線,再寫內容。 案例 A 中投報率最高的兩件事都是「修 bug」,總共花了 1.5 人天,貢獻了 27% 的 AVS 成長。在你確認 8 個 bot 都能拿到完整內容之前,不要開始寫任何新文章。

  2. 用 prompt set 決定資源分配。 平均用力是最貴的做法。87 篇文章全改的效果,不如 20 篇對的文章改到位。

  3. 量測不是為了報告,是為了下一次決策。 每週的 AVS 數字本身沒有意義;有意義的是「這一題上升了,因為上週我們改了那一頁」——這條因果鏈,才是讓 GEO 從專案變成能力的東西。


本系列文章:

Yen

Yen

Yen