為什麼會做這個
我幫網站做 SEO 體檢時,發現一個尷尬的事:我的文章標題寫得太「文案」了。
例如這篇:
「空拍機與病蟲害視覺辨識:你的 24 小時免費植物醫師」
讀者覺得有趣,但 Google 抓不到核心關鍵字「農業 AI」「植物醫生」。搜「農業 AI 教學」找不到我——白寫。
問題是我有 195 篇文章,人工檢查不可能。我需要一個工具:
- 掃過全站
- 從每篇標題抽出主關鍵字
- 檢查這個關鍵字有沒有出現在 description、前 300 字
- 標記出有問題的文章
為什麼不用現成工具?
中文 SEO 的悲慘現實:
| 工具 | 中文支援 |
|---|---|
| Yoast SEO | ❌ 假裝有 |
| SEMrush | ⚠️ 簡體尚可,繁體很差 |
| Ahrefs | ⚠️ 同上 |
| Screaming Frog | ❌ 不檢查內容質量 |
而且這些工具都假設你站在 WordPress 上。我用 Astro,所有內容是 .md,要套這些工具還得先架一個 staging server。寫 100 行 Node 比較快——這也是 AI 輔助寫程式 最適合的場景:小規模、一次性、零依賴。
中文最大的坑:沒有空格
英文 SEO 工具能做的事,大半建立在「文字用空格切詞」這個假設上。中文沒有空格——這是中文 NLP 第一道難題。
正規解法是用 jieba(結巴分詞),但這需要安裝 Python、載 200MB 詞典、跑模型。對一個 build-time 腳本太重了。
我的啟發式做法:取標題前 2 個 CJK 字符當主關鍵字。
function extractPrimaryKeyword(title) {
let head = title.split(/[::((]/)[0]; // 1. 截到第一個冒號/括號之前
head = head.replace(/AI/gi, '') // 2. 去掉「AI」這個無意義詞
.replace(/[「」『』,,。!!??\s+]/g, '');
while (head.length && STOP.has(head[0])) { // 3. 去掉開頭的停用字
head = head.slice(1);
}
const m = head.match(/[\u4e00-\u9fa5]{2}/); // 4. 抓第一段連續 2 個 CJK 字
return m ? m[0] : head.slice(0, 2);
}
例子:
- 「會計的 AI 實戰指南」→
會計 - 「製造業 AI 工廠」→
製造 - 「空拍機與病蟲害視覺辨識」→
空拍(這個有點偏,但比拿整段更實用)
這個 heuristic 不完美,但目的不是學術研究,是「對啦你這篇 description 沒寫核心關鍵字」這種粗暴提醒。夠用就好。
評分邏輯
function score(article) {
const kw = extractPrimaryKeyword(article.title);
const head = article.body.slice(0, 300);
const issues = [];
if (!article.description.includes(kw))
issues.push(`description 缺主關鍵字「${kw}」`);
if (!head.includes(kw))
issues.push(`前 300 字未出現「${kw}」`);
if ([...article.title].length > 35)
issues.push(`title 過長 (SERP 約 30 字截斷)`);
if ([...article.description].length > 80)
issues.push(`description 過長`);
if ([...article.description].length < 30)
issues.push(`description 過短`);
if (issues.length === 0) return 'PASS';
if (issues.length === 1) return 'WARN';
return 'FAIL';
}
真實結果
SEO Health Check — 195 articles scanned
PASS 69 WARN 67 FAIL 59
第一次看到這個數字我嚇了一跳。59 篇 FAIL——也就是 30% 的文章在 SEO 上是裸奔的。
最常見的 FAIL 模式:標題寫得很「文青」,description 直接抄標題的延伸,結果主關鍵字一次都沒出現在前 300 字。
例如:
[FAIL] career/ai-arch-bidding.md (kw: 公共)
公共工程標單與估價解析:三秒破解巨型 RFP 招標書
· description 缺主關鍵字「公共」
· 前 300 字未出現「公共」
這篇文章內容講「建築業如何用 AI 解 RFP」,但整篇前 300 字都在講「我的客戶痛苦的故事」,等講到「公共工程」已經是第 4 段了。Google 看不到。
學到的事
- 不要假設「中文 SEO 工具」存在。它不存在。或者存在但很爛。最快的解法是寫 100 行 Node。
- 啟發式 > 完美 tokenizer。我花 30 分鐘寫的「取前 2 個 CJK 字」雖然粗糙,但它真的能跑 195 篇文章 並標出 59 個問題。完美的中文分詞器需要花一週搞定。
- 「文案感」與「SEO 友善」是 trade-off。我的標題寫得讓人想點,但 Google 看不到。正確做法不是放棄文案感,而是兩個都要:標題前半放關鍵字,後半放文案。例:「會計 AI 實戰:用 ChatGPT 把月結從 4 小時變 30 分鐘」。
- 零依賴工具是長期資產。這個腳本沒有 npm install 任何東西,只用 Node 內建模組。三年後我重灌電腦、換 Node 版本、刪 node_modules,它都還能跑。
接下來要做的事
- 把 59 篇 FAIL 文章逐篇修 description(這是 SEO 報酬率最高的單一行動)
- 加
--fixflag,讓腳本自己提議新的 description(餵給 LLM 改寫,類似 LangChain 的 pipeline 模式) - 整合到 CI:PR 如果引入新的 FAIL 文章就 block
原始碼在
scripts/seo-check.mjs。100 行,零依賴,可直接 fork 套到你的 Astro 站。
❓ FAQ
Q:這個啟發式的「取前 2 個 CJK 字」準確率如何?
A:粗估約 70–80% 的情況能抓到有意義的主關鍵字。主要失敗情境是:標題以動詞開頭(如「打造⋯」抓到「打造」而非核心名詞)、或標題完全用英文術語。但它的目的不是完美分詞,而是「快速標出有問題的文章」——即使關鍵字抓偏了,那篇文章通常也確實有 SEO 問題需要關注。
Q:為什麼不用 jieba 分詞?
A:jieba 是正規的中文分詞工具,品質遠好於啟發式。但它需要 Python 環境 + 200MB 詞典,對一個 build-time 的輕量腳本來說太重了。而且我的需求不是「精準分詞」,只是「粗暴的 SEO 體檢」。當你只需要 80% 的準確度時,100 行零依賴的 Node 腳本比完美的 NLP 方案更有價值。
Q:其他 Astro 站也能直接用這個腳本嗎?
A:可以,只要你的內容也是 Markdown + frontmatter 格式。需要改的只有:1) CONTENT_DIR 路徑,2) frontmatter 的欄位名(你可能叫 name 不叫 title),3) 停用字清單(根據你的內容領域調整)。整體改動不超過 10 行。
Q:PASS / WARN / FAIL 的分級標準可以自己調嗎?
A:可以,而且應該調。我用的是「0 個問題 = PASS / 1 個 = WARN / 2+ 個 = FAIL」,但這只是我自己的容忍度。如果你的內容比較技術向,title 長度限制可能可以放寬;如果你主攻 Google Discover,description 長度門檻要拉更嚴。腳本本身只是框架,規則請依站調。
Q:這個腳本會不會誤殺寫得很好的「文案型」標題?
A:會,而且這正是它的價值。被 FAIL 不代表文章不好,而是提醒你:「這個標題讀者愛看,但 Google 看不到關鍵字」。解法不是改回無聊的標題,而是用「關鍵字 + 文案感」的混合寫法,例:「會計 AI 實戰:把月結從 4 小時變 30 分鐘」——前半吃 SEO,後半吃點擊率。
Q:和用 LLM 評分比起來,這個腳本的優劣是?
A:LLM 評分(丟給 GPT 看每篇文章 SEO 如何)會更細膩、能給出質化建議,但也有三個缺點:1) 每篇要 API call,195 篇跑一次不便宜;2) 不同時段跑結果會飄,難以當基線;3) 慢。這個腳本 3 秒跑完、完全 deterministic、零成本。兩者定位不同:腳本做定期體檢,LLM 做深度診斷。