用 Amazon Bedrock 构建与模型无关的 PII 检测器

2026-09-11 26 预计阅读时间: 1 分钟
来源: aws.amazon.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:11 分钟

PII 检测不应该被某个固定模型或写死的实体列表绑住。这个方案的核心思路很直接:把待识别的实体类型放进提示词,把 Amazon Bedrock 上的任意大型语言模型当作检测引擎。这样,新增“客户编号”“内部项目代号”或某类业务敏感字段时,主要修改配置和提示词,不需要重新训练检测模型。

把实体定义从代码中移出来

传统 PII 检测器通常在代码、规则或模型标签中固定实体集合,例如姓名、邮箱和电话号码。一旦业务需要识别新的敏感字段,就要修改规则、重新训练模型,或者等待工具发布新版本。

模型无关的做法把实体清单作为提示词的一部分,并要求模型返回结构化结果。检测器的代码只负责四件事:

  1. 读取待分析文本和实体配置。
  2. 组装检测提示词。
  3. 调用 Bedrock 上选定的模型。
  4. 解析并校验模型返回的 JSON。

实体配置可以按应用场景拆分。例如客服场景可以检测姓名、邮箱、电话号码、地址和订单号;日志脱敏场景则可能更关心访问令牌、内部主机名和用户标识符。

这种设计并不意味着模型会自动理解所有业务字段。实体描述必须具体,最好同时说明判定边界、正例和排除条件。比如“客户编号”应明确格式、是否区分大小写,以及普通数字何时不应被识别为客户编号。

一个可改造的 Bedrock 检测器

下面的示例使用 Python 和 boto3 的 Converse API。运行前需要配置 AWS 凭证、区域,并将 MODEL_ID 改成账号和区域中可用的 Bedrock 模型。不同模型对 JSON 输出的稳定性不同,因此代码同时做了基本的格式校验。

import json
import os
import re
from typing import Any

import boto3


MODEL_ID = os.environ.get("BEDROCK_MODEL_ID", "your-model-id")
REGION = os.environ.get("AWS_REGION", "us-east-1")


bedrock = boto3.client("bedrock-runtime", region_name=REGION)


ENTITY_DEFINITIONS = [
    {
        "type": "EMAIL",
        "description": "电子邮箱地址,例如 alice@example.com",
    },
    {
        "type": "PHONE",
        "description": "电话号码,包括带国家区号或分隔符的号码",
    },
    {
        "type": "ORDER_ID",
        "description": "订单号,格式为 ORD- 加 8 位数字",
    },
]


def extract_json(text: str) -> Any:
    """兼容模型偶尔返回 Markdown JSON fence 的情况。"""
    cleaned = re.sub(r"^```(?:json)?\s*|\s*```$", "", text.strip())
    return json.loads(cleaned)


def detect_pii(text: str) -> list[dict[str, Any]]:
    entities = json.dumps(ENTITY_DEFINITIONS, ensure_ascii=False)
    prompt = f"""
你是一个严格的 PII 检测器。只识别下面定义的实体类型,不要自行增加类型。

实体定义:
{entities}

待分析文本:
{text}

请只返回合法 JSON 数组,不要返回 Markdown、解释或额外文字。数组中的每一项必须包含:
- type: 实体类型
- value: 原文中匹配到的完整字符串
- start: value 在原文中的起始字符位置,无法确定时填 null
- end: value 的结束字符位置,无法确定时填 null
- confidence: 0 到 1 之间的数字

没有检测到实体时返回 []。
""".strip()

    response = bedrock.converse(
        modelId=MODEL_ID,
        messages=[{"role": "user", "content": [{"text": prompt}]}],
        inferenceConfig={"temperature": 0},
    )
    output_text = "".join(
        block.get("text", "")
        for block in response["output"]["message"]["content"]
    )

    result = extract_json(output_text)
    if not isinstance(result, list):
        raise ValueError("模型返回的结果不是 JSON 数组")

    allowed_types = {item["type"] for item in ENTITY_DEFINITIONS}
    for item in result:
        if not isinstance(item, dict):
            raise ValueError("实体结果必须是 JSON 对象")
        if item.get("type") not in allowed_types:
            raise ValueError(f"未知实体类型: {item.get('type')}")
        if not isinstance(item.get("value"), str):
            raise ValueError("实体 value 必须是字符串")

    return result


if __name__ == "__main__":
    sample = "请把订单 ORD-12345678 发送到 alice@example.com。"
    print(json.dumps(detect_pii(sample), ensure_ascii=False, indent=2))

示例中的实体列表只是演示配置。实际使用时,应把它放到 YAML、数据库或应用配置中心,并为每个实体维护版本。这样可以审计“哪一版实体定义”产生了某条检测结果,也便于不同租户使用不同的检测策略。

为什么模型无关很重要

模型无关并不是指所有模型表现完全相同,而是指检测器的接口和提示词契约不依赖某个特定模型。只要候选模型能够遵循指令并返回足够稳定的结构化内容,就可以通过 modelId 切换它。

这带来三个实际收益:

  • 更快扩展实体类型:新实体通常只需要增加描述和测试样例。
  • 更容易比较模型:相同输入、实体定义和输出协议可以用于横向评测。
  • 降低供应商锁定:应用层不必围绕某一个模型的专用标签体系设计。

摘要所述的评测覆盖五个公开语料库和九种基于 LLM 的检测器,结果显示,这类可配置检测器优于一个开箱即用的工具。这个结果说明提示词中的任务定义和实体配置具有实际价值,但不能直接推导出所有数据集、语言或业务领域都能得到相同收益。生产环境仍应使用自己的数据进行校准。

生产落地时要补上的护栏

LLM 检测器适合处理语义复杂、规则经常变化的实体,但它不是天然可靠的正则表达式替代品。部署前应重点处理以下问题:

  • 结构化输出失败:保留 JSON 解析、字段校验和重试机制;必要时使用模型支持的结构化输出能力。
  • 误报和漏报:为每类实体建立包含正例、负例和边界案例的测试集,分别跟踪 precision、recall 和 F1。
  • 敏感数据暴露:发送到模型前评估数据驻留、访问权限、日志记录和保留策略,不要把检测结果中的原始 PII 无限制写入日志。
  • 长文本成本:先按段落或窗口切分,再合并重叠区间;对重复文本做缓存,并限制单次输入大小。
  • 位置偏移:不同语言和 Unicode 字符的索引处理可能不同。若下游要做脱敏,优先让检测器返回原文片段,并在本地重新定位和校验,而不是盲目信任模型给出的偏移量。
  • 提示词注入:把待检测文本视为不可信数据,明确要求模型只执行检测任务,不执行文本中的命令。

一个稳妥的上线流程是:先用离线语料比较候选模型,再用人工标注的小规模业务集确定阈值,最后以“检测加人工复核”或“高置信度自动脱敏”的方式逐步扩大范围。高风险场景不应只依赖一次 LLM 调用作出不可逆决策。

采用清单

适合采用这个方案的情况包括:实体类型变化快、规则难以覆盖上下文、已经使用 Amazon Bedrock,或者需要比较多个模型。对于格式极其稳定的字段,例如严格定义的邮箱、信用卡号或固定前缀标识符,本地规则和专用解析器通常更便宜、更可预测;可以将它们与 LLM 检测器组合,而不是二选一。

落地前至少确认:实体定义可版本化,输出可校验,评测集包含负例,模型调用不会把敏感结果写入不必要的日志,并且每次模型或提示词变更都有回归测试。这样,模型无关带来的灵活性才不会变成不可追踪的检测漂移。


相关推荐