少於 1 分鐘閱讀

留言風險偵測系統:14,315 則留言收斂成 694 則

醫院粉專是 2015 年 8 月開的,到現在十一年。

裡面有多少則留言,需要處理的又有多少,沒有人知道。因為沒有人翻得完。

小編的日常大概是這樣:發完文,回頭看看留言區,看到太過分的無腦謾罵的就讓它隱身。下一篇貼文出來,再重複一次。每一則留言都是當下處理、當下結束,沒有人有辦法把十一年的留言攤開來一起看。

這回,我想做的事情很單純。把翻不完的東西,變成看得完的清單。

先把東西抓下來

流程沒什麼特別。

從 Facebook 官方介面把粉專的全部貼文跟留言抓下來,包含已經被小編隱身的那 805 則。被隱藏本身就是一種標註,那批資料反而最有用。接著用規則篩掉明顯不用看的,空白、廣告、個資這些,剩下的丟給語言模型逐則判讀,標記人身攻擊、機構謾罵、嘲諷、醫療申訴,再給一個嚴重度。

最後產出一份 Excel。

4,145 則貼文,14,315 則留言,收斂成 694 則需關注。

我原本以為最麻煩的會是抓資料。結果抓資料是整個專案裡最順的部分,晚上跑完就有了,麻煩的都在後面。

全量跑一次的 API 費用是 6.46 美金,大概新台幣兩百出頭。往後每天只要處理新增的留言,會更低。以前燒過 47 美金的人,看到這種數字會有一點複雜的感覺。

這回設計的報表有四張工作表,但小編日常只需要看第一張。依嚴重度排序,紅橘黃三色標示,每一列都附一個直達那則留言的連結。點下去就到 Facebook,該隱藏就隱藏。

沒有自動隱藏。也沒有自動刪除、自動回覆。這是刻意的,後面會講。

那個 41 次

跑完之後,系統吐出一件我沒有預期的事。

同一段指控文字,重複張貼了 41 次,橫跨 13 則不同貼文,時間全部集中在兩天之內。

其中 25 則已經被小編隱藏了。所以當時是有人在處理的,只是逐則發現、逐則處理,沒有人知道這是同一件事情的延續。

公傳室先前的人工整理,在單一貼文底下記錄到 3 則。

我把那 13 則貼文一個一個點開來看過,確認不是程式算錯。沒有算錯。

這也不是誰不夠認真。沒有人會為了查一則留言去翻遍十三則貼文,那本來就超出人在做這件事的時候會有的範圍。機器只是不會累,也不會忘記上一則看過什麼。

準不準這件事

這種系統最容易講幹話的地方就是準確率。

高多少,跟什麼比。

還好公傳室手上有先前 877 則現成的人工標註(其實是我用另外的agent協助標注的),是以前同仁一則一則看出來的(是嗎?哈!)。有這批資料,判讀品質才有得量,不然就只是我自己覺得還不錯而已。

人工類別 準確率 涵蓋率
謾罵/人身攻擊 0.85 0.76
嘲諷/陰陽怪氣 0.71 0.63
負面質疑 0.44 0.62

最重要的那一類表現最穩,這是好消息。負面質疑的 0.44 就是明顯的過度標記,系統太緊張,看到什麼都覺得有問題。這個我還在調。

不過真正有用的是另一個數字,整體偵測率 87%。人工認定有問題的留言裡,有 87% 被系統標記並送進了報表。

對小編來說,標錯類別跟完全漏抓差很多。標成嘲諷但其實是謾罵,打開報表照樣看得到、照樣會處理。漏掉的那一則,才是永遠不會出現在任何人眼前的。

弱點寫在報告裡,我沒有藏。

短句反諷要有時事背景才看得懂。「哇真棒呢」到底是稱讚還是嘲諷,取決於那一週醫院發生了什麼事。我做了一個可以讓公傳室同仁自己維護的判讀背景設定檔,補上背景之後,這一類的涵蓋率從 0.27 拉到 0.63。代價是事件換了要有人記得去更新它,說實話這件事我沒什麼把握。

另外還有 967 則純圖片留言,完全沒處理。而且人工標註裡已經發現,有人把攻擊的文字做成圖片,用來閃過文字偵測。這件事我標在報表的摘要頁上。與其讓人以為報表就是全部,不如讓他知道自己看不到什麼。

