部落格文章有個特性:可以在文章內插入超連結,串聯到自己過去寫過的文章,或者像 Jaron 一樣整理成「延伸閱讀」。
我自己也會這樣做(又是被 Wiwi 影響),每次寫到一半,想到以前寫過相關文章,就會跑去搜尋欄查一下,再手動把網址貼回來。不過這也只限於「有印象」且「剛好想到」的時候,隨著文章越寫越多、時間久了,有時候連自己寫過什麼都快忘了。
在這種情境下,其實我們可以藉助 AI 的「語義理解」來幫忙找出相似文章哦,先來看看效果吧!
網站/部落格
《設計極簡部落格》(原文)
| 相關文章 | 相似度 |
|---|---|
| 網站改版:DIY 靜態網站生成器 | 89% |
| RSS Feed | 86% |
| DIY 網站留言簿 | 86% |
| Bear Blog ʕ•ᴥ•ʔ | 85% |
| 部落格問題挑戰 | 84% |
音樂/播放器
《卡式錄音機》(原文)
| 相關文章 | 相似度 |
|---|---|
| 使用 YouTube 聽音樂 | 85% |
| DJ SET | 83% |
| MP3 網頁播放器 | 83% |
| YouTube 歌單備份 | 83% |
| 網路曾經只是生活中的一部分 | 82% |
旅遊/景點
以下這兩個連結有完整的清單,有興趣的話可以去看一下。
運作原理
第一步:收集文章資訊當作輸入:比如標題、內文、大綱、分類等等。我這邊是使用「標題」和「內文」。(因為我懶得幫文章加標籤跟摘要)
第二步:透過 AI 模型把文章轉換成語義向量(Embedding)。這段向量可以理解為:AI 模型把文章的「意思」壓縮成了一組數字。兩篇文章如果語義相近,它們在向量空間中的距離也會很接近。
第三步:有了所有文章的向量之後,計算它們彼此之間的餘弦相似度,由高到低排序取前幾名,就是「相關文章」了。
兩種 Embedding 方案
方案一:Gemini(API)
可以到 Google AI Studio 申請一組 API Key(免費),然後把文章內容透過 API 丟給 gemini-embedding-001 模型就能得到語義向量了,(教學文檔)。
需要注意的是免費方案有速率限制,我的做法是每篇擷取前 2000 字(小廢文哪來的 2000 字),每隔兩秒呼叫一次,每天最多可以呼叫 1000 次(依官方為準)。
方案二:BGE-M3(本地)
如果不想依賴外部 API,也可以用 BGE-M3 這個開源的 Embedding 模型,透過 Ollama 在本機跑,完全離線、免費,而且用 CPU 就能順順跑。
Python 版的大致流程如下:
- 下載 Ollama、Python
- 下載 BGE-M3 模型:
ollama pull bge-m3 - 安裝 Python 套件:
pip install ollama - 透過 Python 的
ollama套件呼叫 BGE-M3 模型,輸入文章內容,獲得語義向量
計算相似度與排序
有了所有文章的語義向量之後,計算每篇文章之間的餘弦相似度(越接近 1 代表語義越相近),接著對每篇文章做排序後取前幾名,就可以得到推薦清單了。
快取機制
我這邊用 Hash(標題+內文) 的方式來判斷文章是否有改變,只要文章內容沒有改變,就不需要重新計算向量。
相似度的計算目前還是全部重跑一次(讓新、舊文章之間可以互相連結),我自己實測一百多篇大概要跑三秒,還可以接受。
如果你的文章很多的話,可以考慮使用 Vector DB,或者只針對「新文章 vs 舊文章」做增量計算就好。
完整執行流程
- 載入快取,用 Hash 比對找出需要更新的文章。
- 清除已刪除文章的舊快取。
- 對需要更新的文章做 Embedding 存進快取。
- 計算所有文章之間的相似度,由高到低排序,取前 K 名。
- 輸出成
related.json,前端直接讀取渲染,或者生成靜態的 HTML 區塊。
小補充
- 可以加入「時間權重」,讓比較新的文章更容易出現在推薦裡,Bear Blog 也有採用類似的做法。
- 如果你覺得「標題」、「分類」比較重要的話,可以在餵給 AI 之前多重複幾次關鍵資訊,例如:
{標題}{標題}{分類}{內文},這個做法簡單又有效。 - AI 太精準有時會少了點驚喜,可以對相似度分數加入一點點隨機分數,或者在推薦清單中固定留一個位置給「隨機抽樣」的文章。
- 這種做法完全不需要收集使用者資訊哦(按讚數、瀏覽數、停留時間等等),純粹是靠文章內容本身的語義來做推薦,對於不喜歡測量的朋友來說還不錯。
- 雖然功能做好了,但我還在考慮要不要加進網站裡,不然就是當作自己手動插入「延伸閱讀」的參考工具就好。XD