iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
AI Engineering

30天拆Agent:從Repo看設計系列 第 25 篇

Day 25|Presidio 如何辨識與遮罩機敏資料?從辨識規則、中文模型到 LiteLLM 整合

  • 分享至 

  • xImage
  •  

Presidio 是一套開源的機敏資料辨識與去識別化工具。它可以找出文字中的姓名、電話、Email、信用卡號等資料,再依指定方式替換、遮蔽或移除。

例如,客服系統想請 LLM 整理客訴內容,但不需要把客戶的聯絡方式一起送出去,就能先把:

請協助處理退款,聯絡信箱是 alice@example.com。

處理成:

請協助處理退款,聯絡信箱是 <EMAIL_ADDRESS>。

Presidio 可以作為 Python 函式庫放進應用程式,也可以部署成服務。如果搭配 LiteLLM,則能在 Agent 呼叫模型之前,集中處理送出的文字。

不過,採用前需要先弄清楚:它如何判斷哪些字串是機敏資料、中文辨識需要哪些模型,以及遮罩應放在 Agent 的哪個位置。

一、Presidio 如何知道哪些內容需要遮罩?

Presidio 的文字處理主要分成兩個部分:

元件 負責的工作
Analyzer 找出機敏資料的類型、文字位置與辨識分數
Anonymizer 按照這些位置,執行替換、遮蔽或刪除

Analyzer 會執行多個 Recognizer,也就是辨識器。每個辨識器負責一種或多種資料類型,底下可以使用格式規則、專門的解析函式庫,或機器學習模型。

Recognizer 負責辨識 使用的方法
EmailRecognizer Email 正規表示式找候選字串,再檢查網域結構
CreditCardRecognizer 信用卡號 正規表示式+Luhn 檢查碼
PhoneRecognizer 電話號碼 使用 phonenumbers,依地區編碼規則解析
SpacyRecognizer 人名、地點等實體 讀取 spaCy NLP 引擎產生的辨識結果
PatternRecognizer 自訂格式與指定詞彙 正規表示式或詞彙清單

電話:使用外部套件解析號碼

Presidio 的 PhoneRecognizer 會呼叫:

phonenumbers.PhoneNumberMatcher(
    text, region, leniency=self.leniency
)

這是原始碼的呼叫節錄。PhoneNumberMatcher 來自外部的 python-phonenumbers 套件,是 Google libphonenumber 的 Python 移植版。

以這段文字為例:

My phone number is +1 425 882-8080.

套件的處理是:

  1. 使用規則找出像電話的候選字串,包括數字、空格、括號與連字號。
  2. 解析國際冠碼;若沒有冠碼,就利用指定地區解讀本地號碼。
  3. 根據各地區的電話號碼資料,檢查長度、號碼模式等條件,並排除部分日期等誤判。
  4. 通過檢查後,回傳原文中的起訖位置。

Presidio 預設使用的嚴格程度是 VALID,因此不只是「數字夠長就算電話」。

信用卡:先比格式,再做 Luhn 驗證

CreditCardRecognizer 先用正規表示式找出符合候選格式的字串,再移除空格、連字號,執行 Luhn 檢查碼演算法。

Luhn 的計算方式是:

  1. 從最右邊開始,最右一位保留。
  2. 往左每隔一位乘以 2。
  3. 乘以 2 後若是兩位數,就將兩個數字相加,例如 8 × 2 = 16,改計為 1 + 6 = 7。
  4. 全部加總,結果能被 10 整除就通過。

例如常見的測試號碼 4111111111111111:

原始:4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
處理:8 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1
加總:30 → 通過

若只把最後一位改成 2,加總變成 31,就不通過。

這能排除部分輸入錯誤與隨機數字,但通過 Luhn 不代表真有這張卡,也不代表卡片可以交易。這是檢查碼驗證,不是銀行查驗。

上下文:命中關鍵字,就提高既有候選的分數

Presidio 還會利用候選資料附近的詞彙,調整辨識分數。

例如電話辨識器設定了 phone、telephone、mobile、call 等關鍵字。對:

My phone number is +1 425 882-8080.

電話候選先由號碼解析器找到;接著,上下文增強器擷取附近經 NLP 處理的詞彙,包含詞形還原結果,再與辨識器預先設定的關鍵字比較。

查閱的預設實作使用不區分大小寫的子字串比對,也提供完整詞彙比對模式。這個步驟不是請 LLM 判斷句意,也不是計算向量相似度。

若命中支持詞,預設加 0.35,並限制分數上下界。電話的初始分數是 0.4,在這個例子中可提高為:

0.4 + 0.35 = 0.75

找到多個支持詞,不會每個都累加一次。這個機制也只調整已經找到的候選,不會因為出現 phone,就把任意一串文字變成電話。分數是程式的判斷依據,不能直接解讀成「有 75% 的機率是真的」。

姓名與地點:才更依賴 NLP 模型

姓名沒有像信用卡號那樣固定的檢查碼。辨識「王小明」是人名,通常需要 NER(Named Entity Recognition,命名實體辨識)模型,根據文字與上下文標出人名、地點等範圍。

Presidio 的預設英文配置使用 spaCy 的 en_core_web_lg;也提供 Stanza、Transformers 等 NLP 整合方式。使用 Transformers 時,需要的是能完成 NER 任務的模型,以及將模型標籤對應到 Presidio 實體類型的設定。

找出範圍後,Anonymizer 才執行文字操作。例如將 Email 換成 <EMAIL_ADDRESS>、將指定字元換成 *,或直接刪除整段。辨識模型決定遮哪裡;遮罩操作決定怎麼改。

二、辨識身分證、護照,需要提供訓練資料嗎?

不一定,取決於要新增的是規則,還是模型能力。

需求 通常採用的方式 是否需要自行準備訓練資料
格式明確的證件號碼、員工編號 正規表示式、適用的檢查碼、上下文 不需要訓練模型
現成 NER 模型已支援的姓名、地點 接入現成模型,對應實體標籤 不一定需要
模型不支援的新類型,或特定領域辨識不佳 新增規則,或微調 NER 模型 選擇微調時需要標註資料

例如公司員工編號固定是 EMP- 加上六位數,可以定義 EMP-\d{6} 這類規則,再補上符合業務資料的邊界條件。這是在寫辨識規則,不是在訓練模型。

身分證字號與護照號碼也應先依發證國家與證件種類判斷格式。若有適用的檢查碼,就加入對應驗證;不能把信用卡的 Luhn 演算法直接套用到所有證件。Presidio 提供自訂辨識器的擴充入口,可以將這些規則註冊到 Analyzer。

較困難的是「格式相同,但用途不同」。例如同樣一串九位數,可能是護照號碼,也可能是訂單編號。此時就要結合「護照」「passport」等附近詞彙,或應用程式已知的欄位資訊,降低誤判。

如果最後決定訓練模型,資料也不能只是丟進一批未標記文件。一般監督式 NER 微調需要指出:

旅客 [王小明/PERSON] 已完成報到。

也就是提供文字、實體範圍與類型,讓模型學習應該標記哪一段。完成訓練後,再把模型接回 Presidio。

三、Presidio 的比較

Presidio 與其他 PII 辨識系統的比較

PIIBench 整合十個資料集,比較 Presidio、spaCy、BERT 等八種系統。原論文使用 1,398 筆測試資料、3,383 個標註實體;辨識範圍與類型都必須符合標註,才算命中。

以下是原論文 Table 5 的結果,依 F1 排序:

系統 Precision:找到的有多少正確 Recall:應找的有多少找到 F1
Presidio 0.1522 0.1271 0.1385
SpanMarker BERT 0.1723 0.0588 0.0877
spaCy en_core_web_lg 0.0636 0.1395 0.0873
SpanMarker mBERT 0.1477 0.0570 0.0823
BERT-base NER 0.0791 0.0562 0.0657
XLM-RoBERTa NER 0.0508 0.0482 0.0494
Piiranha DeBERTa 0.0604 0.0375 0.0463
XtremeDistil FiNER 0.6990 0.0213 0.0413

這組結果的意義是:現成的辨識系統各有擅長的資料類型,不能期待換上一個模型,就能完整辨識所有機敏資料。

Presidio 結合規則與 NLP,在原論文測試中取得最高 F1,支持將兩種方法搭配使用的方向。例如,電話與信用卡交給格式、解析與檢查碼;姓名等需要上下文判斷的內容,再交給 NER 模型。但所有系統的整體分數仍低,顯示這些現成配置不足以完整涵蓋該測試的資料類型。

對遮罩應用而言,「找到的資料很準」還不夠,「該遮的資料有沒有漏掉」同樣重要。例如 FiNER 的 Precision 較高、Recall 卻很低,代表它在有把握的類型上表現較好,但大量其他實體仍會通過,無法單獨承擔全面遮罩。

作者後續使用修正後的測試資料,針對資料微調的 DeBERTa 取得 F1 0.6476,高於同次測試中最佳的原有比較系統 SpanMarker BERT(0.1723)。這提供了一個實務方向:讓訓練資料與目標類型貼近使用情境,值得優先評估。 不過,這是另一版實驗,不能與上表直接比較。

因此,評估繁體中文 Presidio 時,可以先用規則處理格式明確的證件與電話,再比較中文 NER 對姓名、地址的辨識效果。是否需要微調,應由實際漏判決定;這份研究本身並未證明哪個繁中模型最適合 Presidio。

中文 Presidio 組合的公開比較

社群專案 pii-detect-model 公布了 Presidio 搭配不同中文 NER 與相同規則組的比較:

組合 合併測試集 strict micro F1
Presidio 2.2.363 + CLUENER + cn_common_v5 0.9474
Presidio 2.2.363 + ERNIE + cn_common_v5 0.8968
僅 cn_common_v5 規則 0.6710

測試使用 5,000 篇正式文字、3,000 篇聊天文字,涵蓋姓名、電話、身分證、護照等八類;實體的起點、終點與標籤都要一致才算命中。這裡的 F1 綜合了誤判與漏判表現,並不是「文件有幾成完全遮乾淨」。

這是社群專案公布的中文合成資料評測,不是 Presidio 官方評測。

四、Presidio 搭配 LiteLLM

LiteLLM 提供模型呼叫介面與 Proxy 服務。本文使用的是 LiteLLM Proxy:讓應用程式先把模型請求送到共同入口,再由它轉送到後方的模型服務。

搭配 Presidio 後,可以在這個入口集中執行機敏資料處理。這對多個 Agent、不同程式語言,或同時使用多家模型供應商的環境特別有用,因為辨識規則與遮罩政策可以在共用服務管理。

這個組合官方依據:

以「送出前遮罩」為例,資料流如下:

sequenceDiagram
    participant A as Agent/應用程式
    participant L as LiteLLM Proxy
    participant P as Presidio Analyzer
    participant M as Presidio Anonymizer
    participant V as 模型服務

    A->>L: 模型請求,含待處理文字
    L->>P: 分析文字
    P-->>L: 實體類型、位置、分數
    L->>M: 文字、辨識結果與遮罩規則
    M-->>L: 處理後的文字
    L->>V: 使用處理後文字呼叫模型
    V-->>L: 模型回覆
    L-->>A: 回傳結果

部署者需要準備 Presidio Analyzer、Anonymizer 服務,並在 LiteLLM 的 Guardrail 設定中選擇 presidio、套用對象與執行時機。若目的是防止原文送進模型,就要使用模型呼叫前的 pre_call 路徑;logging_only 只處理記錄用途,不會改變真正送出的請求。

LiteLLM 也提供 MASK 與 BLOCK 等政策:前者替換辨識到的資料,後者在命中條件時阻擋請求。

五、和 Agent 的的組合

自行開發的應用程式,可以在組合好模型輸入後呼叫 Presidio;多個 Agent 共用政策時,則可以讓模型請求經過 LiteLLM Proxy。這類處理通常不適合只做成讓 Agent 自行選擇呼叫的工具,因為那不能保證每次送出前都會執行。

不同工具的接入位置如下。

工具/框架 接入位置
Codex CLI 在 ~/.codex/config.toml 設定自訂模型供應商與 base_url,將模型請求指向相容 Gateway;需確認 Responses API 相容性。文件
Claude Code 透過 ANTHROPIC_BASE_URL 等 Gateway 設定調整模型連線入口,並配合認證與模型設定。文件
Claude Agent SDK 在執行 SDK 的環境配置模型 Gateway;若指的是一般 Anthropic SDK 應用,也能在程式呼叫模型前加入 Presidio。文件
OpenClaw 在模型供應商設定中加入 LiteLLM,再將 Agent 使用的模型指向該供應商。文件
Agno 建立 Agent 時,使用指向 LiteLLM Proxy 的模型物件,例如官方的 LiteLLMOpenAI 整合。文件

需要注意的是,模型 Gateway 只處理經過它、且被 Guardrail 涵蓋的資料。Agent 直接呼叫外部 API、寫入記憶或記錄日誌,是其他資料路徑;在模型入口加上 Presidio,不會自動涵蓋這些地方。

正式採用前,可以用一小批貼近業務的資料回答三個問題:

  1. 遮得完整嗎?
    若「王小明」只辨識到「王小」,剩下的字仍會保留。應檢查完整文字範圍,而不只是有沒有找到人名。

  2. 會遮掉不該遮的內容嗎?
    訂單號、產品型號與測試數字都應列入測試,也要加入完全沒有機敏資料的文件。

  3. 遮罩後,任務仍能完成嗎?
    若不同人物全部變成 <PERSON>,模型可能難以追蹤誰說了什麼。需要維持人物關聯時,應另外設計一致代號與對應管理。

References


上一篇
Day 24|資料交給 Agent 前,業界怎麼遮罩?看 Microsoft、Databricks 與 Snowflake 的做法
系列文
30天拆Agent:從Repo看設計 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言