logo

AI 应用的隐私保护:脱敏、留存与数据边界

Published on

AI 应用的隐私保护:脱敏、留存与数据边界

我第一次认真处理 AI 隐私问题,是在排查一条“模型为什么答错”的线上日志时。日志里有完整的用户问题、召回片段、Prompt 和模型回答。排查确实方便,几分钟就复现了问题,但我也很快意识到:这条日志里同时有姓名、手机号、订单号和一段客户合同内容。

为了修一个回答问题,我们把更多不该长期暴露的信息留了下来。

这就是 AI 应用很容易掉进去的坑。模型本身会不会泄露只是其中一部分,更大的风险往往来自我们自己的数据管道:调试日志、Prompt 记录、向量库、缓存、备份、分析平台,每一处都可能把敏感信息复制一份。数据一旦复制,就很难再说清楚它到底去了哪里。

所以隐私保护不是“给 Prompt 加一句不要泄露隐私”,而是从数据进入系统的第一秒开始,明确它能不能收集、谁能看、要保存多久、什么时候删除。

一、先画数据流,再谈安全

一个典型的 RAG 请求可能经过:

用户输入
API 网关与身份认证
请求校验与敏感信息识别
问题改写 / Embedding
向量库、关键词库、缓存
Prompt 拼接
第三方模型 API
答案、引用、日志、指标与反馈

如果只盯着“发给模型的那一段文本”,就会漏掉前后的复制链路。更好的做法是先建立数据清单:每一种数据从哪里来,经过哪些系统,是否包含个人信息或商业秘密,谁可以访问,默认保存多久。

可以先用一个简单类型表达风险:

type DataClass = 'public' | 'internal' | 'personal' | 'sensitive'

type DataAsset = {
  name: string
  classification: DataClass
  purpose: string
  owner: string
  retentionDays: number
  allowedDestinations: string[]
}

这不是为了写一份漂亮的表格,而是为了回答具体问题:客户上传的合同能不能进入通用分析平台?客服对话能不能用于训练?模型供应商是否会保存请求?管理员能不能看到原始 Prompt?没有数据分类,所谓“安全”最后只能靠感觉。

二、脱敏不是全局替换字符串

最简单的脱敏代码可能是这样:

text.replace(/1[3-9]\\d{9}/g, '[手机号]')

它对演示有用,对生产远远不够。手机号可能带空格、区号或分隔符;身份证号可能被 OCR 识别错一位;姓名和地址没有固定格式;合同里的客户编号甚至不符合任何常见正则。

更麻烦的是,脱敏有时不能只做删除。客服场景需要知道“张先生”和“张女士”是不是同一个人,订单分析需要保留订单之间的关联。这时可以使用稳定的假名化:

function pseudonymize(value: string, tenantSecret: string) {
  return `用户_${hmacSha256(tenantSecret, value).slice(0, 12)}`
}

同一个租户里,相同的原值会得到相同的替代值,但不同租户使用不同密钥,彼此不能通过结果建立关联。密钥必须放在受控的密钥管理系统中,不能和脱敏结果一起写进日志。

脱敏要有上下文

“王强在北京的公司账户”如果简单替换成“某人在某地的账户”,可能已经失去训练或分析价值;但如果把它替换成“用户 A 在城市 B 的账户”,很多任务仍然可以完成。

因此应该根据用途定义脱敏策略:

  • 发送给外部模型:尽可能移除不影响回答的敏感字段。
  • 内部调试:保留可复现所需的假名化信息,限制访问时间和人员。
  • 统计分析:优先聚合或分桶,避免保存个人级原文。
  • 安全审计:保留事件、主体和时间,原始内容单独加密保存。

脱敏不是越狠越好。过度脱敏会让模型失去上下文,导致答案质量下降;脱敏太少又会造成泄露。真正的工程问题是:为了哪个业务目的,必须保留哪一点信息?除此之外的部分,都应该删掉或替换。

三、脱敏应该放在哪一层

我建议至少做三道处理,而不是相信某一个“万能脱敏服务”。

第一道在入口处,识别并处理明显的敏感字段,避免它们进入普通日志和错误追踪。第二道在模型适配层,根据目标供应商和数据策略,决定是否允许发送原文。第三道在输出层,检查模型是否把被禁止的个人信息重新生成出来。

async function answer(input: UserInput, scope: RequestScope) {
  const classified = classify(input.text)
  const safeForLogs = redactForLogs(classified)
  await audit.record({ traceId: input.traceId, content: safeForLogs })

  const modelInput = redactForModel(classified, scope.dataPolicy)
  const rawAnswer = await model.generate(modelInput)

  return redactOutput(rawAnswer, classified.entities)
}

