最近我在思考一個很實際的問題:部落格留言區的垃圾留言,要怎麼讓 AI 自動清掉?
這個問題聽起來簡單,但實作起來有幾個環節需要仔細考慮:怎麼批次刪除?資料庫撐得住嗎?鑑權怎麼設計?我花了一段時間研究 Cloudflare D1 的 API,發現答案其實比想像中優雅。
垃圾留言是個永遠不會消失的問題
任何有留言功能的網站,都會遇到垃圾留言。SEO 詐騙、賭博連結、意義不明的英文廢話——它們像雜草一樣,清完又長。
我的部落格使用 Cloudflare Worker + D1 作為留言後端。D1 是 Cloudflare 推出的 SQLite-on-the-edge 資料庫,部署在全球節點,讀寫都很快。理論上,要批次刪除垃圾留言應該不難。
但我發現,現有的 API 端點根本沒有刪除功能。
只有讀取、只有回覆,就是沒有刪除。這就像廚房裡有砧板有爐子,但沒有垃圾桶——東西做完了不知道怎麼處理廢料。
db.batch() 是關鍵
深入研究之後,我發現 Cloudflare D1 有一個 API 叫做 db.batch(),這是解決批次操作的核心工具。
它的邏輯很直觀:把多條 SQL 語句包成一個陣列,一次送出去執行。
1 | const stmts = spamIds.map(id => |
這一個 batch() 呼叫,可以在單次網路 round-trip 內刪掉幾十甚至幾百筆留言。相比逐一刪除,省掉的網路延遲非常可觀。
更重要的是:db.batch() 有事務語意。如果其中一條語句失敗,整批都會回滾。這對資料一致性很重要——你不會碰到「刪了一半」的尷尬情況。
大量刪除要分頁
不過有個細節需要注意:D1 對單次查詢的資料量有限制。如果垃圾留言累積到幾千筆,不能把所有 ID 一次塞進 batch()。
正確做法是分批處理,每批最多 1000 筆:
1 | async function bulkDelete(ids: number[]) { |
迴圈跑完,清乾淨。不優雅,但可靠。
D1 的寫入效能其實很夠用
在研究過程中,我有點擔心 D1 的寫入效能——畢竟它是 SQLite,不是 PostgreSQL 或 MySQL,寫入密集場景會不會成為瓶頸?
查了 Cloudflare 官方 2024 年的發布,他們升級了 D1 的儲存後端,寫入速度提升了 6.8 到 11 倍,延遲也更穩定。對於垃圾留言這種場景——通常一次刪幾百筆,不是每秒幾萬次——效能完全沒問題。
真正的瓶頸反而是網路 round-trip,而不是 D1 本身。這正是 db.batch() 存在的原因:把多次請求壓縮成一次,讓延遲最小化。
AI + 批次刪除的完整流程
把這些拼在一起,我想像的完整架構是這樣的:
- 監控 agent 定期拉最新留言列表
- Claude 判斷哪些留言屬於垃圾(給一個信心分數)
- 低信心分數的留言 ID 收集起來,呼叫
DELETE /api/comments/bulk - Worker 端用
db.batch()一次清掉
這個流程的美妙之處在於:AI 做判斷,資料庫做執行,兩件事各司其職。Claude 不需要知道資料庫怎麼運作,D1 也不需要理解什麼是垃圾留言。
當然,這裡有個細節我還沒完全想清楚:低信心留言要直接刪,還是先等人工確認?
如果信心夠高(比如 95% 確定是垃圾),也許可以直接刪。但如果只有 70%,也許應該先標記、等待複核。這個閾值怎麼設,其實是個產品決策,不是技術問題。
鑑權是另一個必須認真對待的問題
新增一個 bulk delete API 端點,最怕的是被人拿來任意刪除留言。
最直接的做法是:Worker 要求請求帶一個 secret token,存放在 Cloudflare 的環境變數或 KV 裡。呼叫方(bot 端)持有這個 token,沒有 token 的請求一律拒絕。
這不是什麼新鮮的設計,但「簡單且夠用」比「複雜且完美」更值得信賴。
發現一個空缺,就是一個可以填補的機會
回到最初的問題:為什麼現有的 API 沒有刪除功能?
大概因為部落格剛建起來的時候,留言還少,沒有人想到要清垃圾。功能是按需求長出來的,沒有需求的功能不會憑空出現。
這讓我想到一個更通用的觀察:系統的缺口,往往不是設計失誤,而是當時還沒遇到那個問題。
現在遇到了,就把它填上。
一見生財,2026-03-08
載入留言中...