學習 / 實作
AI Radar 工程拆解:從 RSS 到網站,中間發生了什麼?
AI 應用 · 工程案例
沿著本站真實程式碼,追蹤采集窗口、每日配額、去重、自動檢查和部署,並用證據定位“采集成功卻沒有更新”。
瀏覽統計暫不可用
本文目錄 7
“任務是綠色的,但網站沒有新資訊。”這句話其實混合了五個不同的問題:請求是否成功、是否有符合條件的候選、是否寫入文件、是否進入主干、線上是否部署了那個提交。
這篇文章沿著本站程式碼把它們拆開。閱讀後,你應該能拿著一次采集報告找到內容停在哪一步,也能理解為什麼“每兩小時執行”不等於“每兩小時必須新增十條”。
證據範圍
本文由 AI 輔助整理,依據博客倉庫提交
558e0a9的實現。描述的是可檢查的程式碼行為,不是一次新的線上事故復盤,也沒有測量生產延遲或篩選準確率。文中的配額算例是說明性輸入。可從 固定版本原始碼 對照閱讀。
1. 一條資訊經過哪些邊界?
RSS 來源
→ 請求與解析
→ 主題 / 技術機制篩選
→ 窗口、重復、總配額、來源配額
→ 可公開的資料 + 關聯報道
→ 內容檢查 + 三語言構建
→ Git 提交與推送
→ 部署系統
→ 讀者訪問的頁面前三步決定“值不值得收”。後半段決定“能不能穩定送達”。兩者需要不同的日志,不能用一個成功圖標替代。
| 邊界 | 本站入口 | 需要核對的證據 |
|---|---|---|
| 來源與規則 | config/news-sources.json |
來源啟用狀態、域名白名單、每日限額 |
| 原始響應轉候選 | scripts/news/lib.mjs 的 parseFeed |
有效發布時間、標題、原文 URL、摘錄 |
| 研究相關性 | scripts/news/relevance.mjs |
主題證據、技術機制、拒絕原因 |
| 本輪選擇 | selectItems |
outside-window、duplicate、daily-limit 等原因 |
| 發布文件 | scripts/news/collect.mjs |
data/news/items.json 的實際差異 |
| 檢查與推送 | .github/workflows/ai-news.yml |
構建結果、提交 SHA、推送結果 |
表中路徑均屬於上述固定提交。頁面不會在讀者打開 Radar 時重新抓取 RSS 或調用模型;它讀取已生成的資料。這讓來源故障不直接拖慢頁面請求。
2. 三種時間,解決三個問題
程式碼同時保存 publishedAt 和 collectedAt,報告另有 runAt。前者是來源聲稱的發布時間,後者是本站收錄時間;補采舊文章時,它們天然不同。
當前配置有兩層時間限制:解析器最多接受過去 14 天的條目;一次任務預設只選擇過去 48 小時的候選。手動任務可調整 window_hours,但不能超過解析範圍。擴大窗口也不能讓 RSS 返回它已經移除的舊記錄。
每天十條的“天”按 UTC 收錄日計算,而不是來源發布日期,也不是北京時間午夜。在中國標準時間中,UTC 換日對應上午 08:00。因此,07:50 和 08:10 兩次執行可能落入不同配額日。
當前調度是 35 */2 * * *,即 UTC 偶數小時的第 35 分鐘。它是計劃觸發時間,不能作為準點完成的保證。以上均可核對 工作流 與 選擇函數。
3. 十條是上限,六條也不是保底
設今天已收錄 7 條,其中 AIHOT 5 條。即使下一輪拿到了很多合格候選,全站也只剩 3 個名額,AIHOT 只剩 1 個名額。其他來源預設各自最多 2 條/日;配置可以覆蓋來源上限。
候選按研究優先級、來源優先級、發布時間、ID 依次排序,再逐條判斷。AIHOT 的來源優先級不能越過研究篩選,也不會繞過已用配額。高優先級來源沒有新內容時,不會用不相關內容湊數。
下面是獨立可執行的配額算例,只演示剩餘容量,不替代真實選擇算法:
const remaining = (limit, used) => Math.max(0, limit - used);
const siteSlots = remaining(10, 7);
const aihotSlots = remaining(6, 5);
const aihotCanAdd = Math.min(siteSlots, aihotSlots);
console.log({ siteSlots, aihotSlots, aihotCanAdd });
// { siteSlots: 3, aihotSlots: 1, aihotCanAdd: 1 }這裡有一個值得注意的設計取舍:當前是先到先占的跨執行配額,不是當天結束後再挑最佳十條。早間入庫的普通候選不會因為晚間出現更好的文章而自動被替換。每天嚴格控量與全天最優選擇是兩個不同目標;後者需要候選池和延遲發布策略,目前未實現。
4. 為什麼全文源有幫助,但仍會誤篩?
簡短標題可能只寫“新版本上線”,真正有價值的資訊藏在正文中的“沙箱隔離、測試套件、上下文卸載”。AIHOT 全文源讓這些技術證據進入臨時欄位 relevanceText,供規則判斷。
公開寫入前,publicNewsItem 移除該欄位;頁面保存的來源摘錄最多 180 個字元。讀全文用於判斷,不意味著全文轉載。 當前自動工作流顯式關閉模型摘要,所以來源摘錄也不能標成 AI 總結。
現有篩選包含主題與機制組合,例如上下文工程搭配預算/壓縮,機器人搭配軌跡/資料對齊。商業宣傳、純排名等還會經過排除規則。它比單個關鍵詞更具體,但本質仍是規則,不理解全部語義:一句技術文章中的商業背景也可能觸發排除,一段營銷文案也可能刻意堆滿術語。
因此,規則通過只意味著“滿足本站收錄條件”,不意味著“報道屬實”或“方法有效”。改進篩選應先收集誤收、漏收樣本,再調整 相關性規則,而不是盲目降低閾值。
5. 去重與聚類,不是一回事
采集選擇階段用規范化 URL 和去掉標點、大小寫後的標題阻止重復入庫。展示階段的事件合並還支持相同 URL,以及 72 小時內的相同標題或已有內容哈希。詳見 Radar 資料適配器。
這並不是向量語義聚類。中文報道與英文官方公告即便描述同一件事,只要鏈接、標題和哈希不同,就可能仍是兩個事件。程式碼“支持內容哈希”也不代表當前 RSS 解析器為每條記錄都生成了它。
同組報道會優先選擇原始或官方來源,但來源排序不等於事實核驗。verification 需要核驗者、時間和證據,不能用“官方”或“多個站點轉述”自動制造已核實狀態。
6. “成功但沒更新”的排查順序
先打開該次 Actions 的 news-run-report 附件,再按下面順序縮小範圍:
| 觀察 | 下一步 | 不能直接得出的結論 |
|---|---|---|
來源 failed |
看 HTTP、超時、解析失敗,檢查上一階段安裝是否成功 | 所有來源都失效 |
來源成功,inWindow = 0 |
對比最新發布時間與報告窗口 | 定時任務沒有執行 |
selected = 0 |
查 rejected 與 notSelected 的原因 |
RSS 沒有內容 |
selected > 0,構建失敗 |
看內容檢查/三語言構建日志 | 已經發布 |
| 構建通過,推送失敗 | 核對遠端提交與並發更新,重新集成後檢查 | 資料已經在主干 |
| 推送成功,頁面仍舊 | 比較部署綁定的提交 SHA、生產域名和構建資料 | 一定是瀏覽器快取 |
流程只在至少一個來源成功時保持采集階段成功;部分來源失敗可以和整個任務綠色同時出現。發布步驟還可能因為“沒有文件差異”正常退出。這兩種情況都需要讀報告,而不是只看任務顏色。
當前工作流的並發鎖只約束同組采集任務,不會鎖住人工推送。若檢查期間主干前進,最後的推送可能被拒絕;這個版本沒有自動重算並重試推送。定位時要保留最後成功的邊界,不要通過強制推送跳過問題。
7. 從這個案例帶走什麼?
把任何內容流水線寫成“輸入 → 選擇 → 存儲 → 發布”,然後為每個箭頭定義可檢查的產物。這裡分別是來源狀態、候選決策、文件差異、提交 SHA 與生產部署。
對本站而言,下一步最有價值的工程工作是建立一小份人工標注的篩選樣本集,持續檢查誤收與漏收;它屬於評估工作,不能用今天有幾條新聞來代替。想看目前實際產物,可以回到 AI Radar,也可以查看 站點項目。
寫給未來的自己合上文章前,留下一點自己的理解。
你的私人學習便箋,只存在目前瀏覽器,不會上傳或公開。清理瀏覽器資料會遺失,請匯出留存。三種語言共用這篇文章的便箋。
繼續探索
繼續探索
接下來,走哪條路?
- 用 Java 8 呼叫大型語言模型:從第一次請求到多輪對話 →
透過三個實際執行的 Java 範例,理解模型請求、JSON 解析、讀取逾時與對話歷史。
依據文章關聯與同主題已發布內容整理,不使用隨機推薦。