扫描件、低清复印件和手写表单中的个人信息,往往比普通文本更难处理。OCR 可能漏掉字符,字段位置也不稳定;如果只依赖整页遮盖,又会损失文档的业务可用性。
一种更稳妥的做法,是把 Amazon Bedrock Data Automation、定制 blueprint、AWS Step Functions 和 AWS Lambda 组合起来:先从文档中提取结构化字段,再只对敏感字段做精确脱敏,并用 token matching 质量检查弥补退化图像和手写内容中的召回损失。
从“整页打码”转向“字段级脱敏”
这类流水线的核心不是简单识别某个字符串,而是同时回答两个问题:
- 文档中有哪些业务字段?
- 哪些字段属于需要隐藏的 PII?
定制 blueprint 可以把文档描述为一组字段,例如姓名、地址、身份证号、电话号码、银行账号或保单号。处理结果不再只是“这一页包含 PII”,而是可以定位到具体字段,并据此生成脱敏后的文档或结构化输出。
字段级处理有几个直接收益:
- 保留日期、金额、产品名称等非敏感信息,方便后续审核和检索。
- 对姓名、联系方式等字段单独设置遮盖策略。
- 让审计日志记录“哪个字段被处理”,而不是只记录一页图片被修改。
- 可以针对不同文档类型复用不同 blueprint,而不必为每类文档编写一套 OCR 规则。
不过,blueprint 的字段定义需要和真实文档样本一起迭代。字段名称、数据类型、是否必填以及可能出现的位置,都应该通过正常样本、低质量扫描件和手写样本验证。
用 Step Functions 编排异步处理流程
一个适合生产环境的处理链路可以拆成以下阶段:
S3 输入文档
│
▼
Step Functions
├── Lambda:校验文件、生成 job 元数据
├── Bedrock Data Automation:按 custom blueprint 提取字段
├── Lambda:检查 token matching 质量
├── Choice:通过则进入脱敏;失败则重试或转人工审核
└── Lambda:写入脱敏结果和审计记录
Step Functions 的价值在于把重试、超时、分支和人工审核边界显式化。不要把所有逻辑塞进一个 Lambda:文档较大、处理时间较长时,单个函数容易受到运行时长、内存和临时文件空间的限制。
下面是一份便于改造成 Amazon States Language 的配置草案。Resource 中的 ARN 需要替换为实际部署的 Lambda;Bedrock Data Automation 的调用参数也应按照目标区域和 SDK 版本补齐。
Comment: PII redaction pipeline with quality gating
StartAt: ValidateInput
States:
ValidateInput:
Type: Task
Resource: arn:aws:lambda:REGION:ACCOUNT_ID:function:validate-document
Retry:
- ErrorEquals: [States.Timeout, Lambda.ServiceException]
MaxAttempts: 3
BackoffRate: 2.0
IntervalSeconds: 2
Next: ExtractWithBlueprint
ExtractWithBlueprint:
Type: Task
Resource: arn:aws:lambda:REGION:ACCOUNT_ID:function:start-bedrock-data-automation-job
TimeoutSeconds: 900
Retry:
- ErrorEquals: [States.Timeout, States.TaskFailed]
MaxAttempts: 2
BackoffRate: 2.0
IntervalSeconds: 5
Next: CheckTokenQuality
CheckTokenQuality:
Type: Task
Resource: arn:aws:lambda:REGION:ACCOUNT_ID:function:check-token-quality
Next: QualityGate
QualityGate:
Type: Choice
Choices:
- Variable: $.quality.recall_estimate
NumericGreaterThanEquals: 0.98
Next: RedactFields
Default: ManualReview
RedactFields:
Type: Task
Resource: arn:aws:lambda:REGION:ACCOUNT_ID:function:redact-pii-fields
Next: PublishResult
ManualReview:
Type: Task
Resource: arn:aws:lambda:REGION:ACCOUNT_ID:function:send-to-review-queue
End: true
PublishResult:
Type: Task
Resource: arn:aws:lambda:REGION:ACCOUNT_ID:function:publish-redacted-document
End: true
这份示例故意把 Data Automation 的调用封装在 Lambda 中。这样做可以隔离 SDK 版本变化,也便于在提交任务前统一处理 S3 URI、blueprint 标识、幂等键和权限校验。
用 token matching 发现 OCR 漏检
低质量文档中,模型可能已经识别出大部分字段,但仍然漏掉一个字符或把空格、连字符处理得不一致。例如,原文中的证件号可能是 110105-1980-1234-5678,OCR 结果却变成 110105 1980 1234 5678。
token matching 质量检查可以把多个来源放在一起比较:
- blueprint 提取出的字段值;
- OCR 的原始文本;
- 业务系统已有的参考 token,例如订单号、客户号或文件元数据;
- 脱敏结果中是否仍然出现敏感 token。
下面的 Python 示例不依赖 AWS SDK,可以直接运行,用于演示“规范化 token、检查匹配、决定是否放行”的最小逻辑。生产环境可以把 extracted_fields 替换为 Data Automation 的结构化输出,把 ocr_text 替换为 OCR 或文档解析结果。
运行方式:
python3 token_quality_check.py
token_quality_check.py:
import re
from typing import Dict, List
def normalize(value: str) -> str:
"""忽略大小写、空格和常见分隔符,降低 OCR 格式差异的影响。"""
return re.sub(r"[\s\-_/]+", "", value or "").casefold()
def token_present(token: str, text: str) -> bool:
return normalize(token) in normalize(text)
def check_quality(
extracted_fields: Dict[str, str],
ocr_text: str,
sensitive_fields: List[str],
minimum_recall: float = 0.98,
) -> Dict[str, object]:
expected = [
value for name, value in extracted_fields.items()
if name in sensitive_fields and value
]
matched = [value for value in expected if token_present(value, ocr_text)]
recall = len(matched) / len(expected) if expected else 1.0
return {
"recall_estimate": round(recall, 4),
"passed": recall >= minimum_recall,
"missing_tokens": [value for value in expected if value not in matched],
}
if __name__ == "__main__":
fields = {
"full_name": "Zhang San",
"phone": "138-0013-8000",
"policy_number": "AB-2024-0009",
}
ocr_text = "Name: Zhang San; Phone: 138 0013 8000; Policy: AB20240009"
result = check_quality(
extracted_fields=fields,
ocr_text=ocr_text,
sensitive_fields=["full_name", "phone", "policy_number"],
)
print(result)
if not result["passed"]:
raise SystemExit("quality gate failed: route document to manual review")
这个检查器并不能替代模型评估,也不能证明“文档中不存在 PII”。它的作用是建立一个廉价、可解释的质量门:当关键 token 没有在原始文本中出现,或者不同来源的结果不一致时,暂停自动脱敏并转人工复核。
在生产环境中,召回率阈值不应固定套用。身份证号、银行账号等高风险字段可以设置更严格的阈值;低风险字段则可以结合人工抽样和业务容错率调整。还应记录误报、漏报和转人工比例,持续回放真实样本。
脱敏结果、权限和审计不能遗漏
PII 流水线的安全边界不止是模型本身。建议至少落实以下约束:
- 原始文档和脱敏文档使用不同的 S3 前缀,必要时使用不同的 KMS 密钥。
- Step Functions、Lambda 和 Data Automation 任务采用最小权限 IAM policy,不要为方便而授予整个存储桶的读写权限。
- 原始文档设置生命周期策略,明确保留期限和删除责任。
- 审计日志记录输入对象、blueprint 版本、处理状态、质量结果和输出对象,但避免把完整 PII 写进普通日志。
- 通过幂等键避免 Step Functions 重试时重复生成结果。
- 对失败文档保留可追踪的 job ID,并把人工审核作为明确的终态,而不是静默跳过。
还需要区分两种输出:供人查看的脱敏 PDF 或图像,以及供系统使用的结构化 JSON。前者关注遮盖区域和视觉效果,后者关注字段值、状态和审计信息。两者最好分别验证,避免出现“图片已经遮住,但 JSON 仍然泄露”的不一致。
落地时的检查清单
可以按下面的顺序推进:
- 收集正常扫描、低清扫描和手写样本,建立脱敏回归集。
- 为每类文档定义 custom blueprint 和敏感字段清单。
- 用 Step Functions 拆分提取、质量检查、脱敏和发布步骤。
- 使用 token matching 检查 OCR 漏检,并为高风险字段设置更严格的放行条件。
- 对失败任务、低召回结果和高置信度冲突设置人工审核路径。
- 通过 CloudWatch 指标或等价监控观察处理延迟、失败率、人工审核率和字段级漏检率。
- 在扩大吞吐量前,先验证权限、数据保留和重试幂等性。
Amazon Bedrock Data Automation 解决的是文档理解和结构化提取问题;真正可靠的 PII 脱敏系统,还需要 blueprint 设计、质量门、工作流编排和数据治理共同配合。把这些环节拆开并显式验证,才能在规模化处理扫描件时兼顾召回率、精确度和可审计性。