删掉邮箱后,Agent Trace 仍可能泄露什么:一条可重放脱敏流水线

摘要:生产 Trace 即使删掉邮箱,仍可能通过工具结果、内部文档、secret 和准标识符组合泄密;删得过多又会破坏失败重放。本文给出
classify → transform → verify流水线,并交付 sanitized trace、redaction manifest 与 replay invariant report。
关键词:Agent Trace、PII 脱敏、secret detection、回归评测、数据治理
你准备把一次生产事故变成回归用例。用户邮箱已经替换成 [EMAIL_1],于是团队把这条 Trace 复制进 Eval 仓库。
但工具结果里仍有完整客户行,错误堆栈暴露了内部路径,检索片段带着未发布文档,tenant_id + 时间 + 罕见订单状态 足以重新定位用户。更糟的是,某个环境变量里出现了仍有效的访问令牌。此时"PII 正则通过"既不能证明数据安全,也不能保证这条用例还能重放。
真正的问题不是如何把更多字符串替换成 ***,而是如何做一次可验证转换:删掉不该进入评测资产的内容,同时保留失败复现需要的实体关系、状态变化、工具 Schema 和判定条件。
本文给出一个单一产物:sanitized trace + redaction manifest + replay invariant report。它不是合规证明,而是一份能被安全、数据和 Eval 团队共同复核的工程交接物。

风险在 Trace 生成时就出现了

OpenAI Agents SDK 当前文档显示,tracing 默认启用,generation span 和 function span 可以保存模型与工具输入输出;trace_include_sensitive_data 默认是 True,可以按 run 或环境变量关闭。文档还把 tracing、诊断日志和 ZDR 分成不同控制面:ZDR 组织不能使用该 tracing,而日志是否携带模型或工具数据另有配置。S1
这个例子不能外推为所有框架的默认行为,却足以证明一个常见误区:团队不能等到"导出训练集"时才开始治理。敏感内容可能已经出现在 SDK Trace、反向代理、APM、错误日志、工具平台、备份和人工标注系统里。关闭其中一个开关,不会机械地清空其他副本。
OpenTelemetry 当前 GenAI 属性表也明确警告,system instructions、工具参数和工具结果都可能包含敏感信息。S2 所以只扫描用户消息天然漏掉一半风险面:
- 工具参数可能包含邮箱、订单号、文件路径、查询条件或授权上下文;
- 工具结果可能返回完整数据库行、内部文档、跨租户内容或环境变量;
- system instructions 和 tool definitions 可能暴露内部策略、权限模型与未公开接口;
- 多个看似无害的事件组合后,可能形成可重识别的时间线。
因此,采集前的字段最小化优先于采集后的批量清洗。能不进入 Trace 的原文,就不应因为"以后会脱敏"而先完整落盘。

稳定 Token 保留关系,但不等于匿名

回归重放经常需要跨事件关联。用户消息中的 alice@example.com、工具参数中的邮箱和工具结果中的客户 ID 如果被分别删除,测试就失去了"同一实体在三步中保持一致"的条件。稳定 token 更有用:
text
用户:查询 [EMAIL_1] 的退款状态
工具:customer_email=[EMAIL_1]
结果:customer_id=[CUSTOMER_1], status=pending_review
下一步:读取 [CUSTOMER_1] 的审批记录
但这不是匿名化。ICO 当前指南明确区分匿名化与假名化:tokenisation 后,只要能借助另存映射重新关联个人,数据仍属于个人数据。S4 NIST IR 8053 也强调,去标识化数据仍可能被重识别,而且风险对象包括结构化信息、自由文本与多媒体。S3
工程上应把 token 的稳定范围压到重放所需的最小域:同一 Trace 内稳定,通常比跨租户、跨数据集或永久全局稳定更安全。映射表应与 sanitized trace 分离存储、独立授权、加密并设置保留期;训练或外部共享默认不携带可逆映射。
这里的取舍很具体:稳定范围越大,跨步骤重放越方便,链接攻击面也越大。不存在一个"全局稳定且匿名"的免费答案。

一条可重放脱敏流水线

