為什麼會做這個
我的網站有 195 篇 AI 主題文章。SEO 慢慢做沒問題,但有一個更快的流量來源:讓 LLM 引用我。
當有人在 ChatGPT 問「2026 有哪些 AI 教學網站?」,如果 ChatGPT 知道我的站,它會直接把我列出來。問題是:ChatGPT 怎麼會知道?
答案是 llms.txt 規範。這是社群提案的標準,讓網站像 robots.txt 一樣告訴 AI 爬蟲「我有什麼內容、在哪裡找」。目前 ChatGPT、Claude、Perplexity 都會抓這個檔案。
痛點:手動維護不可能
llms.txt 本身只是一份 Markdown 連結清單,寫一次很簡單:
# Mason AI Lab
> 中文 AI 知識站,涵蓋 195 篇教學與產業洞察。
## 學習入門
- [AI 新手村](https://masonailab.com/learn/beginners/)
- [Prompt 寫作入門](https://masonailab.com/learn/prompt-basics/)
...
但每寫一篇新文章就要手動更新一次 llms.txt,這不是工程問題,是紀律問題——而我已經被自己騙過太多次了。任何需要紀律的事都會被遺忘。
我需要一個會自動跑的東西。
解法:prebuild hook + 80 行 Node
Astro 的 package.json 支援 npm 的 prebuild 生命週期,意思是每次 npm run build 之前會自動跑這個腳本:
{
"scripts": {
"prebuild": "node scripts/gen-llms-full.mjs",
"build": "astro build"
}
}
這保證了只要我部署網站,llms-full.txt 就一定是最新的——不需要記得、不需要規律,完全自動。
腳本核心邏輯
import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
import { join, relative, sep, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const CONTENT_DIR = join(ROOT, 'src', 'content');
const SITE = 'https://masonailab.com';
// 1. 遞迴掃描所有 .md 檔
function walk(dir) {
const out = [];
for (const name of readdirSync(dir)) {
const p = join(dir, name);
const s = statSync(p);
if (s.isDirectory()) out.push(...walk(p));
else if (name.endsWith('.md')) out.push(p);
}
return out;
}
// 2. 解析 frontmatter,抽出 title / description / body
function parse(file) {
const raw = readFileSync(file, 'utf8');
const m = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
if (!m) return null;
// ... 抽 title, description, slug, section
}
// 3. 依分類排序、串接、寫檔
const articles = walk(CONTENT_DIR).map(parse).filter(Boolean);
articles.sort(/* 依 section 順序 */);
const out = articles.flatMap(a => [
`## ${a.title}`,
`Source: ${SITE}/${a.section}/${a.slug}/`,
a.body,
'---',
]).join('\n\n');
writeFileSync(join(ROOT, 'public/llms-full.txt'), out);
完整版 80 行,連 Windows 路徑空格的 bug 都處理了(fileURLToPath 別忘了)。
結果
[gen-llms-full] wrote 195 articles -> public/llms-full.txt (1096.7 KB)
每次 push 上 Cloudflare Pages,llms.txt 與 llms-full.txt 都是最新的。195 篇文章從此會自動出現在任何抓 llms.txt 的 AI 引擎裡。
學到的事
- GEO(Generative Engine Optimization)和 SEO 是兩種戰場。SEO 等 Google 排名要 3-6 個月,GEO 是「我有沒有被 AI 看到」,可以即時生效。如果你平常用 AI 輔助寫程式,這個腳本 30 分鐘就能搞出來。
- 靜態站的優勢被 AI 時代放大了。Astro 把所有內容變成 .md,讓全站索引變成 80 行腳本就能搞定的事——換成 WordPress 或 React SPA 會痛苦十倍。
- 任何需要紀律的事都應該被自動化。Prebuild hook 是被低估的工程實踐:零維護成本、零遺忘風險、隨 build 同步。
- llms.txt 不是銀彈,它只是讓 LLM「找得到」你。內容好不好、有沒有獨特觀點、能不能被引用,還是要自己寫。
接下來要做的事
- 觀察 server log,看哪些 AI bot 真的在抓 llms.txt(GPTBot、ClaudeBot、PerplexityBot)
- 為每篇文章加結構化的「TL;DR」區塊,讓 AI 引用時更容易截取重點
- 寫一個監測腳本,定期問 ChatGPT「2026 中文 AI 教學網站有哪些?」,看我的站有沒有被列出來
原始碼在
scripts/gen-llms-full.mjs(連結待補)。歡迎 fork 改造成你的版本。
❓ FAQ
Q:llms.txt 跟 sitemap.xml 有什麼不同?
A:sitemap.xml 是給 Google 等搜尋引擎看的「網址清單」,只列出 URL 和最後更新時間。llms.txt 則是給 AI 引擎看的「全文索引」,包含每篇文章的完整內容。搜尋引擎需要自己爬頁面解析 HTML;AI 引擎直接讀 llms.txt 就能理解你的全部內容。兩者互補,不是取代關係。
Q:llms.txt 這麼大(1.1 MB),會影響網站效能嗎?
A:不會。這個檔案只有 AI 爬蟲會抓,一般使用者的瀏覽器不會載入它。放在 Cloudflare Pages 等 CDN 上,邊緣節點會快取,對伺服器幾乎零負擔。而且 AI 爬蟲的頻率很低(通常每天 1–2 次),不像 Google 爬蟲那麼頻繁。
Q:WordPress 或其他框架也能做 llms.txt 嗎?
A:可以,但會比較麻煩。WordPress 需要寫一個外掛來遍歷所有文章,或者用 WP-CLI 匯出後再處理。React SPA 更痛苦——內容分散在 API 和 state 裡,沒有靜態 .md 檔可以直接掃。Astro 和 Hugo 這類靜態站框架天生適合這種全站索引的操作。
Q:要同時放 llms.txt 和 llms-full.txt 嗎?
A:建議兩個都放。llms.txt 是簡短的「目錄」(標題 + 連結),讓 AI 快速掃過知道你有什麼;llms-full.txt 是完整全文,讓 AI 直接拿去引用。不同 AI 爬蟲偏好不同,兩個一起放成本只多幾行腳本,但覆蓋面最廣。
Q:怎麼知道 AI 真的有抓我的 llms.txt?
A:看伺服器 log。Cloudflare Pages 的 Analytics 可以過濾 User-Agent,找 GPTBot、ClaudeBot、PerplexityBot、Google-Extended 這些 AI 爬蟲的 request。通常上線 1-2 週後會開始看到它們定期抓 /llms.txt 和 /llms-full.txt。
Q:llms.txt 會影響一般 SEO 排名嗎?
A:不會直接影響 Google 排名——Google 主要還是看 HTML 頁面。但 llms.txt 會影響「AI 搜尋」的曝光(ChatGPT、Perplexity 等),這是獨立於 Google 之外的新流量源。換句話說:傳統 SEO 和 GEO 是兩條平行的管線,llms.txt 做的是後者。