【寻迹校园 HarmonyOS NEXT 实战 44】把候选交给小艺前先脱敏:XiaoYiAgentAdapter 的数据最小化设计
【寻迹校园 HarmonyOS NEXT 实战 44】把候选交给小艺前先脱敏:XiaoYiAgentAdapter 的数据最小化设计
本章导读:这是“寻迹校园 HarmonyOS NEXT 实战”系列第 44 篇。本文以
XiaoYiAgentAdapter.ets、XiaoYiClipboardAdapter.ets和现有测试为证据,拆解本机候选如何经过字段白名单、最多三条限制、分段截断、正则脱敏、240 字总上限和用户主动复制后再交给小艺。文中不会展示真实 Agent/Workflow ID,也不会把正则替换描述成完整 DLP。

上图是原创隐私数据流概念图,不包含真实用户数据或项目截图。AI 辅助的第一原则不是“尽量给模型更多上下文”,而是“只给完成当前任务所必需的最少信息”。
一、为什么候选对象不能直接拼进 Prompt
一条失物记录可能包含标题、精确地点、照片 URI、联系方式、私密特征、创建时间和内部状态。直接 JSON.stringify(report) 会带来四类风险:
- 把与比较无关的字段传给外部能力;
- 把手机号、证件号或微信号带入 Prompt;
- 把认领用的私密答案泄露给候选人;
- Prompt 过长,重要冲突被噪声淹没。
数据最小化不是事后加一条正则,而是从数据结构、候选数量、字段长度和交互动作共同限制。
二、先明确小艺在本项目中的职责
小艺只负责:比较脱敏候选的相似点和冲突,帮助用户决定下一步查看哪条记录。
小艺不负责:
- 判断物品最终归属;
- 读取私密核验答案;
- 获取原图或沙箱路径;
- 自动提交认领;
- 替代双方确认交接。
职责越窄,允许字段就越容易形成白名单。
三、输入不是单条记录,而是匹配包
prepareMatchSnapshot(queryReportId) 先调用 reportService.getMatchBundle(),得到查询记录和候选集合。Service 已经完成本机规则匹配,Agent Adapter 不再重新计算分数。
ReportService:决定候选集合与顺序
XiaoYiAgentAdapter:压缩、脱敏、限制数量
XiaoYiFunctionPage:展示、复制、打开小艺
小艺:解释相似点与冲突
这样 AI 适配层不会越权修改核心匹配规则。
四、当前代码最多只取三条候选
早期规划曾写“最多五条”,但当前真实代码是:
export const XIAOYI_INITIAL_QUERY_MAX_LENGTH: number = 240;
const XIAOYI_INITIAL_QUERY_MAX_CANDIDATES: number = 3;
const candidates = bundle.candidates.slice(0, XIAOYI_INITIAL_QUERY_MAX_CANDIDATES);
文章必须跟随当前实现。最多三条能控制长度,也能让用户在小艺回复中清楚对应“候选 1、2、3”。如果未来调整数量,需要同时更新总长度、UI 预览、测试和真机粘贴验证。
五、无候选时拒绝调用
当 candidates.length === 0,适配器直接返回“暂无足够证据交给小艺比较”。这比发送一个只有查询记录的 Prompt 更诚实。
没有候选时,小艺无法比较相似点与冲突。硬拉起只会得到泛化建议,还可能让用户误以为系统已经发现线索。
六、Prompt 首句先限制模型任务
当前摘要第一行是:
比较以下脱敏校园失物候选,列出相似点与冲突,不判断归属。
它同时做三件事:限定领域、限定输出、声明不判断归属。后续每条记录只用稳定短格式表达:
类型/类别/模糊地点/短日期/公开特征
Prompt 设计从业务边界开始,不从“你是一个聪明助手”开始。
七、字段白名单比黑名单更可靠
compactReport() 只保留:
| 字段 | 当前限制 | 用途 |
|---|---|---|
| 类型 | 丢失/拾得 | 判断相反类型 |
| 类别 | 最多 6 字 | 快速识别物品大类 |
| 地点 | 最多 10 字 | 保留模糊区域 |
| 日期 | MM-DD 或最多 5 字 |
时间接近度 |
| 公开特征 | 最多 18 字 | 颜色、外观等对比 |
没有进入白名单的照片 URI、内部 ID、处理记录、私密特征和持久化字段不会被序列化。
八、公开特征也需要再次清洗
用户可能把手机号写进标题或描述,所以“公开字段”不等于“天然安全”。safeText() 会先调用 redactText(),再把单段限制在最多 80 字。
compactText() 还会把换行变为空格、分号统一为逗号,并根据当前字段上限继续截断。多层上限让任何单个字段都无法吞掉全部 Prompt。
九、正则脱敏覆盖什么
当前实现处理三类模式:
value.replace(/1[3-9][0-9]{9}/g, '[已隐藏手机号]')
.replace(/[0-9]{17}[0-9Xx]/g, '[已隐藏证件号]')
.replace(/(微信|QQ|手机|电话|联系方式)[::]?\s*[A-Za-z0-9_-]{4,}/g, '$1[已隐藏]');
它能覆盖常见连续手机号、18 位证件号和带联系方式前缀的账号串。替换发生在压缩前,也会在复制前再做一次。
十、正则不是完整 DLP
以下表达可能逃过当前规则:
- 用空格、短横线或汉字拆开的手机号;
- 邮箱、宿舍门牌、班级学号;
- “一三八……”这类中文数字;
- 图片中的文字;
- 没有“微信/电话”前缀的账号;
- 间接身份组合信息。
所以正则只是最低限度防线。更稳妥的策略仍是字段白名单、禁止原图、限制候选、用户确认和持续对抗测试。
十一、240 字总上限是最后一道保险
所有行合并后,适配器把 queryText 截断到最多 240 字。复制前 prepareClipboardPayload() 会再次脱敏并再次执行 240 字上限。
双重处理有意义:页面参数可能被其他调用路径构造,不能假设进入剪贴板前一定来自同一个安全函数。
同时要注意,简单 substring() 可能在末尾截断一个语义单元。当前真实样例为 193 字,没有触发截断;未来可考虑按候选行预算长度,但那是演进项,不应冒充当前实现。
十二、适配器返回快照,不直接打开平台
XiaoYiAgentSnapshot 只包含:
queryTitle;candidateCount;queryText。
页面先展示快照,让用户知道会分享什么,再进入 Function 页面。数据准备与平台打开分离后,可以独立测试脱敏逻辑,也能在小艺不可用时保留原生候选。
十三、剪贴板必须由用户明确触发
XiaoYiClipboardAdapter.copyPlainText() 只在用户点击复制按钮后执行。它创建纯文本 PasteData,把共享范围设置为 ShareOption.LOCALDEVICE,再调用 setData()。
const pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
const property = pasteData.getProperty();
property.shareOption = pasteboard.ShareOption.LOCALDEVICE;
pasteData.setProperty(property);
await pasteboard.getSystemPasteboard().setData(pasteData);
当前适配器不读取剪贴板,不上传剪贴板,不持久化摘要,也没有新增读取权限。
十四、为什么不用自动复制
自动复制会覆盖用户剪贴板,也会削弱“用户知道数据将被分享”的控制感。当前页面把流程写成两个明确步骤:
- 复制脱敏摘要;
- 打开小艺并粘贴发送。
用户可以在第一步看到摘要,在第二步选择是否继续。即使小艺打开失败,原生候选仍然可用。
十五、错误也要最小化
剪贴板错误只映射为“系统剪贴板正忙”“系统阻止本次复制”或通用“复制失败”,不会把内部异常对象、内容或设备路径展示给用户。
平台错误同样应显示可行动文案,而不是打印包含业务数据的完整日志。开发日志可以记录错误码,但不应记录 240 字摘要正文。
十六、数据流全景

上图展示从匹配包到用户主动复制的六段门禁。它是架构说明图,不代表系统读取了图中列出的所有敏感字段;真实实现通过白名单避免这些字段进入输出。
十七、测试应该同时验证正向与反向
当前测试覆盖的关键断言包括:
- 最多输出三条候选;
- 摘要长度不超过 240;
- 手机号、证件号和微信账号被移除;
- 空字符串不能进入剪贴板;
- 剪贴板适配器只写不读。
还应持续补充绕过样例,例如带空格手机号、邮箱、中文数字和超长混合文本。隐私测试不是一次性通过后永久安全。
十八、不要在文章中泄露平台标识
源码可能包含真实 Agent ID 或 Workflow ID,它们不属于讲解脱敏算法所必需的信息。公开代码示例应统一写成 agent_xxx、workflow_xxx,日志截图也应检查相关字段。
同样不要展示签名密码、Profile、证书路径、账号或设备序列号。技术细节足够复现设计,不等于公开所有配置。
十九、本章证据边界
本章能证明当前适配器按最多三条、字段长度、正则和 240 字上限生成脱敏摘要;剪贴板只在用户操作后写入本机共享范围;相关本地测试和 2026-08-20 显式复制/粘贴真机链路已有记录。
本章不能证明正则覆盖所有敏感信息、剪贴板内容永不被系统中其他合规组件访问、所有机型行为一致,或 AI 输出能够判断最终归属。
二十、小结
AI 数据最小化不是一个 replace(),而是一条可复核链路:先限定任务,再限制候选,再使用字段白名单,然后分段压缩、正则脱敏、总长截断,最后由用户主动复制。
这条链路让小艺只看到完成“比较相似点与冲突”所需的最少文本,同时保留原生核验和最终确认。下一章继续拆解 FunctionComponent 的支持性检查、选项配置与错误码映射。
下一篇:《【寻迹校园 HarmonyOS NEXT 实战 45】FunctionComponent 接入实战:支持性检查、queryText 与错误码映射》。
更多推荐



所有评论(0)