脱敏器应像编译器一样工作:输入有 Schema 和用途,转换有显式动作,输出要通过两类验证。三段管线分别是 classify → transform → verify。
第一步:按用途分类,而不是先跑检测器
同一条生产 Trace 面向不同用途,允许保留的信息不同:
| 用途 | 可保留内容 | 默认不应保留 |
|---|---|---|
| 事故响应 | 最小必要原文、完整时序、受限工具结果 | 无关客户内容、无限期副本 |
| 产品分析 | 聚合字段、低基数枚举、时延与状态 | 原始消息、完整参数和结果 |
| 回归 Eval | 失败触发片段、实体关系、工具 Schema、oracle 所需状态 | 可逆身份、真实凭证、无关文档 |
| 训练候选 | 单独授权且可追溯的最小语义 | Eval holdout、事故原文、映射表 |
| 外部共享 | 不可逆匿名或合成内容 | 可链接 token、内部资产和真实租户结构 |
先写用途,才能回答某个字段应该删除、泛化、tokenize 还是保留。一个不区分用途的"统一脱敏版本"往往既泄露过多,又无法重放。
第二步:Schema-aware 转换,未知字段默认隔离
结构化工具参数和结果应先按路径应用策略,自由文本检测只处理剩余未知内容:
yaml
policies:
- path: spans[*].tool.arguments.customer_email
action: stable_token
namespace: trace_local_email
- path: spans[*].tool.arguments.api_key
action: drop_and_alert
- path: spans[*].tool.result.internal_notes
action: minimal_excerpt
- path: spans[*].metadata.tenant_id
action: scoped_token
- path: spans[*].timestamps
action: shift_consistently
建议把动作分成五类:
drop:与用途无关,直接移除;drop_and_alert:疑似有效 secret,移除并进入安全事件队列;stable_token:保留同一实体的局部关联;semantic_substitute:用同类型虚构值替换,但保持枚举、格式和业务关系;digest_only:只保留版本、大小、哈希或来源引用,不复制正文。
未知工具结果不应自动全文进入下游。更稳的默认值是隔离、限制体积并要求补充 Schema。通用 LLM 可以辅助发现漏项,但不能成为唯一清洗器;把原文发送给远程模型本身会新增一条数据传输路径。
Secrets 也不能被当作普通 PII。检测到疑似仍有效的令牌时,正确动作不是只在副本里改成 ***,而是保存不含 secret 的指纹与来源位置,升级安全流程,并按实际状态判断是否撤销或轮换。
第三步:隐私残留和重放效用必须同时验证
脱敏完成后要跑两组测试。
第一组验证残留风险:
- 各类别 PII/secret 的漏报与误报;
- 准标识符组合的唯一性与外部链接风险;
- 跨租户 token 是否可能碰撞或关联;
- 映射表、原始 Trace 和派生数据的访问边界;
- 删除请求能否沿 lineage 找到所有副本。
第二组验证 replay invariant:
- Tool Schema 仍合法;
- 同一实体在相关 span 中仍保持一致;
- 时间先后、超时与审批窗口没有被破坏;
- 金额替换后仍位于同一业务阈值侧;
- 失败触发条件和 oracle 仍可判定;
- sanitized fixture 在隔离环境中仍能运行。
例如,原事故依赖"金额超过 10,000 需要二次审批"。如果脱敏把金额随机改成 200,即使所有姓名都删净,这条用例也已经失真。语义替换必须同时保留 amount > approval_threshold 这一不变量。
Redaction manifest 让转换可复核
sanitized trace 不应单独交付。每次转换至少生成一份不含原始敏感值的 manifest:
yaml
sanitization_run_id: SAN-EXAMPLE-001
source_trace_digest: sha256:...
purpose: regression_eval
policy_version: trace-sanitize-v3
transformations:
- path: spans[4].tool.arguments.customer_email
action: stable_token
token_scope: trace_local
- path: spans[7].tool.result.api_key
action: drop_and_alert
incident_ref: SEC-REDACTED
residual_risk:
quasi_identifier_review: required
replay_invariants:
schema_valid: true
entity_links_preserved: true
approval_threshold_preserved: true
lineage:
derived_fixture_digest: sha256:...
这份 manifest 解决三件事:安全人员知道哪些字段被怎样处理;Eval 维护者知道哪些语义关系被承诺保留;删除或策略更新时,数据团队能定位派生 fixture。它不能证明法律合规,也不能保存被删除的原值。
哪些情况下不该继续脱敏,而应停止导出

不是每条生产 Trace 都值得抢救成 Eval。以下情况应先停止下游流转:
- 出现跨租户内容,且无法证明污染范围;
- 命中可能仍有效的凭证、cookie、私钥或会话令牌;
- 失败依赖大量客户原文,最小片段仍足以识别个人或商业秘密;
- 无法建立 source → sanitized trace → fixture 的 lineage;
- 删除或泛化后,失败触发条件和 oracle 已不可判定;
- 数据用途、合法基础、访问角色或保留期仍未明确。
更简单的替代方案可能是重新构造合成 fixture,而不是继续清洗真实事故。合成数据也需防止复制罕见结构或原句,但在无法安全保留原始语义时,它通常比反复修补生产副本更可控。
结论

Agent Trace 脱敏的目标不是让文件里看不到邮箱,而是把一条生产轨迹转换为"最少但足够"的可重放证据。
先按用途决定允许保留什么,再用 Schema-aware 策略处理用户内容、工具参数、工具结果、系统指令、文件和多媒体,最后同时验证残留风险与 replay invariant。稳定 token 可以保留实体关系,但通常仍是假名化;ZDR、关闭某个 tracing 开关或 PII scanner 通过,都不能替代整条数据流的治理。
最终应交付三件东西:sanitized trace、redaction manifest、replay invariant report。三者齐全,团队才有证据判断这条 Trace 是否既能重放,也值得继续保留。
参考来源
- S1 OpenAI Agents SDK, Tracing 与 Configuration,访问日期:2026-08-30。
- S2 OpenTelemetry, GenAI semantic convention attributes,访问日期:2026-08-30;当前页面提示相关字段迁往独立 GenAI 语义约定仓库。
- S3 NIST, IR 8053: De-Identification of Personal Information,2015-10。
- S4 UK ICO, Introduction to anonymisation,访问日期:2026-08-30;页面提示指南正在复核。