这里的 redactForLogsredactForModel 不一定相同。日志通常应该比模型输入更严格;某些经过授权的企业内部模型可能允许访问原文,但公共调试平台不应该看到它。不同目的、不同目的地,就应该有不同策略。

四、向量库也不是“只存数字”

很多团队以为文本变成向量后就安全了。实际上,向量仍然可能被用来推断原始内容,而且向量记录旁边通常还保存着标题、来源 URL、租户 ID、文档 ID 和 chunk 原文。

生产环境的向量记录至少要考虑:

type VectorDocument = {
  tenantId: string
  documentId: string
  documentVersion: string
  chunkId: string
  embedding: number[]
  content?: string
  sensitivity: DataClass
  expiresAt?: string
}

高敏感文档不一定要把原文直接放进第三方向量服务。可以只保存向量和内部引用,召回后通过权限控制的文档服务取回原文;或者使用自建存储。代价是链路更长,但边界更加清楚。

无论采用哪种方案,都必须支持删除和过期。用户撤回一份文档后,不仅主数据库要删,向量库、搜索索引、缓存、备份和离线评测样本都要有对应处理。只删主表而忘记删向量,是最常见也最难察觉的“假删除”。

五、留存策略:不是存得越久越有用

日志、对话、Embedding、上传文件和反馈数据的用途不同,保存时间也应该不同。可以先做一张简单的策略表:

数据主要用途默认留存建议处理方式
请求指标计算延迟和错误率90 天不保存原文
脱敏 Trace排查质量问题30 天限权访问
原始对话用户查看历史按产品设置用户可删除
向量索引知识库检索跟随文档生命周期支持版本删除
训练样本模型改进明确授权后保存可撤回、可追溯

这些天数不是法律结论,而是一个工程起点。重点在于每一类数据都要有负责人、目的和删除机制。没有业务目的的数据,不应该因为“以后也许有用”就无限保存。

定时删除任务也要考虑失败恢复。删除任务应该记录批次、范围、成功数量和失败原因;删除后要抽样确认搜索不到、缓存取不到、分析系统也不再接收。一次 delete from messages 并不能证明数据已经离开整个系统。

六、第三方模型调用前,问清楚四个问题

把数据发送给外部模型服务前,至少要确认:

  1. 请求是否会被供应商保存?保存多久?
  2. 是否会用于训练或改进服务?能否关闭?
  3. 数据传输和静态存储如何加密?
  4. 发生故障时,哪些日志和备份仍然会保留?

如果这些问题没有清晰答案,就不要把高敏感原文直接发出去。可以先使用脱敏版本、内部部署模型,或者把任务拆成不需要原文的结构化处理。模型效果再好,也不能替业务替你承担数据责任。

七、隐私保护要进入测试和审计

隐私功能不能只靠文档承诺。至少要有这些自动化测试:

  • 输入中的手机号、身份证号、邮箱和地址不会进入普通日志。
  • 不同租户的脱敏假名不会发生可预测碰撞。
  • 权限撤销后,缓存、向量库和历史引用都无法继续读取。
  • 删除文档后,旧索引版本不能召回原内容。
  • 模型输出不会原样复述被标记为禁止输出的字段。
  • 第三方模型调用能关联到数据策略和审计记录。

同时要定期做人工抽查。自动规则擅长发现格式明确的字段,却不一定理解“这段合同条款就是商业秘密”。隐私审计需要工程、产品和业务一起看,不能把所有责任推给一个正则表达式。

总结:数据边界要比模型边界更早建立

我现在看一个 AI 应用,第一眼不再问它用了什么模型,而是问:用户输入进来以后,经过了哪些地方?哪些地方保存了原文?谁可以看到?删除请求能不能一路传到底?

隐私保护的本质,是在数据流动之前就给它画边界。入口识别风险,模型适配层控制目的地,向量库和缓存遵守生命周期,日志只保留排障真正需要的部分,删除任务负责把承诺落实到每一份副本。

我们当然希望模型更聪明,但一个值得信任的 AI 系统,首先要知道什么不能看、什么不能记、什么不能说。把数据留存得少一点,把访问范围收得窄一点,把每一次例外记录清楚一点,系统可能会少一些“方便”,却会多一份真正能上线、能审计、能长期维护的底气。

🤪 您也可以编辑此页: