AI大模型工具如何赋能个人创业和一人公司?用Python搭建模型调用前的敏感信息脱敏网关
个人创业者接入大模型后,最先得到的通常不是一套复杂的智能体系统,而是一个很朴素的自动化流程:把客户留言、会议纪要或业务表单整理成提示词,调用模型,再把结果交给人工确认。
这个流程很快,但也容易忽略一个问题:发给模型的原始文本里,可能混有手机号、邮箱、身份证号码、内网地址、访问令牌,甚至直接包含在 JSON 的 api_key 字段中。
因此,一人公司真正需要的并不只是“会调用模型”,还要在模型调用之前增加一道本地网关:
原始业务数据
↓
敏感信息检测
↓
脱敏与密钥字段阻断
↓
生成不含原文秘密的审计摘要
↓
允许进入模型调用
本文给出一套只依赖 Python 标准库的完整实现。它能处理普通文本和嵌套 JSON,能对候选结果进行二次校验,也能输出不记录原始敏感值的审计信息。完整代码和 10 个单元测试均已在本地运行。
需要先说明边界:这是一套模型调用前的工程防护示例,不是完整的数据防泄漏系统,也不能替代隐私、法务和安全评估。
一、为什么简单替换几个数字还不够
最直接的做法,是分别写几个正则表达式,再依次执行 re.sub()。但在真实输入里,这种实现很容易出现三个问题。
第一,正则只能说明一段字符“形状相似”,不能证明它一定有效。比如 999.168.1.8 看起来像 IPv4 地址,却不是合法地址;18 位数字看起来像身份证号码,也可能具有错误的出生日期或校验码。
第二,不同检测规则可能命中同一段文本。例如访问令牌中可能含有符合其他规则的片段。如果直接按代码顺序替换,后执行的规则会在前一个占位符上继续工作,结果既不稳定,也难以审计。
第三,敏感信息不一定只在文本值里。下面这种对象即使正文没有手机号,也不能原样进入模型:
payload = {
"task": "整理客户反馈",
"authorization": "Bearer real-secret",
"api_key": "sk-real-secret"
}
所以网关需要把“识别候选项”“验证候选项”“解决重叠”“替换文本”“阻断敏感字段”拆开处理。
二、先定义威胁模型和最小边界
本文处理的是这样一种常见场景:
- 输入来自表单、聊天记录或内部业务系统;
- 个人经营者准备将输入交给外部或自建的大模型接口;
- 调用前希望移除常见个人信息和凭据;
- 仍需保留文本结构,方便模型完成分类、摘要或改写;
- 日志可以记录发生了哪类脱敏,但不能反向恢复原值。
示例覆盖邮箱、中国大陆手机号、候选身份证号码、IPv4 地址、Bearer 令牌和常见密钥字段。它没有覆盖姓名、详细地址、人脸、银行卡、行业专用编号以及上下文推断出的隐私信息。
《个人信息保护法》第六条提出,处理个人信息应当具有明确、合理的目的,与处理目的直接相关,并采取对个人权益影响最小的方式,收集限于实现处理目的的最小范围。因此,工程上更稳妥的默认动作不是“先全部发送,再研究如何删除”,而是在调用前先缩减不必要的数据。法律原文可查阅工业和信息化部公布的《中华人民共和国个人信息保护法》文本。
三、用“正则发现+函数验证”减少误判
先定义检测器。每个检测器包含类型、正则、验证函数和优先级:
from dataclasses import dataclass
import re
from typing import Callable
Validator = Callable[[str], bool]
@dataclass(frozen=True)
class Detector:
kind: str
pattern: re.Pattern[str]
validator: Validator = lambda _value: True
priority: int = 0
邮箱和手机号可以直接使用较保守的模式。IPv4 地址则先由正则发现候选项,再交给 ipaddress.IPv4Address 验证:
import ipaddress
def valid_ipv4(value: str) -> bool:
try:
ipaddress.IPv4Address(value)
return True
except ipaddress.AddressValueError:
return False
Python 的 ipaddress 模块用于创建、处理和验证 IPv4、IPv6 地址及网络;无效地址会触发异常,具体行为见Python ipaddress 文档。
身份证候选项还需要检查日期和校验码。18 位公民身份号码的结构不能只用 \d{17}[0-9Xx] 判断。本文实现会验证出生日期,再按权重计算最后一位:
from datetime import datetime
CN_ID_WEIGHTS = (7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
CN_ID_CHECK = "10X98765432"
def valid_cn_id(value: str) -> bool:
normalized = value.upper()
if not re.fullmatch(r"\d{17}[0-9X]", normalized):
return False
try:
datetime.strptime(normalized[6:14], "%Y%m%d")
except ValueError:
return False
total = sum(int(number) * weight for number, weight in zip(normalized[:17], CN_ID_WEIGHTS))
return CN_ID_CHECK[total % 11] == normalized[-1]
对应的现行标准信息可在全国标准信息公共服务平台的 GB 11643-1999 页面核对。
这种“正则负责召回、验证器负责过滤”的结构有一个实际好处:后续要增加银行卡、订单号或企业内部编号时,可以为每类数据配置独立校验器,不必把所有逻辑堆进一条难以维护的正则表达式。
四、重叠命中不能靠替换顺序解决
检测阶段只收集候选项,不立即改写原文:
@dataclass(frozen=True)
class Candidate:
kind: str
start: int
end: int
priority: int
def collect_candidates(text: str, detectors: tuple[Detector, ...]):
candidates = []
for detector in detectors:
for match in detector.pattern.finditer(text):
value = match.group(0)
if detector.validator(value):
candidates.append(
Candidate(
detector.kind,
match.start(),
match.end(),
detector.priority,
)
)
return candidates
然后按“优先级更高、覆盖范围更长、出现位置更靠前”的顺序选取互不重叠的结果。Bearer 令牌的优先级高于普通片段,完整令牌一旦被选中,它覆盖范围内的低优先级候选项就不再重复处理。
ordered = sorted(
candidates,
key=lambda item: (-item.priority, -(item.end - item.start), item.start),
)
selected = []
for candidate in ordered:
overlaps = any(
candidate.start < current.end and current.start < candidate.end
for current in selected
)
if not overlaps:
selected.append(candidate)
最后再按文本位置统一替换。占位符使用稳定序号:
<EMAIL_1>
<EMAIL_2>
<CN_MOBILE_1>
<IPV4_1>
相比把所有邮箱都改成同一个 [REDACTED],稳定占位符保留了“同一类数据出现了几次”的结构信息,也方便测试预期结果。
五、递归处理 JSON,并直接阻断密钥字段
业务输入通常不是一段字符串,而是由字典、列表、数字和布尔值组成的 JSON。网关需要递归遍历:
SENSITIVE_FIELD_NAMES = {
"password",
"passwd",
"secret",
"api_key",
"access_token",
"refresh_token",
"authorization",
}
def sanitize_value(value, path="$"):
if isinstance(value, dict):
cleaned = {}
for key, child in value.items():
child_path = f"{path}.{key}"
if key.lower() in SENSITIVE_FIELD_NAMES:
cleaned[key] = "<BLOCKED_SECRET_FIELD>"
else:
cleaned[key] = sanitize_value(child, child_path)
return cleaned
if isinstance(value, list):
return [
sanitize_value(child, f"{path}[{index}]")
for index, child in enumerate(value)
]
if isinstance(value, str):
return redact_text(value).text
return value
这里有一个关键决策:命中 api_key、authorization 等字段名时,不尝试判断字段值长得像不像密钥,而是直接阻断。因为凭据格式会变化,依赖格式识别反而容易漏掉新类型的令牌。
数字、布尔值和空值保持原样,可以避免为了脱敏而改变业务字段类型。
六、审计日志只能记录“发生了什么”
如果日志把脱敏前后的完整文本都保存下来,那么脱敏网关只保护了模型接口,却把秘密复制到了日志系统。
本文的审计对象只保留三类信息:
- 哪条 JSON 路径发生了脱敏;
- 每种类型命中了多少次;
- 哪些敏感字段被整体阻断。
它不会保存原始值,也不会保存能够直接还原原文的映射表。实际运行结果如下:
{
"text_fields_with_redaction": 1,
"blocked_secret_fields": [
"$.customer.authorization",
"$.api_key"
],
"findings": [
{
"path": "$.customer.message",
"redacted_count": 3,
"kinds": {
"email": 1,
"cn_mobile": 1,
"ipv4": 1
}
}
]
}
即使这段审计记录被单独查看,也只能知道客户消息里出现过三类信息,无法看到邮箱、电话和地址原值。
七、一次完整运行
输入对象如下:
payload = {
"task": "整理以下联系记录,不要补写事实",
"customer": {
"message": "请回复 demo@example.com,备用电话 13800138000,测试服务器 192.168.1.8。",
"authorization": "Bearer example-token"
},
"api_key": "sk-example-token",
"flags": ["internal", 1, True]
}
safe_payload, audit = prepare_model_payload(payload)
网关输出:
{
"task": "整理以下联系记录,不要补写事实",
"customer": {
"message": "请回复 <EMAIL_1>,备用电话 <CN_MOBILE_1>,测试服务器 <IPV4_1>。",
"authorization": "<BLOCKED_SECRET_FIELD>"
},
"api_key": "<BLOCKED_SECRET_FIELD>",
"flags": [
"internal",
1,
true
]
}
模型可以继续理解任务、信息类型和句子结构,但拿不到示例中的原始联系方式与凭据。实际接入时,应当只把 safe_payload 交给模型客户端,原始 payload 不进入请求构造函数。
八、用 10 个测试验证边界,而不是只跑演示
本文配套测试覆盖以下行为:
- 邮箱和手机号能够被替换;
- 多个同类值获得稳定序号;
- 合法 IPv4 能被识别;
- 非法 IPv4 保留原样;
- 合法身份证候选项能被识别;
- 错误校验码不会被误判;
- Bearer 令牌优先处理重叠片段;
- 嵌套 JSON 能递归处理并阻断密钥字段;
- 审计结果不泄露原始秘密;
- 普通文本不会被无故改写。
运行方式:
python -m unittest -v test_csdn_ai_redaction_gateway.py
本地实际结果:
Ran 10 tests in 0.020s
OK
这里特意同时测试“应该命中”和“不应该命中”的样本。脱敏程序如果只有正向样本,很容易在演示中看起来正确,却在真实业务中把版本号、订单号或普通数字误删。
九、这套实现仍然会漏掉什么
工程上必须把限制写清楚。
首先,姓名和地址高度依赖上下文,单靠正则难以可靠识别。其次,经过空格、同音字、图片或编码变形的信息可能绕过模式。再次,同一段内容是否敏感与业务背景有关,例如公开客服电话和私人手机号不能一概而论。
此外,脱敏也不等于匿名化。上下文中剩余的职位、时间、地区和事件组合,仍可能让特定个人被重新识别。生产环境还需要结合数据分级、访问控制、传输加密、供应商评估、保存期限、删除机制和人工复核。
因此,合理的部署方式不是把这份脚本当作“合规开关”,而是把它放在纵深防护中的第一道可测试关卡。
十、个人创业者如何把网关接入工作流
对于一人公司,不建议一开始就搭建庞大的安全平台。可以先把入口收敛到一个函数:
def call_model_safely(raw_payload, model_client):
safe_payload, audit = prepare_model_payload(raw_payload)
save_audit_without_raw_values(audit)
return model_client.generate(safe_payload)
再设置三条简单规则:
- 所有业务系统只能通过这个入口调用模型;
- 网关测试失败时停止部署,不能静默跳过;
- 新增数据类型时,先补充正反样本,再增加检测规则。
这比在每个脚本里各写一段替换逻辑更适合个人经营者。规则集中后,修复一次就能覆盖多个自动化任务,审计格式也保持一致。
“AI大模型工具如何赋能个人创业和一人公司”的关键,并不是把更多内容无差别交给模型,而是让模型在明确边界内承担重复工作。对于关注 OPC中国、一人公司运营和 AI大模型工具深度运用的人来说,可验证的输入控制,往往比再增加一个提示词技巧更接近长期可用的生产能力。
“智能体来了”在这里也可以理解为一种工作状态:当智能体真正进入业务流程,检测、审核、失败处理和责任边界也应一起到位。
结语
这套脱敏网关没有追求覆盖所有敏感信息,而是完成了一个更具体、可验证的目标:在模型调用前,对常见文本信息和敏感字段进行统一处理,并留下不含原始秘密的审计摘要。
如果准备继续扩展,可以按业务风险依次增加自定义词典、行业编号校验、文件元数据清理和人工复核队列。但无论功能扩展到哪一步,都应保留本文的基本原则:先发现候选项,再进行验证;先生成安全副本,再调用模型;日志只记录必要事实,不复制秘密。
说明:本文使用 AI 工具辅助进行结构整理和语言优化,方案设计、代码、测试与内容已由发布者人工审核。
更多推荐


所有评论(0)