工具
本地化文本脱敏工具:在送入大模型前自动清除 PII 与密钥
一款离线运行的本地工具,通过多层检测管道(正则、checksum、GLiNER NER)识别并替换文本中的个人信息和密钥…
2026.08.30 · 周日约 5 分钟阅读
随着大模型被广泛集成到日常工作中,如何避免在调用 LLM 时意外泄露个人隐私信息和密钥,成为开发者与企业越来越关心的问题。近期在 Hacker News 上引起关注的一款本地化文本脱敏工具,给出了一个完全离线的解决方案:检测和清除 PII(个人身份信息)与密钥的过程不依赖任何外部 LLM 服务,一次性下载模型后即可在本地完成全部处理。
核心特性:两种输出模式
工具提供两种输出方式以适配不同场景:
- redact(默认):所有识别到的值统一替换为对应的占位符(如
〈EMAIL_ADDRESS〉)。 - pseudonymize(化名化):同一值在全文中映射到同一稳定标签(如
PERSON_001),同时将「标签→原始值」的映射表写入独立文件,不与脱敏后的输出混在一起,便于需要保留可逆映射的内部流程。
整个流程不调用任何外部 LLM,原始文本也不会发送到任何第三方服务。
检测管道:多层叠加
工具的检测并非依赖单一模型,而是一条分层管道。每个检测器输出统一的 (entity_type, start, end, score) 跨度列表,由 merge_detections 合并到运行集合中,保证最终结果不重叠,再交给 Presidio 的 anonymizer 替换。管道大致分为以下几个阶段:
- Presidio 结构化 PII 检测:以 spaCy 仅作为分词与 POS 引擎,使用 Presidio 识别
EMAIL_ADDRESS、PHONE_NUMBER、US_SSN、US_ITIN、CREDIT_CARD、IP_ADDRESS、IBAN_CODE、US_PASSPORT、US_BANK_NUMBER、DATE_TIME、URL等,仅保留分数 ≥ 0.35 的结果。 - 规则修正:丢弃 spaCy 的全部 NER 输出——其 PERSON 识别在技术文本中表现差(如将 Django、Grafana、「Cloud Run」误判为 PERSON),改为由 GLiNER 接管 PERSON;纯数字、无上下文的「电话号码」也按订单号、追踪号等过滤。
- URI/主机名正则:将
scheme://…与内部伪 TLD(.internal、.corp)作为「PROTECTED 跨度」插入,避免后续更窄的 URL 匹配覆盖完整地址。 - GLiNER(
gliner_multi_pii-v1):逐段执行 PERSON / ORGANIZATION / LOCATION / ADDRESS 检测,规避长文档注意力稀释问题,并对结果做二次审查——过滤云平台 token(GCP、S3)、全大写段落标题、含角色词的 PERSON、把工具名误判为 PERSON 的情况(通过一轮 technology 标签的仲裁判断)。 - 补充规则:街道地址(基于 USPS Pub. 28 后缀列表)、州/邮编、生日(仅当紧邻「DOB」「date of birth」「born」时触发),并把相邻的 ADDRESS + LOCATION 跨度合并为单个脱敏块。
- 密钥检测:集成
detect-secrets识别 API key、token、私钥、JWT、basic-auth 凭证,以及连接字符串中scheme://user:PASS@host形式的密码字段。
重叠消解策略
不同检测器对同一段文本可能给出相互冲突的跨度。merge_detections 的处理逻辑如下:
- 同类型合并:两个检测器都将某地址判为 ADDRESS 时,合并为一个跨度,而非让更窄的覆盖更宽的。
- 保护类型:URL、EMAIL_ADDRESS、US_SSN、US_ITIN、CREDIT_CARD、IP_ADDRESS、PHONE_NUMBER、US_BANK_NUMBER、US_DRIVER_LICENSE 等 PROTECTED 类型不会被低置信度的 NER 猜测片段驱逐。
- 0.05 容差:GLiNER 分数经过校准,新的命中若仅比已有命中低不到 0.05,仍可取代旧结果,避免真实命中因微小的分数差异被错误丢弃。
适用场景
对于需要将日志、客户工单、内部文档等文本送入云端 LLM、又不希望敏感信息外泄的团队,这款工具提供了一个零外部依赖、可脚本化集成的预处理环节。它的设计重点在于「在数据离开本地之前完成清洗」,而不是事后审计或脱敏后的二次校验。对于合规要求较严的行业(金融、医疗、法律),这种本地化前置处理尤其值得纳入 LLM 接入链路。
