哪些数据不应该直接喂给模型?

将数据发送给第三方 AI 服务(如 OpenAI、Anthropic)时,数据会经过对方服务器处理,存在隐私泄露和合规风险。以下类别的数据必须在发送前脱敏处理:

数据类别具体示例风险等级
个人身份信息(PII)姓名、身份证号、手机号、邮箱、地址🔴 极高
认证凭证密码、API Key、Token、私钥、Cookie🔴 极高
金融数据银行卡号、信用卡号、账户余额、交易流水🔴 极高
医疗健康数据诊断记录、用药信息、基因数据🔴 极高
商业机密未发布产品计划、客户列表、定价策略🟠 高
内部系统信息服务器IP、数据库结构、内部接口文档🟠 高
员工信息薪资、绩效、人事档案🟡 中

三种脱敏方法

方法一:正则表达式替换

适合结构化、格式固定的敏感数据,如手机号、身份证号、银行卡号等。速度快,无需额外依赖。

import re
from typing import Tuple

# 脱敏规则配置
DESENSITIZE_RULES = [
    # (模式名, 正则表达式, 替换值)
    ("phone",    r'1[3-9]\d{9}',                           "[手机号]"),
    ("id_card",  r'\d{17}[\dXx]',                          "[身份证号]"),
    ("bank_card",r'\d{16,19}',                             "[银行卡号]"),
    ("email",    r'[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}',        "[邮箱]"),
    ("api_key",  r'(sk|pk|api)[_-]?[a-zA-Z0-9]{20,}',     "[API密钥]"),
    ("password", r'(password|pwd|passwd)\s*[:=]\s*\S+',    "[密码已隐藏]"),
    ("ip",       r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', "[IP地址]"),
    ("aws_key",  r'AKIA[0-9A-Z]{16}',                     "[AWS密钥]"),
]

def desensitize(text: str) -> Tuple[str, dict]:
    """
    对文本进行脱敏处理
    返回:(脱敏后文本, 统计信息)
    """
    result = text
    stats = {}
    for name, pattern, replacement in DESENSITIZE_RULES:
        matches = re.findall(pattern, result, re.IGNORECASE)
        if matches:
            stats[name] = len(matches)
            result = re.sub(pattern, replacement, result, flags=re.IGNORECASE)
    return result, stats

# 使用示例
raw_text = """
客户张三,手机号 13812345678,
身份证 110101199001011234,
邮箱 zhang@example.com。
API Key: sk-abc123def456ghi789jkl012
"""

clean_text, report = desensitize(raw_text)
print("脱敏结果:", clean_text)
print("脱敏统计:", report)
# 输出:
# 客户张三,手机号 [手机号],
# 身份证 [身份证号],
# 邮箱 [邮箱]。
# API Key: [API密钥]

方法二:NER 命名实体识别

正则无法覆盖非结构化的实体,如人名、机构名、地址等自然语言表达的 PII。此时需要借助 NLP 模型做命名实体识别(NER):

# 使用 spacy 或 presidio 做 NER 脱敏
# pip install presidio-analyzer presidio-anonymizer

from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine

analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()

def ner_desensitize(text: str, language: str = "zh") -> str:
    """使用 NER 识别并脱敏实体"""
    # 识别实体
    results = analyzer.analyze(
        text=text,
        entities=["PERSON", "PHONE_NUMBER", "EMAIL_ADDRESS", 
                  "CREDIT_CARD", "LOCATION", "DATE_TIME"],
        language=language
    )
    # 匿名化处理
    anonymized = anonymizer.anonymize(
        text=text,
        analyzer_results=results
    )
    return anonymized.text

# 对于中文,也可使用 HanLP 或 jieba + 自定义规则
# 企业场景推荐:本地部署的轻量 NER 模型,避免数据外发

方法三:令牌化(Tokenization)映射

用可逆的令牌替换敏感数据,处理完成后可以还原。适合需要 AI 分析结果后与原始数据关联的场景:

import uuid
import json

class TokenizationVault:
    """令牌化保险库:敏感数据 ↔ 令牌 双向映射"""
    
    def __init__(self):
        self._token_to_data = {}  # 令牌 → 原始数据
        self._data_to_token = {}  # 原始数据 → 令牌(避免重复令牌)
    
    def tokenize(self, sensitive_value: str, prefix: str = "TOKEN") -> str:
        """将敏感值替换为令牌"""
        if sensitive_value in self._data_to_token:
            return self._data_to_token[sensitive_value]
        token = f"[{prefix}_{uuid.uuid4().hex[:8].upper()}]"
        self._token_to_data[token] = sensitive_value
        self._data_to_token[sensitive_value] = token
        return token
    
    def detokenize(self, text: str) -> str:
        """将令牌还原为原始值"""
        result = text
        for token, original in self._token_to_data.items():
            result = result.replace(token, original)
        return result
    
    def tokenize_text(self, text: str, patterns: list) -> str:
        """批量令牌化文本中的敏感数据"""
        import re
        result = text
        for pattern, prefix in patterns:
            matches = re.findall(pattern, result)
            for match in matches:
                token = self.tokenize(match, prefix)
                result = result.replace(match, token, 1)
        return result

# 使用示例
vault = TokenizationVault()

original = "请分析张三(13812345678)的合同违约问题"
tokenized = vault.tokenize_text(original, [
    (r'[\u4e00-\u9fa5]{2,4}(?=()', "NAME"),
    (r'1[3-9]\d{9}', "PHONE"),
])

print("发给AI:", tokenized)
# → "请分析[NAME_A1B2C3D4]([PHONE_E5F6G7H8])的合同违约问题"

ai_response = "根据分析,[NAME_A1B2C3D4] 存在合同违约行为..."
restored = vault.detokenize(ai_response)
print("还原结果:", restored)
# → "根据分析,张三 存在合同违约行为..."

脱敏架构设计建议

小结

数据脱敏是 AI 应用合规的第一道门。正则适合结构化数据、NER 适合非结构化实体、令牌化适合需要还原的场景。三者结合,配合网关层的统一拦截,可以构建完整的数据保护链路。记住:最好的防护是数据根本不离开你的系统,本地部署模型是终极方案。