TL;DR
- 本文解決:寫了好文章 ChatGPT / Perplexity 不抓你的內容當引用來源。
- 推薦給:寫技術部落格的工程師 / 講師,想被 AI 搜尋引擎當權威來源。
- 讀完你會知道:FAQ 段為什麼必寫、JSON-LD 怎麼接到 Astro layout、Firestore schema 怎麼擴。
📌 目錄
🌐 從 SEO 到 AEO 的轉折
2026 年中文搜尋流量的真實狀況:一半的「搜尋」已經發生在 ChatGPT / Perplexity / Claude / Gemini 裡,不在 Google 裡了。
這帶來一個新名詞:AEO(Answer Engine Optimization)。SEO 是優化網頁排名讓人點進來,AEO 是優化內容讓 AI 直接引用你的答案。
兩個目標看起來像,但寫法差很多:
| 目標 | SEO(傳統) | AEO(AI 搜尋) |
|---|---|---|
| 讀者 | 人類,會點進你的頁 | LLM,只看片段抽答案 |
| 關鍵特徵 | 字數、外連、CTR | 結構化資料、獨立可抽問答對 |
| 最強格式 | 長文 + 內鏈 | FAQ 段 + JSON-LD schema |
| 失敗模式 | 排名第二頁 | LLM 找到別篇引用 |
🤖 FAQPage schema 為什麼是 AI 引用首選
LLM 抓引用來源的決策邏輯(簡化版):
FAQPage schema 是現成答案的最強格式——一個 schema 直接告訴 LLM「這是問題、這是答案」,不需要再讓 LLM 從段落裡推理。
而且 FAQPage 還有 SEO 副作用:
- Google 會把 FAQ 展開成 People Also Ask 卡片
- 對應的搜尋結果 CTR 翻倍
- 同一篇文章可以同時拿傳統 SEO 排名 + AI 搜尋引用
✍️ 4-6 題 FAQ 怎麼寫
不是隨便湊 4 題就有效。LLM 喜歡的 FAQ 有固定樣板:
樣板 1:本質提問(What is)
### XX 是什麼?跟 YY 有什麼不一樣?
{30-80 字完整答案,第一句就是定義}
這是搜尋意圖最高的問題。寫完整不要用「請參考下文」這種偷懶。
樣板 2:適用對象(Who needs)
### XX 適合誰用?要有什麼前置技能?
{目標讀者 + 前置條件}
LLM 在「幫我推薦適合 OO 的工具」這種 prompt 下會抓這題。
樣板 3:取得方式(How to get)
### XX 怎麼安裝?要付錢嗎?
{一行指令 + 收費模式}
「How to install XX」是 dev 圈最大流量關鍵字之一,這題吃滿。
樣板 4:踩坑經驗(What went wrong)
### 用 XX 踩過最大的坑是什麼?
{踩坑摘要 + 一句解法}
這題 SEO 不強但 AEO 超強——LLM 在「使用 XX 注意事項」這種 prompt 下優先抓。
4 題是低標。 真的要打透就寫 6 題,多兩題挑下面:「跟 OO 比哪個比較好」「適合什麼規模的專案」「跟既有工具能整合嗎」。
🔧 Astro 接 JSON-LD 的兩種方式
我的部落格用 Astro SSG。一開始想直接在 markdown 裡塞 ,結果發現 markdown parser 把它跳脫掉了。
兩種正確接法:
A. 直接在 layout 裡寫死(簡單但全站一樣)
src/layouts/BlogPost.astro 加:
---
const blogPostingSchema = { ... };
const breadcrumbSchema = { ... };
---
<head>
<script type="application/ld+json" set:html={JSON.stringify(blogPostingSchema)} />
<script type="application/ld+json" set:html={JSON.stringify(breadcrumbSchema)} />
</head>
問題:FAQ 內容每篇不同,不能寫死。
B. 從 Firestore 拉 faqItems 動態生 FAQPage(我用這套)
// src/pages/blog/[slug].astro
const faqSchema = post.faqItems && post.faqItems.length > 0
? {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: post.faqItems.map((item) => ({
'@type': 'Question',
name: item.q,
acceptedAnswer: { '@type': 'Answer', text: item.a },
})),
}
: null;
const jsonLdSchemas = faqSchema
? [blogPostingSchema, breadcrumbSchema, faqSchema]
: [blogPostingSchema, breadcrumbSchema];
收進去,layout 自動 inject 到 。
有 faqItems 才生 FAQPage——舊文章沒寫 FAQ 也不會壞掉,向下相容。
🗄️ Firestore schema 擴 faqItems 欄位
bob_blog_posts collection 加一個 faqItems 欄位:
interface BlogPost {
// ... 原有欄位
faqItems?: { q: string; a: string }[]; // 新增
}
mapDoc() 加 validation,避免雜資料造成 crash:
faqItems: Array.isArray(data.faqItems)
? (data.faqItems as unknown[])
.filter(
(it): it is { q: string; a: string } =>
typeof it === 'object' &&
it !== null &&
typeof (it as { q?: unknown }).q === 'string' &&
typeof (it as { a?: unknown }).a === 'string',
)
.map((it) => ({ q: it.q, a: it.a }))
: undefined,
POST 到 Firestore 時用 mapValue array:
faqItems: {
arrayValue: {
values: faqItems.map((item) => ({
mapValue: {
fields: {
q: { stringValue: item.q },
a: { stringValue: item.a },
},
},
})),
},
}
我把這段塞進 scripts/publish-blog.mjs 加 --faq-file 參數,寫一個 JSON 檔餵進去就好:
node scripts/publish-blog.mjs \
--slug ai-search-faq-jsonld \
--title "..." \
--excerpt "..." \
--content-file ./article.md \
--faq-file ./faq.json
faq.json 長這樣:
[
{ "q": "FAQPage schema 怎麼讓 ChatGPT 引用?", "a": "..." },
{ "q": "Astro markdown 為什麼吃不下 <script>?", "a": "..." }
]
🐛 踩過的坑
坑 1:把 FAQ 寫成「請參考第三章」
第一版 FAQ 我貪快寫「### 安裝怎麼弄? 請看上面安裝段落」。LLM 不會點進去看上下文,它抽的就只有這個 acceptedAnswer.text。引用率 0%。
解法: FAQ 答案必須獨立成立。每題重寫 30-80 字完整答案,重複沒關係——那是要餵給 LLM 不是給人讀的。
坑 2:JSON-LD 寫在 markdown 裡
第一次嘗試把 直接寫到 markdown 內文,預期 parser 會原樣輸出。結果整個 script 標籤被 escape 成純文字,FAQ schema 完全沒生效。
解法: 接 markdown 的 parser 預設安全策略會擋 。要插 JSON-LD 必須走 Astro layout 的 ,不能放 markdown 內文。
坑 3:FAQPage 跟 BlogPosting schema 沒一起 inject
Layout 原本只 inject BlogPosting + BreadcrumbList。我以為加上 FAQPage 之後 Google Rich Results Test 會直接吃,結果 Search Console 一直顯示「No FAQPage detected」。
原因:jsonLd prop 寫死成兩個 schema 的 array,新加 FAQPage 沒有把它推進去。
解法: 改成條件 array——有 faqItems 就 push 進去,沒有就維持原本兩個。
const jsonLdSchemas = faqSchema
? [blogPostingSchema, breadcrumbSchema, faqSchema]
: [blogPostingSchema, breadcrumbSchema];
📅 明天(2026-05-05)會發:寫文章每個數字都即時查(Live Search Injection)
下一篇拆 P2,看為什麼「Step 0 查過一次」不夠,每個版本號 / 價錢 / GitHub stars 都要當下重抓。
❓ 常見問題
FAQ 段在文章哪個位置最有效?
收尾段(心法 / 時間成本拆解)之後、延伸資源之前。理由:讀者讀到尾段表示有興趣,FAQ 給他「最後一些補充」的感覺。LLM 抓的時候不在乎位置,所以視覺上放尾段對人類最友善。
FAQPage schema 一定要 4 題以上嗎?
Google 沒有硬規定,但少於 4 題基本不會展 People Also Ask 卡片。LLM 也偏好「題目夠多看起來權威」的頁面。我自己定 4 為低標、6 為標準、8 為深度文。
Astro markdown parser 為什麼擋 ?
預設安全策略(避免內容注入),不是 Astro 特有,幾乎所有 markdown parser 都這樣。要插 script 必須走 layout 的 ,或自己改 parser 把 sanitize 關掉(不推薦,會引入 XSS 風險)。
已經發過的舊文要回頭補 FAQ 嗎?
看流量。流量前 5 名的舊文補 FAQ,回收效益最高(同樣 30 分鐘,新文 0 流量加 FAQ 等於白做)。其他可以不補。我自己的策略:每月選 3 篇高流量舊文補 FAQ,當作 SEO 維護工作。
怎麼驗證 FAQPage schema 真的有生效?
用 Google Rich Results Test 貼網址,看「Detected items」有沒有列出 FAQPage。再搭配 Search Console > 增強 > FAQ,等 Google 重新爬完會更新統計。