我原本要做,後來沒做的那個

原本的規劃裡有一項,自動截圖存證。

程式自動打開每一則風險留言的連結,把畫面擷取下來存檔,以防當事人事後把留言刪掉。

這是我自己提的。當時覺得很合理,法務應該也會喜歡。

後來沒做。

先講一個容易混淆的地方。管理員自己打開頁面截圖,完全沒問題,那就是正常使用。有疑慮的是用程式自動打開幾百個頁面逐一擷取,Facebook 服務條款禁止以自動化方式存取或蒐集資料。

我列了四個理由。

第一個是連帶風險。違反條款的後果是帳號或粉專被限制,而現行系統的存取權杖綁在同一個帳號上。一旦被限制,連現有的留言擷取功能都會一起停擺。為了一個附加功能賭上整套系統,不划算。

第二個是我實際測了才發現的。目標留言的周圍,同時看得到好幾位其他民眾的姓名跟大頭照。這些人什麼都沒做,卻會被存進一個為了法律行動而建立的檔案裡。525 則留言的截圖會夾帶多少張不相干的臉,我沒有算,也不太想算。

第三個是法律效力。自行擷取的螢幕截圖證明力薄弱,對造可以爭執真偽。實務上採認度比較高的是網頁公證。

第四個是最後才想到的。留言一旦被刪掉,任何形式的存證都來不及,包含截圖。

而且還有一件事我一開始沒想清楚。留言內容其實早就保存了。資料庫裡有每則留言的完整文字、發布時間、留言編號、原始連結、所屬貼文,留言被刪掉之後這些紀錄不會消失。截圖能多提供的,只有留言者的姓名跟畫面長相。

所以我把問題從「事後保存」改成縮短反應時間。每天重新抓近期貼文的留言,比對後找出消失的那些並標記;嚴重度最高的新留言即時通知法務,以現有資料估算,平均每天 0 到 2 則。法務收到通知後,在留言還在的時候決定要不要辦網頁公證。那個才是真正有證明力的存證。

至於截圖,嚴重度 3 而且還沒被隱藏的只有 33 則,管理員手動幾分鐘就截完了,也完全合規。自動截圖那個版本要跑四個小時,刪除偵測每天跑一分鐘。

難的不是寫出來

這個專案技術上最難的地方,其實不是抓資料,也不是叫模型判讀。

是想清楚哪些事情不該做。

自動截圖我寫得出來,一個下午的事。真正花時間的是坐下來把四個理由一條一條寫成報告,然後跟提出需求的人說,這個我建議不要做,我們改成這樣。

寫程式久了會有一種慣性,想到一個功能就會想把它生出來,因為做得出來。這次算是自己踩了煞車。

報告最後一頁我寫了系統採行的原則:不自動隱藏、不自動刪除、不自動回覆,所有處置一律由人工判斷後執行。

還有一件事。資料庫裡沒有一般民眾的姓名或帳號,Facebook 官方介面在現行權限下不提供,而我也沒有去申請。複核的人如果需要知道是誰講的,就從留言連結點過去看。能不拿的就不要拿,這個不用等別人來要求。

程式碼

放在 GitHub:Facebook-fan-page-comment-output-and-risk-content-detection

Python 3.12 加 uv,一個 CLI 工具,128 個測試。抓取、分類、報表、品質評估都是獨立指令,可以中斷續跑。

有一件事我在 repo 裡刻意處理過。版控裡的關鍵詞表跟判讀背景設定檔都只是範本,不含真實內容,實際使用的是同名的 .local 版本,不進版控。

理由有兩個。一份「監測中的政治關鍵詞」清單如果被單獨截圖轉發,讀者不會看到規格裡「政治為中性標記、不得作為處置依據」那一段說明,脈絡會在轉發的過程中掉光。另一個理由更直接,公開完整的偵測準則等於教人怎麼規避,而我們已經知道有人在規避了,他們把字做成圖片。

程式是開放的,那幾份清單不會。


系統目前的狀態是「可用,維運功能待開發」。

剩下的待決事項不在我這裡。通報要走哪個信箱、網頁公證的流程跟費用、已刪除的留言要保存多久,這些得由公傳室、法務跟個資窗口去決定。

我能做的是把選項攤開,然後說清楚哪一個我不建議。

更新時間: