AI 讀你的履歷,卻看不見你的名字
當你執行 AI 適配分析時,我們會將你的履歷傳送給一個語言模型,讓它根據職缺內容評估你的經驗。這項分析確實有用——但它引出了一個我們不喜歡答案的問題:你的履歷究竟去了哪裡?
透過我們的閘道,送到一個模型供應商那裡。你的履歷上承載的不只是你的經驗——還有你的姓名、電子郵件、電話號碼,以及你的 GitHub 和 LinkedIn。這些資訊模型根本不需要,就能判斷你是否適合後端工程師職位。但它們過去仍會離開我們的服務。
所以我們停止這樣做了。你的履歷現在會在送達模型之前先進行去識別化——如果我們無法完成去識別化,我們就不會送出履歷。
簡單的 80% 與困難的 20%
電子郵件、電話和網址很簡單:幾個樣式規則就能乾淨地抓到。我們測試過,效果穩定。
姓名才是難題。我們用同一個偵測器測試了兩份真實履歷(在此已匿名化)。在單欄式排版中,它能順利找出姓名。但在雙欄式履歷上就失靈了:排版將區段標題放在第一行,把姓名往下擠,而這個人的姓氏從未以純文字出現——它只藏在電子郵件 ([email protected]) 和個人檔案網址 (/jordan-price) 裡。沒有任何樣式比對規則能復原一份文件從未明寫的姓名。
這個結論形塑了我們的設計:樣式比對器只是底線,不是完整的解法。姓名需要一個能讀懂脈絡的模型。
一個不離開我們機器的模型
最直覺的做法——請一個大型雲端模型來找出個人識別資訊(PII)——反而違背了本意:那正是我們想避免的那一跳。所以我們需要一個本機方案。
我們使用的是 OpenAI 的 Privacy Filter——一個專為此任務打造的小型開放權重模型:用於偵測文字中的個人資訊。它是一個 token 分類器,可在 CPU 上執行,且永遠不會離開我們自己的伺服器。我們把那份棘手的雙欄式履歷丟給它,它成功找回了樣式比對器無法偵測的隱藏姓氏。同樣重要的是:它保留了雇主名稱和城市不動——這些是分析所需的訊號,過度遮罩反而會讓判斷結果變差。
現在的請求流程
每一份送進模型的履歷都會經過同樣的兩個步驟:
- 輸入時遮罩。 我們偵測出識別資訊,並以佔位符取代(
[REDACTED_NAME]、[REDACTED_EMAIL_1]……)。模型供應商看到的是佔位符,永遠不會看到原始內容——在分析的每一個階段都一樣。 - 輸出時還原。 結果回傳後,我們會把真實數值換回來給你。你看到的分析結果與過去完全相同;供應商看到的只是一個陌生人。
模型仍可看到的內容都是刻意保留的:雇主、大學、職稱、技能,以及你所在的國家。被遮罩的是那些能個人識別你,卻對適配判斷毫無幫助的資訊。
刻意設計的「失敗即關閉」
重要的是當去識別化工具無法使用時會怎樣。要「優雅降級」、直接把原始履歷送出去當然很容易——但那正是我們拒絕上線的那個錯誤。當偵測器停機或無法連線時,我們完全不會把你的履歷送給模型。那次分析就單純不會執行。我們寧願什麼都不顯示,也不願洩漏你的個資。隱私是不能因服務中斷而被關閉的預設值。
我們保留下來的權衡
- 家庭地址採盡力而為的處理方式。現代履歷很少包含完整郵寄地址(通常只列出一個城市,我們刻意保留可見),在自由格式文字中偵測街道地址也是最弱的一環。模型有抓到時我們會遮罩,並坦承這層防護並不滴水不漏。
- 獨立的模型程序。 偵測器以獨立的小型服務運行在其他後端元件旁,而非被整併進去——這是在不把它的執行環境拖進其他所有地方的情況下,運行模型最乾淨的方式。一條日後可重新檢視的整齊接縫。
最終效果很簡單:你履歷中那些識別身分的部分,現在會止步於我們這道門。AI 仍然會讀取你的履歷。只是它不會得知你的名字。